home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / IP.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  17KB  |  597 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.  
  163.     if((IPLEN + ip->optlen + len_p(bp)) != ip->length) {
  164.         /* then we lost some bytes somewhere :-( VE3DTE */
  165.         free_p(bp);
  166.         return;
  167.     }
  168.  
  169.     /* Look it up in the transport protocol table */
  170.     for(ipp = Iplink;ipp->funct != NULL;ipp++){
  171.         if(ipp->proto == ip->protocol)
  172.             break;
  173.     }
  174.     if(ipp->funct != NULL){
  175.         /* Found, call transport protocol */
  176.         (*ipp->funct)(iface,ip,bp,rxbroadcast);
  177.     } else {
  178.         /* Not found */
  179.         if(rxcnt == 0){
  180.             /* Send an ICMP Protocol Unknown response... */
  181.             ipInUnknownProtos++;
  182.             /* ...unless it's a broadcast */
  183.             if(!rxbroadcast){
  184.                 icmp_output(ip,bp,ICMP_DEST_UNREACH,
  185.                 ICMP_PROT_UNREACH,NULLICMP);
  186.             }
  187.         }
  188.         free_p(bp);
  189.     }
  190. }
  191.   
  192. #ifdef ENCAP
  193. /* Handle IP packets encapsulated inside IP */
  194. void
  195. ipip_recv(iface,ip,bp,rxbroadcast)
  196. struct iface *iface;    /* Incoming interface */
  197. struct ip *ip;      /* Extracted IP header */
  198. struct mbuf *bp;    /* Data portion */
  199. int rxbroadcast;    /* True if received on subnet broadcast address */
  200. {
  201.     struct phdr phdr;
  202.     struct mbuf *tbp;
  203.   
  204.     if((tbp = pushdown(bp,sizeof(phdr))) == NULLBUF){
  205.         free_p(bp);
  206.         return;
  207.     }
  208.     bp = tbp;
  209.     phdr.iface = &Encap;
  210.     phdr.type = CL_NONE;
  211.     memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  212.     enqueue(&Hopper,bp);
  213. }
  214. #endif
  215.   
  216. /* Process IP datagram fragments
  217.  * If datagram is complete, return it with ip->length containing the data
  218.  * length (MINUS header); otherwise return NULLBUF
  219.  */
  220. static
  221. struct mbuf *
  222. fraghandle(ip,bp)
  223. struct ip *ip;      /* IP header, host byte order */
  224. struct mbuf *bp;    /* The fragment itself */
  225. {
  226.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  227.     struct frag *lastfrag,*nextfrag,*tfp;
  228.     struct mbuf *tbp;
  229.     int16 i;
  230.     int16 last;     /* Index of first byte beyond fragment */
  231.   
  232.     last = ip->offset + ip->length - (IPLEN + ip->optlen);
  233.   
  234.     rp = lookup_reasm(ip);
  235.     if(ip->offset == 0 && !ip->flags.mf){
  236.         /* Complete datagram received. Discard any earlier fragments */
  237.         if(rp != NULLREASM){
  238.             free_reasm(rp);
  239.             ipReasmOKs++;
  240.         }
  241.         return bp;
  242.     }
  243.     ipReasmReqds++;
  244.     if(rp == NULLREASM){
  245.         /* First fragment; create new reassembly descriptor */
  246.         if((rp = creat_reasm(ip)) == NULLREASM){
  247.             /* No space for descriptor, drop fragment */
  248.             ipReasmFails++;
  249.             free_p(bp);
  250.             return NULLBUF;
  251.         }
  252.     }
  253.     /* Keep restarting timer as long as we keep getting fragments */
  254.     stop_timer(&rp->timer);
  255.     start_timer(&rp->timer);
  256.   
  257.     /* If this is the last fragment, we now know how long the
  258.      * entire datagram is; record it
  259.      */
  260.     if(!ip->flags.mf)
  261.         rp->length = last;
  262.   
  263.     /* Set nextfrag to the first fragment which begins after us,
  264.      * and lastfrag to the last fragment which begins before us
  265.      */
  266.     lastfrag = NULLFRAG;
  267.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  268.         if(nextfrag->offset > ip->offset)
  269.             break;
  270.         lastfrag = nextfrag;
  271.     }
  272.     /* Check for overlap with preceeding fragment */
  273.     if(lastfrag != NULLFRAG  && ip->offset < lastfrag->last){
  274.         /* Strip overlap from new fragment */
  275.         i = lastfrag->last - ip->offset;
  276.         pullup(&bp,NULLCHAR,i);
  277.         if(bp == NULLBUF)
  278.             return NULLBUF; /* Nothing left */
  279.         ip->offset += i;
  280.     }
  281.     /* Look for overlap with succeeding segments */
  282.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  283.         tfp = nextfrag->next;   /* save in case we delete fp */
  284.   
  285.         if(nextfrag->offset >= last)
  286.             break;  /* Past our end */
  287.         /* Trim the front of this entry; if nothing is
  288.          * left, remove it.
  289.          */
  290.         i = last - nextfrag->offset;
  291.         pullup(&nextfrag->buf,NULLCHAR,i);
  292.         if(nextfrag->buf == NULLBUF){
  293.             /* superseded; delete from list */
  294.             if(nextfrag->prev != NULLFRAG)
  295.                 nextfrag->prev->next = nextfrag->next;
  296.             else
  297.                 rp->fraglist = nextfrag->next;
  298.             if(tfp->next != NULLFRAG)
  299.                 nextfrag->next->prev = nextfrag->prev;
  300.             freefrag(nextfrag);
  301.         } else
  302.             nextfrag->offset = last;
  303.     }
  304.     /* Lastfrag now points, as before, to the fragment before us;
  305.      * nextfrag points at the next fragment. Check to see if we can
  306.      * join to either or both fragments.
  307.      */
  308.     i = INSERT;
  309.     if(lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  310.         i |= APPEND;
  311.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  312.         i |= PREPEND;
  313.     switch(i){
  314.         case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  315.             tfp = newfrag(ip->offset,last,bp);
  316.             tfp->prev = lastfrag;
  317.             tfp->next = nextfrag;
  318.             if(lastfrag != NULLFRAG)
  319.                 lastfrag->next = tfp;   /* Middle of list */
  320.             else
  321.                 rp->fraglist = tfp; /* First on list */
  322.             if(nextfrag != NULLFRAG)
  323.                 nextfrag->prev = tfp;
  324.             break;
  325.         case APPEND:    /* Append to lastfrag */
  326.             append(&lastfrag->buf,bp);
  327.             lastfrag->last = last;  /* Extend forward */
  328.             break;
  329.         case PREPEND:   /* Prepend to nextfrag */
  330.             tbp = nextfrag->buf;
  331.             nextfrag->buf = bp;
  332.             append(&nextfrag->buf,tbp);
  333.             nextfrag->offset = ip->offset;  /* Extend backward */
  334.             break;
  335.         case (APPEND|PREPEND):
  336.         /* Consolidate by appending this fragment and nextfrag
  337.          * to lastfrag and removing the nextfrag descriptor
  338.          */
  339.             append(&lastfrag->buf,bp);
  340.             append(&lastfrag->buf,nextfrag->buf);
  341.             nextfrag->buf = NULLBUF;
  342.             lastfrag->last = nextfrag->last;
  343.   
  344.         /* Finally unlink and delete the now unneeded nextfrag */
  345.             lastfrag->next = nextfrag->next;
  346.             if(nextfrag->next != NULLFRAG)
  347.                 nextfrag->next->prev = lastfrag;
  348.             freefrag(nextfrag);
  349.             break;
  350.     }
  351.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG
  352.     && rp->length != 0){
  353.         /* We've gotten a complete datagram, so extract it from the
  354.          * reassembly buffer and pass it on.
  355.          */
  356.         bp = rp->fraglist->buf;
  357.         rp->fraglist->buf = NULLBUF;
  358.         /* Tell IP the entire length */
  359.         ip->length = rp->length + (IPLEN + ip->optlen);
  360.         free_reasm(rp);
  361.         ipReasmOKs++;
  362.         return bp;
  363.     } else
  364.         return NULLBUF;
  365. }
  366. /* Arrange for receipt of raw IP datagrams */
  367. struct raw_ip *
  368. raw_ip(protocol,r_upcall)
  369. int protocol;
  370. void (*r_upcall)__ARGS((struct raw_ip *));
  371. {
  372.     register struct raw_ip *rp;
  373.   
  374.     rp = (struct raw_ip *)callocw(1,sizeof(struct raw_ip));
  375.     rp->protocol = protocol;
  376.     rp->r_upcall = r_upcall;
  377.     rp->next = Raw_ip;
  378.     Raw_ip = rp;
  379.     return rp;
  380. }
  381. /* Free a raw IP descriptor */
  382. void
  383. del_ip(rpp)
  384. struct raw_ip *rpp;
  385. {
  386.     struct raw_ip *rplast = NULLRIP;
  387.     register struct raw_ip *rp;
  388.   
  389.     /* Do sanity check on arg */
  390.     for(rp = Raw_ip;rp != NULLRIP;rplast=rp,rp = rp->next)
  391.         if(rp == rpp)
  392.             break;
  393.     if(rp == NULLRIP)
  394.         return; /* Doesn't exist */
  395.   
  396.     /* Unlink */
  397.     if(rplast != NULLRIP)
  398.         rplast->next = rp->next;
  399.     else
  400.         Raw_ip = rp->next;
  401.     /* Free resources */
  402.     free_q(&rp->rcvq);
  403.     free((char *)rp);
  404. }
  405.   
  406. static struct reasm *
  407. lookup_reasm(ip)
  408. struct ip *ip;
  409. {
  410.     register struct reasm *rp;
  411.     struct reasm *rplast = NULLREASM;
  412.   
  413.     for(rp = Reasmq;rp != NULLREASM;rplast=rp,rp = rp->next){
  414.         if(ip->id == rp->id && ip->source == rp->source
  415.         && ip->dest == rp->dest && ip->protocol == rp->protocol){
  416.             if(rplast != NULLREASM){
  417.                 /* Move to top of list for speed */
  418.                 rplast->next = rp->next;
  419.                 rp->next = Reasmq;
  420.                 Reasmq = rp;
  421.             }
  422.             return rp;
  423.         }
  424.   
  425.     }
  426.     return NULLREASM;
  427. }
  428. /* Create a reassembly descriptor,
  429.  * put at head of reassembly list
  430.  */
  431. static struct reasm *
  432. creat_reasm(ip)
  433. register struct ip *ip;
  434. {
  435.     register struct reasm *rp;
  436.   
  437.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  438.         return rp;  /* No space for descriptor */
  439.     rp->source = ip->source;
  440.     rp->dest = ip->dest;
  441.     rp->id = ip->id;
  442.     rp->protocol = ip->protocol;
  443.     set_timer(&rp->timer,ipReasmTimeout * 1000L);
  444.     rp->timer.func = ip_timeout;
  445.     rp->timer.arg = rp;
  446.   
  447.     rp->next = Reasmq;
  448.     Reasmq = rp;
  449.     return rp;
  450. }
  451.   
  452. /* Free all resources associated with a reassembly descriptor */
  453. static void
  454. free_reasm(r)
  455. struct reasm *r;
  456. {
  457.     register struct reasm *rp;
  458.     struct reasm *rplast = NULLREASM;
  459.     register struct frag *fp;
  460.   
  461.     for(rp = Reasmq;rp != NULLREASM;rplast = rp,rp=rp->next)
  462.         if(r == rp)
  463.             break;
  464.     if(rp == NULLREASM)
  465.         return; /* Not on list */
  466.   
  467.     stop_timer(&rp->timer);
  468.     /* Remove from list of reassembly descriptors */
  469.     if(rplast != NULLREASM)
  470.         rplast->next = rp->next;
  471.     else
  472.         Reasmq = rp->next;
  473.   
  474.     /* Free any fragments on list, starting at beginning */
  475.     while((fp = rp->fraglist) != NULLFRAG){
  476.         rp->fraglist = fp->next;
  477.         free_p(fp->buf);
  478.         free((char *)fp);
  479.     }
  480.     free((char *)rp);
  481. }
  482.   
  483. /* Handle reassembly timeouts by deleting all reassembly resources */
  484. static void
  485. ip_timeout(arg)
  486. void *arg;
  487. {
  488.     register struct reasm *rp;
  489.   
  490.     rp = (struct reasm *)arg;
  491.     free_reasm(rp);
  492.     ipReasmFails++;
  493. }
  494. /* Create a fragment */
  495. static struct frag *
  496. newfrag(offset,last,bp)
  497. int16 offset,last;
  498. struct mbuf *bp;
  499. {
  500.     struct frag *fp;
  501.   
  502.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  503.         /* Drop fragment */
  504.         free_p(bp);
  505.         return NULLFRAG;
  506.     }
  507.     fp->buf = bp;
  508.     fp->offset = offset;
  509.     fp->last = last;
  510.     return fp;
  511. }
  512. /* Delete a fragment, return next one on queue */
  513. static void
  514. freefrag(fp)
  515. struct frag *fp;
  516. {
  517.     free_p(fp->buf);
  518.     free((char *)fp);
  519. }
  520.   
  521. #ifndef LINUX
  522.   
  523. /* In red alert mode, blow away the whole reassembly queue. Otherwise crunch
  524.  * each fragment on each reassembly descriptor
  525.  */
  526. void
  527. ip_garbage(red)
  528. int red;
  529. {
  530.     struct reasm *rp,*rp1;
  531.     struct frag *fp;
  532.     struct raw_ip *rwp;
  533.   
  534.     /* Run through the reassembly queue */
  535.     for(rp = Reasmq;rp != NULLREASM;rp = rp1){
  536.         rp1 = rp->next;
  537.         if(red){
  538.             free_reasm(rp);
  539.         } else {
  540.             for(fp = rp->fraglist;fp != NULLFRAG;fp = fp->next){
  541.                 mbuf_crunch(&fp->buf);
  542.             }
  543.         }
  544.     }
  545.     /* Run through the raw IP queue */
  546.     for(rwp = Raw_ip;rwp != NULLRIP;rwp = rwp->next)
  547.         mbuf_crunch(&rwp->rcvq);
  548. }
  549.   
  550. #endif /* LINUX */
  551.   
  552. #ifdef notdef
  553.   
  554. /* Execute random quench algorithm on an interface's output queue */
  555. void
  556. rquench(ifp,drop)
  557. struct iface *ifp;
  558. int drop;
  559. {
  560.     struct mbuf *bp,*bplast;
  561.     int i;
  562.     struct qhdr qhdr;
  563.     struct ip ip;
  564.     struct mbuf *bpdup;
  565.   
  566.     if((i = len_q(ifp->outq)) == 0)
  567.         return; /* Queue is empty */
  568.   
  569.     i = random(i);  /* Select a victim */
  570.   
  571.     /* Search for i-th message on queue */
  572.     bplast = NULLBUF;
  573.     for(bp = ifp->outq;bp != NULLBUF && i>0;i--,bplast=bp,bp=bp->anext)
  574.         ;
  575.     if(bp == NULLBUF)
  576.         return; /* "Can't happen" */
  577.   
  578.     /* Send a source quench */
  579.     dup_p(&bpdup,bp,0,len_p(bp));
  580.     pullup(&bpdup,(char *)&qhdr,sizeof(qhdr));
  581.     ntohip(&ip,&bpdup);
  582.     icmp_output(&ip,bpdup,ICMP_QUENCH,0,NULLICMP);
  583.     free_p(bpdup);
  584.     if(!drop)
  585.         return; /* All done */
  586.   
  587.     /* Drop the packet */
  588.     if(bplast != NULLBUF)
  589.         bplast->anext = bp->anext;
  590.     else
  591.         ifp->outq = bp->anext;  /* First on list */
  592.     free_p(bp);
  593. }
  594.   
  595. #endif
  596.   
  597.