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