home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / telecomm / nhclb120 / ip.c < prev    next >
C/C++ Source or Header  |  1993-09-26  |  10KB  |  412 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.  */
  5. #define    TLB    30 * (1000/MSPTICK)    /* Reassembly limit time */
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "timer.h"
  9. #include "internet.h"
  10. #include "iface.h"
  11. #include "ip.h"
  12. #include "icmp.h"
  13.  
  14. void ip_recv();
  15. static struct mbuf *fraghandle();
  16. static struct reasm  *lookup_reasm();
  17. static struct reasm *creat_reasm();
  18. static void free_reasm();
  19. static void ip_timeout();
  20. static struct frag * newfrag();
  21. static void freefrag();
  22.  
  23.  
  24.  
  25.  
  26.  
  27. char ip_ttl = MAXTTL;    /* Default time-to-live for IP datagrams */
  28.  
  29. struct reasm *reasmq;
  30.  
  31. #define    INSERT    0
  32. #define    APPEND    1
  33. #define    PREPEND    2
  34.  
  35. /* Send an IP datagram. Modeled after the example interface on p 32 of
  36.  * RFC 791
  37.  */
  38. int
  39. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  40. int32 source;            /* source address */
  41. int32 dest;            /* Destination address */
  42. char protocol;            /* Protocol */
  43. char tos;            /* Type of service */
  44. char ttl;            /* Time-to-live */
  45. struct mbuf *bp;        /* Data portion of datagram */
  46. int16 length;            /* Optional length of data portion */
  47. int16 id;            /* Optional identification */
  48. char df;            /* Don't-fragment flag */
  49. {
  50.     struct mbuf *htonip(),*tbp;
  51.     struct ip ip;        /* Pointer to IP header */
  52.     static int16 id_cntr;    /* Datagram serial number */
  53.     int ip_route();        /* Datagram router */
  54.  
  55.     if(length == 0 && bp != NULLBUF)
  56.         length = len_mbuf(bp);
  57.     if(id == 0)
  58.         id = id_cntr++;        
  59.     if(ttl == 0)
  60.         ttl = ip_ttl;
  61.  
  62.     /* Fill in IP header */
  63.     ip.tos = tos;
  64.     ip.length = IPLEN + length;
  65.     ip.id = id;
  66.     if(df)
  67.         ip.fl_offs = DF;
  68.     else
  69.         ip.fl_offs = 0;
  70.     ip.ttl = ttl;
  71.     ip.protocol = protocol;
  72.     ip.source = source;
  73.     ip.dest = dest;
  74.     ip.optlen = 0;
  75.     if((tbp = htonip(&ip,bp,0)) == NULLBUF){
  76.         free_p(bp);
  77.         return -1;
  78.     }
  79.     return ip_route(tbp,0);        /* Toss it to the router */
  80. }
  81.  
  82. /* Reassemble incoming IP fragments and dispatch completed datagrams
  83.  * to the proper transport module
  84.  */
  85. void
  86. ip_recv(ip,bp,rxbroadcast)
  87. struct ip *ip;        /* Extracted IP header */
  88. struct mbuf *bp;    /* Data portion */
  89. char rxbroadcast;    /* True if received on subnet broadcast address */
  90. {
  91.     struct mbuf *fraghandle();
  92.     void (*recv)();    /* Function to call with completed datagram */
  93.     void tcp_input(),udp_input(),icmp_input();
  94.     int length;
  95.  
  96.     /* Initial check for protocols we can't handle */
  97.     switch(uchar(ip->protocol)){
  98.     case TCP_PTCL:
  99.         recv = tcp_input;
  100.         break;
  101.     case UDP_PTCL:
  102.         recv = udp_input;
  103.         break;
  104.     case ICMP_PTCL:
  105.         recv = icmp_input;
  106.         break;
  107.     default:
  108.         /* Send an ICMP Protocol Unknown response... */
  109.         ip_stats.badproto++;
  110.         /* ...unless it's a broadcast */
  111.         if(!rxbroadcast){
  112.             icmp_output(ip,bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
  113.         }
  114.         free_p(bp);
  115.         return;
  116.     }
  117.     /* If we have a complete packet, call the next layer
  118.      * to handle the result. Note that fraghandle passes back
  119.      * a length field that does NOT include the IP header
  120.      */
  121.     if((bp = fraghandle(ip,bp)) != NULLBUF) {
  122.         length = ip->length - (IPLEN + ip->optlen);
  123. /* 
  124.  * the TCP will just append the bytes to the file.  If we don't
  125.  * have the number of bytes we think we do, and the extras
  126.  * happen to be zero, the checksum test won't trigger, and we'll
  127.  * lose.
  128.  */
  129.         if (len_mbuf(bp) != length) {
  130.             free_p(bp);
  131.             return;
  132.         }
  133.         (*recv)(bp,ip->protocol,ip->source,ip->dest,ip->tos,
  134.             length,rxbroadcast);
  135.     }
  136. }
  137. /* Process IP datagram fragments
  138.  * If datagram is complete, return it with ip->length containing the data
  139.  * length (MINUS header); otherwise return NULLBUF
  140.  */
  141. static
  142. struct mbuf *
  143. fraghandle(ip,bp)
  144. struct ip *ip;        /* IP header, host byte order */
  145. struct mbuf *bp;    /* The fragment itself */
  146. {
  147.     void ip_timeout(),freefrag(),free_reasm();
  148.     struct reasm *lookup_reasm(),*creat_reasm();
  149.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  150.     struct frag *lastfrag,*nextfrag,*tfp/* ,*newfrag()*/ ;
  151.     struct mbuf *tbp;
  152.     int16 i;
  153.     int16 offset;        /* Index of first byte in fragment */
  154.     int16 last;        /* Index of first byte beyond fragment */
  155.     char mf;        /* 1 if not last fragment, 0 otherwise */
  156.  
  157.     offset = (ip->fl_offs & F_OFFSET) << 3;    /* Convert to bytes */
  158.     last = offset + ip->length - (IPLEN + ip->optlen);
  159.     mf = (ip->fl_offs & MF) ? 1 : 0;
  160.  
  161.     rp = lookup_reasm(ip);
  162.     if(offset == 0 && !mf){
  163.         /* Complete datagram received. Discard any earlier fragments */
  164.         if(rp != NULLREASM)
  165.             free_reasm(rp);
  166.  
  167.         return bp;
  168.     }
  169.     if(rp == NULLREASM){
  170.         /* First fragment; create new reassembly descriptor */
  171.         if((rp = creat_reasm(ip)) == NULLREASM){
  172.             /* No space for descriptor, drop fragment */
  173.             free_p(bp);
  174.             return NULLBUF;
  175.         }
  176.     }
  177.     /* Keep restarting timer as long as we keep getting fragments */
  178.     stop_timer(&rp->timer);
  179.     start_timer(&rp->timer);
  180.  
  181.     /* If this is the last fragment, we now know how long the
  182.      * entire datagram is; record it
  183.      */
  184.     if(!mf)
  185.         rp->length = last;
  186.  
  187.     /* Set nextfrag to the first fragment which begins after us,
  188.      * and lastfrag to the last fragment which begins before us
  189.      */
  190.     lastfrag = NULLFRAG;
  191.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  192.         if(nextfrag->offset > offset)
  193.             break;
  194.         lastfrag = nextfrag;
  195.     }
  196.     /* Check for overlap with preceeding fragment */
  197.     if(lastfrag != NULLFRAG  && offset < lastfrag->last){
  198.         /* Strip overlap from new fragment */
  199.         i = lastfrag->last - offset;
  200.         pullup(&bp,NULLCHAR,i);
  201.         if(bp == NULLBUF)
  202.             return NULLBUF;    /* Nothing left */
  203.         offset += i;
  204.     }
  205.     /* Look for overlap with succeeding segments */
  206.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  207.         tfp = nextfrag->next;    /* save in case we delete fp */
  208.  
  209.         if(nextfrag->offset >= last)
  210.             break;    /* Past our end */
  211.         /* Trim the front of this entry; if nothing is
  212.          * left, remove it.
  213.          */
  214.         i = last - nextfrag->offset;
  215.         pullup(&nextfrag->buf,NULLCHAR,i);
  216.         if(nextfrag->buf == NULLBUF){
  217.             /* superseded; delete from list */
  218.             if(nextfrag->prev != NULLFRAG)
  219.                 nextfrag->prev->next = nextfrag->next;
  220.             else
  221.                 rp->fraglist = nextfrag->next;
  222.             if(tfp->next != NULLFRAG)
  223.                 nextfrag->next->prev = nextfrag->prev;
  224.             freefrag(nextfrag);
  225.         } else
  226.             nextfrag->offset = last;
  227.     }
  228.     /* Lastfrag now points, as before, to the fragment before us;
  229.      * nextfrag points at the next fragment. Check to see if we can
  230.      * join to either or both fragments.
  231.      */
  232.     i = INSERT;
  233.     if(lastfrag != NULLFRAG && lastfrag->last == offset)
  234.         i |= APPEND;
  235.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  236.         i |= PREPEND;
  237.     switch(i){
  238.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  239.         tfp = newfrag(offset,last,bp);
  240.         tfp->prev = lastfrag;
  241.         tfp->next = nextfrag;
  242.         if(lastfrag != NULLFRAG)
  243.             lastfrag->next = tfp;    /* Middle of list */
  244.         else
  245.             rp->fraglist = tfp;    /* First on list */
  246.         if(nextfrag != NULLFRAG)
  247.             nextfrag->prev = tfp;
  248.         break;
  249.     case APPEND:    /* Append to lastfrag */
  250.         append(&lastfrag->buf,bp);
  251.         lastfrag->last = last;    /* Extend forward */
  252.         break;
  253.     case PREPEND:    /* Prepend to nextfrag */
  254.         tbp = nextfrag->buf;
  255.         nextfrag->buf = bp;
  256.         append(&nextfrag->buf,tbp);
  257.         nextfrag->offset = offset;    /* Extend backward */
  258.         break;
  259.     case (APPEND|PREPEND):
  260.         /* Consolidate by appending this fragment and nextfrag
  261.          * to lastfrag and removing the nextfrag descriptor
  262.          */
  263.         append(&lastfrag->buf,bp);
  264.         append(&lastfrag->buf,nextfrag->buf);
  265.         nextfrag->buf = NULLBUF;
  266.         lastfrag->last = nextfrag->last;
  267.  
  268.         /* Finally unlink and delete the now unneeded nextfrag */
  269.         lastfrag->next = nextfrag->next;
  270.         if(nextfrag->next != NULLFRAG)
  271.             nextfrag->next->prev = lastfrag;
  272.         freefrag(nextfrag);
  273.         break;
  274.     }
  275.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  276.         && rp->length != 0){
  277.         /* We've gotten a complete datagram, so extract it from the
  278.          * reassembly buffer and pass it on.
  279.          */
  280.         bp = rp->fraglist->buf;
  281.         rp->fraglist->buf = NULLBUF;
  282.         /* Tell IP the entire length */
  283.         ip->length = rp->length + (IPLEN + ip->optlen);
  284.         free_reasm(rp);
  285.         return bp;
  286.     } else
  287.         return NULLBUF;
  288. }
  289. static struct reasm *
  290. lookup_reasm(ip)
  291. struct ip *ip;
  292. {
  293.     register struct reasm *rp;
  294.  
  295.     for(rp = reasmq;rp != NULLREASM;rp = rp->next){
  296.         if(ip->source == rp->source && ip->dest == rp->dest
  297.          && ip->protocol == rp->protocol && ip->id == rp->id)
  298.             return rp;
  299.     }
  300.     return NULLREASM;
  301. }
  302. #ifdef    FOO
  303. static
  304. int16
  305. hash_reasm(source,dest,protocol,id)
  306. int32 source;
  307. int32 dest,
  308. char protocol;
  309. int16 id;
  310. {
  311.     register int16 hval;
  312.  
  313.     hval = loword(source);
  314.     hval ^= hiword(source);
  315.     hval ^= loword(dest);
  316.     hval ^= hiword(dest);
  317.     hval ^= uchar(protocol);
  318.     hval ^= id;
  319.     hval %= RHASH;
  320.     return hval;
  321. }
  322. #endif
  323. /* Create a reassembly descriptor,
  324.  * put at head of reassembly list
  325.  */
  326. static struct reasm *
  327. creat_reasm(ip)
  328. register struct ip *ip;
  329. {
  330.     register struct reasm *rp;
  331.     void ip_timeout();
  332.  
  333.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  334.         return rp;    /* No space for descriptor */
  335.     rp->source = ip->source;
  336.     rp->dest = ip->dest;
  337.     rp->id = ip->id;
  338.     rp->protocol = ip->protocol;
  339.     rp->timer.start = TLB;
  340.     rp->timer.func = ip_timeout;
  341.     rp->timer.arg = (char *)rp;
  342.  
  343.     rp->next = reasmq;
  344.     if(rp->next != NULLREASM)
  345.         rp->next->prev = rp;
  346.     reasmq = rp;
  347.     return rp;
  348. }
  349.  
  350. /* Free all resources associated with a reassembly descriptor */
  351. static void
  352. free_reasm(rp)
  353. register struct reasm *rp;
  354. {
  355.     register struct frag *fp;
  356.  
  357.     stop_timer(&rp->timer);
  358.     /* Remove from list of reassembly descriptors */
  359.     if(rp->prev != NULLREASM)
  360.         rp->prev->next = rp->next;
  361.     else
  362.         reasmq = rp->next;
  363.     if(rp->next != NULLREASM)
  364.         rp->next->prev = rp->prev;
  365.     /* Free any fragments on list, starting at beginning */
  366.     while((fp = rp->fraglist) != NULLFRAG){
  367.         rp->fraglist = fp->next;
  368.         free_p(fp->buf);
  369.         free((char *)fp);
  370.     }
  371.     free((char *)rp);
  372. }
  373.  
  374. /* Handle reassembly timeouts by deleting all reassembly resources */
  375. static void
  376. ip_timeout(arg)
  377. int *arg;
  378. {
  379.     register struct reasm *rp;
  380.  
  381.     rp = (struct reasm *)arg;
  382.     free_reasm(rp);
  383. }
  384. /* Create a fragment */
  385. static
  386. struct frag *
  387. newfrag(offset,last,bp)
  388. int16 offset,last;
  389. struct mbuf *bp;
  390. {
  391.     struct frag *fp;
  392.  
  393.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  394.         /* Drop fragment */
  395.         free_p(bp);
  396.         return NULLFRAG;
  397.     }
  398.     fp->buf = bp;
  399.     fp->offset = offset;
  400.     fp->last = last;
  401.     return fp;
  402. }
  403. /* Delete a fragment, return next one on queue */
  404. static
  405. void
  406. freefrag(fp)
  407. struct frag *fp;
  408. {
  409.     free_p(fp->buf);
  410.     free((char *)fp);
  411. }
  412.