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