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