home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / hamradio / s920603.zip / IP.C < prev    next >
C/C++ Source or Header  |  1992-05-01  |  14KB  |  551 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  */
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "timer.h"
  9. #include "internet.h"
  10. #include "netuser.h"
  11. #include "iface.h"
  12. #include "pktdrvr.h"
  13. #include "ip.h"
  14. #include "icmp.h"
  15.  
  16. static struct mbuf *fraghandle __ARGS((struct ip *ip,struct mbuf *bp));
  17. static void ip_timeout __ARGS((void *arg));
  18. static void free_reasm __ARGS((struct reasm *rp));
  19. static void freefrag __ARGS((struct frag *fp));
  20. static struct reasm *lookup_reasm __ARGS((struct ip *ip));
  21. static struct reasm *creat_reasm __ARGS((struct ip *ip));
  22. static struct frag *newfrag __ARGS((int16 offset,int16 last,struct mbuf *bp));
  23. static void rdrop __ARGS((struct iface *ifp));
  24.  
  25. struct mib_entry Ip_mib[20] = {
  26.     "",            0,
  27.     "ipForwarding",        1,
  28.     "ipDefaultTTL",        MAXTTL,
  29.     "ipInReceives",        0,
  30.     "ipInHdrErrors",    0,
  31.     "ipInAddrErrors",    0,
  32.     "ipForwDatagrams",    0,
  33.     "ipInUnknownProtos",    0,
  34.     "ipInDiscards",        0,
  35.     "ipInDelivers",        0,
  36.     "ipOutRequests",    0,
  37.     "ipOutDiscards",    0,
  38.     "ipOutNoRoutes",    0,
  39.     "ipReasmTimeout",    TLB,
  40.     "ipReasmReqds",        0,
  41.     "ipReasmOKs",        0,
  42.     "ipReasmFails",        0,
  43.     "ipFragOKs",        0,
  44.     "ipFragFails",        0,
  45.     "ipFragCreates",    0,
  46. };
  47.  
  48. struct reasm *Reasmq;
  49. static struct raw_ip *Raw_ip;
  50.  
  51. #define    INSERT    0
  52. #define    APPEND    1
  53. #define    PREPEND    2
  54.  
  55. /* Send an IP datagram. Modeled after the example interface on p 32 of
  56.  * RFC 791
  57.  */
  58. int
  59. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  60. int32 source;            /* source address */
  61. int32 dest;            /* Destination address */
  62. char protocol;            /* Protocol */
  63. char tos;            /* Type of service */
  64. char ttl;            /* Time-to-live */
  65. struct mbuf *bp;        /* Data portion of datagram */
  66. int16 length;            /* Optional length of data portion */
  67. int16 id;            /* Optional identification */
  68. char df;            /* Don't-fragment flag */
  69. {
  70.     struct mbuf *tbp;
  71.     struct ip ip;            /* IP header */
  72.     static int16 id_cntr = 0;    /* Datagram serial number */
  73.  
  74.     ipOutRequests++;
  75.  
  76.     if(source == INADDR_ANY)
  77.         source = locaddr(dest);
  78.     if(length == 0 && bp != NULLBUF)
  79.         length = len_p(bp);
  80.     if(id == 0)
  81.         id = id_cntr++;        
  82.     if(ttl == 0)
  83.         ttl = ipDefaultTTL;
  84.  
  85.     /* Fill in IP header */
  86.     ip.version = IPVERSION;
  87.     ip.tos = tos;
  88.     ip.length = IPLEN + length;
  89.     ip.id = id;
  90.     ip.offset = 0;
  91.     ip.flags.mf = 0;
  92.     ip.flags.df = df;
  93.     ip.flags.congest = 0;
  94.     ip.ttl = ttl;
  95.     ip.protocol = protocol;
  96.     ip.source = source;
  97.     ip.dest = dest;
  98.     ip.optlen = 0;
  99.     if((tbp = htonip(&ip,bp,IP_CS_NEW)) == NULLBUF){
  100.         free_p(bp);
  101.         return -1;
  102.     }
  103.     if(ismyaddr(ip.dest)){
  104.         /* Pretend it has been sent by the loopback interface before
  105.          * it appears in the receive queue
  106.          */
  107.         net_route(&Loopback,tbp);
  108.         Loopback.ipsndcnt++;
  109.         Loopback.rawsndcnt++;
  110.         Loopback.lastsent = secclock();
  111.     } else
  112.         net_route(NULLIF,tbp);
  113.     return 0;
  114. }
  115.  
  116. /* Reassemble incoming IP fragments and dispatch completed datagrams
  117.  * to the proper transport module
  118.  */
  119. void
  120. ip_recv(iface,ip,bp,rxbroadcast)
  121. struct iface *iface;    /* Incoming interface */
  122. struct ip *ip;        /* Extracted IP header */
  123. struct mbuf *bp;    /* Data portion */
  124. int rxbroadcast;    /* True if received on subnet broadcast address */
  125. {
  126.     /* Function to call with completed datagram */
  127.     register struct raw_ip *rp;
  128.     struct mbuf *bp1,*tbp;
  129.     int rxcnt = 0;
  130.     register struct iplink *ipp;
  131.  
  132.     /* If we have a complete packet, call the next layer
  133.      * to handle the result. Note that fraghandle passes back
  134.      * a length field that does NOT include the IP header
  135.      */
  136.     if((bp = fraghandle(ip,bp)) == NULLBUF)
  137.         return;        /* Not done yet */
  138.  
  139.     ipInDelivers++;
  140.  
  141.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next){
  142.         if(rp->protocol != ip->protocol)
  143.             continue;
  144.         rxcnt++;
  145.         /* Duplicate the data portion, and put the header back on */
  146.         dup_p(&bp1,bp,0,len_p(bp));
  147.         if(bp1 != NULLBUF && (tbp = htonip(ip,bp1,IP_CS_OLD)) != NULLBUF){
  148.             enqueue(&rp->rcvq,tbp);
  149.             if(rp->r_upcall != NULLVFP)
  150.                 (*rp->r_upcall)(rp);
  151.         } else {
  152.             free_p(bp1);
  153.         }
  154.     }
  155.     /* Look it up in the transport protocol table */
  156.     for(ipp = Iplink;ipp->funct != NULL;ipp++){
  157.         if(ipp->proto == ip->protocol)
  158.             break;
  159.     }
  160.     if(ipp->funct != NULL){
  161.         /* Found, call transport protocol */
  162.         (*ipp->funct)(iface,ip,bp,rxbroadcast);
  163.     } else {
  164.         /* Not found */
  165.         if(rxcnt == 0){
  166.             /* Send an ICMP Protocol Unknown response... */
  167.             ipInUnknownProtos++;
  168.             /* ...unless it's a broadcast */
  169.             if(!rxbroadcast){
  170.                 icmp_output(ip,bp,ICMP_DEST_UNREACH,
  171.                  ICMP_PROT_UNREACH,NULLICMP);
  172.             }
  173.         }
  174.         free_p(bp);
  175.     }
  176. }
  177. /* Handle IP packets encapsulated inside IP */
  178. void
  179. ipip_recv(iface,ip,bp,rxbroadcast)
  180. struct iface *iface;    /* Incoming interface */
  181. struct ip *ip;        /* Extracted IP header */
  182. struct mbuf *bp;    /* Data portion */
  183. int rxbroadcast;    /* True if received on subnet broadcast address */
  184. {
  185.     net_route(&Encap,bp);
  186. }
  187.  
  188. /* Process IP datagram fragments
  189.  * If datagram is complete, return it with ip->length containing the data
  190.  * length (MINUS header); otherwise return NULLBUF
  191.  */
  192. static
  193. struct mbuf *
  194. fraghandle(ip,bp)
  195. struct ip *ip;        /* IP header, host byte order */
  196. struct mbuf *bp;    /* The fragment itself */
  197. {
  198.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  199.     struct frag *lastfrag,*nextfrag,*tfp;
  200.     struct mbuf *tbp;
  201.     int16 i;
  202.     int16 last;        /* Index of first byte beyond fragment */
  203.  
  204.     last = ip->offset + ip->length - (IPLEN + ip->optlen);
  205.  
  206.     rp = lookup_reasm(ip);
  207.     if(ip->offset == 0 && !ip->flags.mf){
  208.         /* Complete datagram received. Discard any earlier fragments */
  209.         if(rp != NULLREASM){
  210.             free_reasm(rp);
  211.             ipReasmOKs++;
  212.         }
  213.         return bp;
  214.     }
  215.     ipReasmReqds++;
  216.     if(rp == NULLREASM){
  217.         /* First fragment; create new reassembly descriptor */
  218.         if((rp = creat_reasm(ip)) == NULLREASM){
  219.             /* No space for descriptor, drop fragment */
  220.             ipReasmFails++;
  221.             free_p(bp);
  222.             return NULLBUF;
  223.         }
  224.     }
  225.     /* Keep restarting timer as long as we keep getting fragments */
  226.     stop_timer(&rp->timer);
  227.     start_timer(&rp->timer);
  228.  
  229.     /* If this is the last fragment, we now know how long the
  230.      * entire datagram is; record it
  231.      */
  232.     if(!ip->flags.mf)
  233.         rp->length = last;
  234.  
  235.     /* Set nextfrag to the first fragment which begins after us,
  236.      * and lastfrag to the last fragment which begins before us
  237.      */
  238.     lastfrag = NULLFRAG;
  239.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  240.         if(nextfrag->offset > ip->offset)
  241.             break;
  242.         lastfrag = nextfrag;
  243.     }
  244.     /* Check for overlap with preceeding fragment */
  245.     if(lastfrag != NULLFRAG  && ip->offset < lastfrag->last){
  246.         /* Strip overlap from new fragment */
  247.         i = lastfrag->last - ip->offset;
  248.         pullup(&bp,NULLCHAR,i);
  249.         if(bp == NULLBUF)
  250.             return NULLBUF;    /* Nothing left */
  251.         ip->offset += i;
  252.     }
  253.     /* Look for overlap with succeeding segments */
  254.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  255.         tfp = nextfrag->next;    /* save in case we delete fp */
  256.  
  257.         if(nextfrag->offset >= last)
  258.             break;    /* Past our end */
  259.         /* Trim the front of this entry; if nothing is
  260.          * left, remove it.
  261.          */
  262.         i = last - nextfrag->offset;
  263.         pullup(&nextfrag->buf,NULLCHAR,i);
  264.         if(nextfrag->buf == NULLBUF){
  265.             /* superseded; delete from list */
  266.             if(nextfrag->prev != NULLFRAG)
  267.                 nextfrag->prev->next = nextfrag->next;
  268.             else
  269.                 rp->fraglist = nextfrag->next;
  270.             if(tfp->next != NULLFRAG)
  271.                 nextfrag->next->prev = nextfrag->prev;
  272.             freefrag(nextfrag);
  273.         } else
  274.             nextfrag->offset = last;
  275.     }
  276.     /* Lastfrag now points, as before, to the fragment before us;
  277.      * nextfrag points at the next fragment. Check to see if we can
  278.      * join to either or both fragments.
  279.      */
  280.     i = INSERT;
  281.     if(lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  282.         i |= APPEND;
  283.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  284.         i |= PREPEND;
  285.     switch(i){
  286.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  287.         tfp = newfrag(ip->offset,last,bp);
  288.         tfp->prev = lastfrag;
  289.         tfp->next = nextfrag;
  290.         if(lastfrag != NULLFRAG)
  291.             lastfrag->next = tfp;    /* Middle of list */
  292.         else
  293.             rp->fraglist = tfp;    /* First on list */
  294.         if(nextfrag != NULLFRAG)
  295.             nextfrag->prev = tfp;
  296.         break;
  297.     case APPEND:    /* Append to lastfrag */
  298.         append(&lastfrag->buf,bp);
  299.         lastfrag->last = last;    /* Extend forward */
  300.         break;
  301.     case PREPEND:    /* Prepend to nextfrag */
  302.         tbp = nextfrag->buf;
  303.         nextfrag->buf = bp;
  304.         append(&nextfrag->buf,tbp);
  305.         nextfrag->offset = ip->offset;    /* Extend backward */
  306.         break;
  307.     case (APPEND|PREPEND):
  308.         /* Consolidate by appending this fragment and nextfrag
  309.          * to lastfrag and removing the nextfrag descriptor
  310.          */
  311.         append(&lastfrag->buf,bp);
  312.         append(&lastfrag->buf,nextfrag->buf);
  313.         nextfrag->buf = NULLBUF;
  314.         lastfrag->last = nextfrag->last;
  315.  
  316.         /* Finally unlink and delete the now unneeded nextfrag */
  317.         lastfrag->next = nextfrag->next;
  318.         if(nextfrag->next != NULLFRAG)
  319.             nextfrag->next->prev = lastfrag;
  320.         freefrag(nextfrag);
  321.         break;
  322.     }
  323.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  324.         && rp->length != 0){
  325.         /* We've gotten a complete datagram, so extract it from the
  326.          * reassembly buffer and pass it on.
  327.          */
  328.         bp = rp->fraglist->buf;
  329.         rp->fraglist->buf = NULLBUF;
  330.         /* Tell IP the entire length */
  331.         ip->length = rp->length + (IPLEN + ip->optlen);
  332.         free_reasm(rp);
  333.         ipReasmOKs++;
  334.         return bp;
  335.     } else
  336.         return NULLBUF;
  337. }
  338. /* Arrange for receipt of raw IP datagrams */
  339. struct raw_ip *
  340. raw_ip(protocol,r_upcall)
  341. int protocol;
  342. void (*r_upcall)();
  343. {
  344.     register struct raw_ip *rp;
  345.  
  346.     rp = (struct raw_ip *)callocw(1,sizeof(struct raw_ip));
  347.     rp->protocol = protocol;
  348.     rp->r_upcall = r_upcall;
  349.     rp->next = Raw_ip;
  350.     Raw_ip = rp;
  351.     return rp;
  352. }
  353. /* Free a raw IP descriptor */
  354. void
  355. del_ip(rpp)
  356. struct raw_ip *rpp;
  357. {
  358.     struct raw_ip *rplast = NULLRIP;
  359.     register struct raw_ip *rp;
  360.  
  361.     /* Do sanity check on arg */
  362.     for(rp = Raw_ip;rp != NULLRIP;rplast=rp,rp = rp->next)
  363.         if(rp == rpp)
  364.             break;
  365.     if(rp == NULLRIP)
  366.         return;    /* Doesn't exist */
  367.  
  368.     /* Unlink */
  369.     if(rplast != NULLRIP)
  370.         rplast->next = rp->next;
  371.     else
  372.         Raw_ip = rp->next;
  373.     /* Free resources */
  374.     free_q(&rp->rcvq);
  375.     free((char *)rp);
  376. }
  377.  
  378. static struct reasm *
  379. lookup_reasm(ip)
  380. struct ip *ip;
  381. {
  382.     register struct reasm *rp;
  383.     struct reasm *rplast = NULLREASM;
  384.  
  385.     for(rp = Reasmq;rp != NULLREASM;rplast=rp,rp = rp->next){
  386.         if(ip->id == rp->id && ip->source == rp->source
  387.          && ip->dest == rp->dest && ip->protocol == rp->protocol){
  388.             if(rplast != NULLREASM){
  389.                 /* Move to top of list for speed */
  390.                 rplast->next = rp->next;
  391.                 rp->next = Reasmq;
  392.                 Reasmq = rp;
  393.             }
  394.             return rp;
  395.         }
  396.  
  397.     }
  398.     return NULLREASM;
  399. }
  400. /* Create a reassembly descriptor,
  401.  * put at head of reassembly list
  402.  */
  403. static struct reasm *
  404. creat_reasm(ip)
  405. register struct ip *ip;
  406. {
  407.     register struct reasm *rp;
  408.  
  409.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  410.         return rp;    /* No space for descriptor */
  411.     rp->source = ip->source;
  412.     rp->dest = ip->dest;
  413.     rp->id = ip->id;
  414.     rp->protocol = ip->protocol;
  415.     set_timer(&rp->timer,ipReasmTimeout * 1000L);
  416.     rp->timer.func = ip_timeout;
  417.     rp->timer.arg = rp;
  418.  
  419.     rp->next = Reasmq;
  420.     Reasmq = rp;
  421.     return rp;
  422. }
  423.  
  424. /* Free all resources associated with a reassembly descriptor */
  425. static void
  426. free_reasm(r)
  427. struct reasm *r;
  428. {
  429.     register struct reasm *rp;
  430.     struct reasm *rplast = NULLREASM;
  431.     register struct frag *fp;
  432.  
  433.     for(rp = Reasmq;rp != NULLREASM;rplast = rp,rp=rp->next)
  434.         if(r == rp)
  435.             break;
  436.     if(rp == NULLREASM)
  437.         return;    /* Not on list */
  438.  
  439.     stop_timer(&rp->timer);
  440.     /* Remove from list of reassembly descriptors */
  441.     if(rplast != NULLREASM)
  442.         rplast->next = rp->next;
  443.     else
  444.         Reasmq = rp->next;
  445.  
  446.     /* Free any fragments on list, starting at beginning */
  447.     while((fp = rp->fraglist) != NULLFRAG){
  448.         rp->fraglist = fp->next;
  449.         free_p(fp->buf);
  450.         free((char *)fp);
  451.     }
  452.     free((char *)rp);
  453. }
  454.  
  455. /* Handle reassembly timeouts by deleting all reassembly resources */
  456. static void
  457. ip_timeout(arg)
  458. void *arg;
  459. {
  460.     register struct reasm *rp;
  461.  
  462.     rp = (struct reasm *)arg;
  463.     free_reasm(rp);
  464.     ipReasmFails++;
  465. }
  466. /* Create a fragment */
  467. static struct frag *
  468. newfrag(offset,last,bp)
  469. int16 offset,last;
  470. struct mbuf *bp;
  471. {
  472.     struct frag *fp;
  473.  
  474.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  475.         /* Drop fragment */
  476.         free_p(bp);
  477.         return NULLFRAG;
  478.     }
  479.     fp->buf = bp;
  480.     fp->offset = offset;
  481.     fp->last = last;
  482.     return fp;
  483. }
  484. /* Delete a fragment, return next one on queue */
  485. static void
  486. freefrag(fp)
  487. struct frag *fp;
  488. {
  489.     free_p(fp->buf);
  490.     free((char *)fp);
  491. }
  492.  
  493. /* In red alert mode, blow away the whole reassembly queue. Otherwise crunch
  494.  * each fragment on each reassembly descriptor
  495.  */
  496. void
  497. ip_garbage(red)
  498. int red;
  499. {
  500.     struct reasm *rp,*rp1;
  501.     struct frag *fp;
  502.     struct raw_ip *rwp;
  503.     struct iface *ifp;
  504.  
  505.     /* Run through the reassembly queue */
  506.     for(rp = Reasmq;rp != NULLREASM;rp = rp1){
  507.         rp1 = rp->next;
  508.         if(red){
  509.             free_reasm(rp);
  510.         } else {
  511.             for(fp = rp->fraglist;fp != NULLFRAG;fp = fp->next){
  512.                 mbuf_crunch(&fp->buf);
  513.             }
  514.         }
  515.     }
  516.     /* Run through the raw IP queue */
  517.     for(rwp = Raw_ip;rwp != NULLRIP;rwp = rwp->next)
  518.         mbuf_crunch(&rwp->rcvq);
  519.     /* In red mode, drop one packet on each interface output queue */
  520.     if(!red)
  521.         return;
  522.     for(ifp=Ifaces;ifp != NULLIF;ifp = ifp->next){
  523.         rdrop(ifp);
  524.     }
  525. }
  526. /* Execute random drop algorithm on an interface's output queue */
  527. static void
  528. rdrop(ifp)
  529. struct iface *ifp;
  530. {
  531.     struct mbuf *bp,*bplast;
  532.     int i;
  533.  
  534.     i = len_q(ifp->outq);
  535.     if(i == 0)
  536.         return;    /* Queue is empty */
  537.  
  538.     i = random(i);    /* Select condemned party */
  539.  
  540.     /* Search for i-th message on queue */
  541.     bplast = NULLBUF;
  542.     for(bp = ifp->outq;bp != NULLBUF && i>0;i--,bplast=bp,bp=bp->anext)
  543.         ;
  544.     /* Now remove and free it */
  545.     if(bplast != NULLBUF)
  546.         bplast->anext = bp->anext;
  547.     else
  548.         ifp->outq = bp->anext;    /* First on list */
  549.     free_p(bp);
  550. }
  551.