home *** CD-ROM | disk | FTP | other *** search
/ GRIPS 2: Government Rast…rocessing Software & Data / GRIPS_2.cdr / dos / ncsa_tel / tel_2_2_ / source / ip.c < prev    next >
C/C++ Source or Header  |  1988-07-15  |  12KB  |  497 lines

  1. /*
  2. *   IP.C
  3. *   IP level routines, including ICMP
  4. *   also includes a basic version of UDP, not generalized yet
  5. *
  6. ****************************************************************************
  7. *                                                                          *
  8. *      part of:                                                            *
  9. *      TCP/IP kernel for NCSA Telnet                                       *
  10. *      by Tim Krauskopf                                                    *
  11. *                                                                          *
  12. *      National Center for Supercomputing Applications                     *
  13. *      152 Computing Applications Building                                 *
  14. *      605 E. Springfield Ave.                                             *
  15. *      Champaign, IL  61820                                                *
  16. *                                                                          *
  17. ****************************************************************************
  18. *  Revision history:
  19. *
  20. *  10/87  Initial source release, Tim Krauskopf
  21. *  2/88  typedefs of integer lengths, TK
  22. */
  23.  
  24. #include "stdio.h"
  25. #include "protocol.h"
  26. #include "data.h"
  27.  
  28. uint16 ipcheck(),tcpcheck();
  29.  
  30. /***************************************************************************/
  31. /*  ipinterpret
  32. *   Called by the reception routine with a new IP packet.  Check the checksum,
  33. *   addressing and protocol type and call appropriate routines.
  34. */
  35.  
  36. ipinterpret(p)
  37.     IPKT *p;
  38.     {
  39.     int hischeck,iplen,i;
  40.  
  41. /*
  42. *  We cannot handle fragmented IP packets yet, return an error
  43. */
  44.     if (p->i.frags & 0x20) {
  45.         netposterr(304);
  46.         return(1);
  47.     }
  48.  
  49. /*
  50. *  checksum verification of IP header
  51. */
  52.  
  53.     if (p->i.check) {             /* no IP checksumming if check=0 */
  54.         if (ipcheck(&p->i.versionandhdrlen,(p->i.versionandhdrlen & 0x0f) << 1))  {
  55.             netposterr(300);    /* bad IP checksum */
  56.             return(1);             /* drop packet */
  57.         }
  58.     }
  59.  
  60. /*
  61. *  check to make sure that the packet is for me.
  62. *  Throws out all packets which are not directed to my IP address.
  63. *
  64. *  This code is incomplete.  It does not pass broadcast IP addresses up
  65. *  to higher layers.  It used to report packets which were incorrectly
  66. *  addressed, but no longer does.  Needs proper check for broadcast 
  67. *  addresses.
  68. */
  69.     if (!comparen(nnipnum,p->i.ipdest,4)) {     /* potential non-match */
  70.         return(1);                /* drop packet */
  71.     }
  72.  
  73. /*
  74. *  Extract total length of packet
  75. */
  76.     iplen = intswap(p->i.tlen);
  77.  
  78. /*
  79. *  See if there are any IP options to be handled.
  80. *  We don't understand IP options, post a warning to the user and drop
  81. *  the packet.
  82. */
  83.     i = (p->i.versionandhdrlen & 0x0f)<<2;
  84.  
  85.     if (i > 20) {
  86.         netposterr(302);                /* packet with options */
  87.         return(1);
  88.     }
  89.  
  90.     switch (p->i.protocol) {        /* which protocol to handle this packet? */
  91.         case PROTUDP:
  92.             return(udpinterpret(p,iplen-i));
  93.             break;
  94.         case PROTTCP:
  95.             return(tcpinterpret(p,iplen-i));    /* pass tcplen on to TCP */
  96.         case PROTICMP:
  97.             return(icmpinterpret(p,iplen-i));
  98.         default:
  99.             netposterr(303);
  100.             return(1);
  101.     }
  102.  
  103.     return(0);
  104. }    
  105.  
  106. #ifdef NNDEBUG
  107. ipdump(p)
  108.     IPKT *p;
  109.     {
  110.     uint16 iplen,iid;
  111.  
  112.     iid = intswap(p->i.ident);
  113.  
  114.     iplen = intswap(p->i.tlen);
  115.  
  116.     puts("found IP packet:");
  117.  
  118.     printf("Version+hdr: %x     service %d      tlen %u   \n",
  119.             p->i.versionandhdrlen,p->i.service,iplen);
  120.     printf("Ident: %u    frags: %4x    ttl: %d    prot: %d  \n",
  121.             iid,p->i.frags,p->i.ttl,p->i.protocol);
  122.     printf("addresses: s: %d.%d.%d.%d    t: %d.%d.%d.%d \n",
  123.         p->i.ipsource[0],p->i.ipsource[1],p->i.ipsource[2],p->i.ipsource[3],
  124.         p->i.ipdest[0],p->i.ipdest[1],p->i.ipdest[2],p->i.ipdest[3]);
  125.  
  126.  
  127.     puts("\n");
  128.     
  129. }
  130.  
  131. /***************************************************************************/
  132. /*  ipsend   THIS ROUTINE HAS NOT BEEN TESTED, NEVER USED!
  133. *   generic send of an IP packet according to parameters.  Use of this
  134. *   procedure is discouraged.  Terribly inefficient, but may be useful for
  135. *   tricky or diagnostic situations.  Unused for TCP.
  136. *
  137. *   usage:  ipsend(data,ident,prot,options,hdrlen)
  138. *        data is a pointer to the data to be sent
  139. *       ident is the 16 bit identifier
  140. *       prot is the protocol type, PROTUDP or PROTTCP or other
  141. *       hlen is in bytes, total header length, 20 is minimum
  142. *       dlen is the length of the data field, in bytes
  143. *        who is ip address of recipient
  144. *       options must be included in hlen and hidden in the data stream
  145. */
  146. ipsend(data,dlen,iid,iprot,who,hlen)
  147.     unsigned char *data,iprot,*who;
  148.     int iid,dlen,hlen;
  149.     {
  150.     int iplen;
  151.  
  152.     if (dlen > 512)
  153.         dlen = 512;
  154.  
  155.     iplen = hlen+dlen;                         /* total length of packet */
  156.     blankip.i.tlen = intswap(iplen);            /* byte swap */
  157.  
  158.     blankip.i.versionandhdrlen = 0x40 | (hlen>>2);
  159.  
  160.     blankip.i.ident = intswap(iid);           /* byte swap */
  161.  
  162.     blankip.i.protocol = iprot;
  163.  
  164.     blankip.i.check = 0;                    /* set to 0 before calculating */
  165.  
  166.     movebytes(blankip.i.ipdest,who,4);
  167.     movebytes(blankip.d.me,myaddr,DADDLEN);
  168.  
  169.     movenbytes(blankip.x.data,data,dlen);  /* might be header options data */
  170.  
  171.     blankip.i.check = ipcheck(&blankip.i.versionandhdrlen,hlen>>1);
  172.                                         /* checks based on words */
  173.  
  174.  
  175. /* resolve knowledge of Ethernet hardware addresses */
  176.  
  177. /*
  178. *  This is commented out because I know that this procedure is broken!
  179. *  If you use it, debug it first.
  180.  
  181.     dlayersend(&blankip,iplen+14);
  182. */
  183.  
  184.     return(0);
  185. }
  186.  
  187. #endif
  188.  
  189. /****************************************************************************/
  190. /*  icmpinterpret
  191. *   interpret the icmp message that just came in
  192. */
  193. icmpinterpret(p,icmplen)
  194.     ICMPKT *p;
  195.     int icmplen;
  196.     {
  197.     uint i,cksum,hisck;
  198.     IPLAYER *iptr;
  199.  
  200.     i = p->c.type;
  201.     netposterr(600 + i);        /* provide info for higher layer user */
  202.  
  203.  
  204.     if (p->c.check) {            /* ignore if chksum = 0 */
  205.         if (ipcheck(&p->c,icmplen>>1)) {
  206.             netposterr(699);
  207.             return(-1);
  208.         }
  209.     }
  210.  
  211.     switch (i) {
  212.         case 8:                            /* ping request sent to me */
  213.             p->c.type = 0;                /* echo reply type */
  214.             neticmpturn(p,icmplen);        /* send back */
  215.             break;
  216.  
  217.         case 5:                            /* ICMP redirect */
  218.             iptr = (IPLAYER *)p->data;
  219.             netputuev(ICMPCLASS,IREDIR,0);        /* event to be picked up */
  220.  
  221.             movebytes(nnicmpsave,iptr->ipdest,4);        /* dest address */
  222.             movebytes(nnicmpnew,&p->c.part1,4);            /* new gateway */
  223.             break;
  224.  
  225.         default:
  226.             break;
  227.     }
  228.  
  229.     return(0);
  230. }
  231.  
  232. /****************************************************************************/
  233. /*  udpinterpret
  234. *   take incoming UDP packets and make them available to the user level
  235. *   routines.  Currently keeps the last packet coming in to a port.
  236. *
  237. *   Limitations:
  238. *   Can only listen to one UDP port at a time.  Only saves the last packet
  239. *   received on that port.
  240. *   Port numbers should be assigned like TCP ports are (future).
  241. */
  242. udpinterpret(p,ulen)
  243.     UDPKT *p;
  244.     int ulen;
  245.     {
  246.     uint hischeck,mycheck;
  247. /*
  248. *  did we want this data ?  If not, then let it go, no comment
  249. *  If we want it, copy the relevent information into our structure
  250. */
  251.     if (intswap(p->u.dest) != ulist.listen) 
  252.         return(1);
  253.  
  254. /*
  255. *  first compute the checksum to see if it is a valid packet
  256. */
  257.     hischeck = p->u.check;
  258.     p->u.check = 0;
  259.  
  260.     if (hischeck) {
  261.         movebytes(tcps.source,p->i.ipsource,8);
  262.         tcps.z = 0;
  263.         tcps.proto = p->i.protocol;
  264.  
  265.         tcps.tcplen = intswap(ulen);
  266.  
  267.  
  268.         mycheck = tcpcheck(&tcps,&p->u,ulen);
  269.  
  270.         if (hischeck != mycheck) {
  271.             netposterr(700);
  272.             return(2);
  273.         }
  274.  
  275.         p->u.check = hischeck;                    /* put it back */
  276.     }
  277.  
  278.     ulen -= 8;                        /* account for header */
  279.     if (ulen > UMAXLEN)                /* most data that we can accept */
  280.         ulen = UMAXLEN;
  281.  
  282.     movebytes(ulist.who,p->i.ipsource,4);
  283.     movebytes(ulist.data,p->data,ulen);
  284.     ulist.length = ulen;
  285.     ulist.stale = 0;
  286.     netputuev(USERCLASS,UDPDATA,ulist.listen);        /* post that it is here */
  287.  
  288.     return(0);
  289. }
  290.  
  291. /****************************************************************************/
  292. /*  neturead
  293. *   get the data from the UDP buffer
  294. *   Returns the number of bytes transferred into your buffer, -1 if none here
  295. *   This needs work.
  296. */
  297. neturead(buffer)
  298.     char *buffer;
  299.     {
  300.     if (ulist.stale)
  301.         return(-1);
  302.  
  303.     movebytes(buffer,ulist.data,ulist.length);
  304.     ulist.stale = 1;
  305.  
  306.     return(ulist.length);
  307. }
  308.  
  309. /***************************************************************************/
  310. /*  netulisten
  311. *   Specify which UDP port number to listen to.
  312. *   Can only listen to one at a time.
  313. */
  314. netulisten(port)
  315.     int port;
  316.     {
  317.     ulist.listen = port;
  318. }
  319.  
  320. /***************************************************************************/
  321. /*  netusend
  322. *   send some data out in a UDP packet
  323. *   uses the preinitialized data in the port packet ulist.udpout
  324. *   
  325. *   returns 0 on okay send, nonzero on error
  326. */
  327. netusend(machine,port,retport,buffer,n)
  328.     unsigned char *machine,*buffer;
  329.     unsigned int port,retport;
  330.     int n;
  331.     {
  332.     unsigned char *pc;
  333.  
  334.     if (n > UMAXLEN)
  335.         n = UMAXLEN;
  336. /*
  337. *  make sure that we have the right dlayer address
  338. */
  339.     if (!comparen(machine,ulist.udpout.i.ipdest,4)) {
  340.         pc = netdlayer(machine);
  341.         if (pc == NULL) 
  342.             return(-2);
  343.         movebytes(ulist.udpout.d.dest,pc,DADDLEN);
  344.         movebytes(ulist.udpout.i.ipdest,machine,4);
  345.         movebytes(ulist.tcps.dest,machine,4);
  346.     }
  347.  
  348.     ulist.udpout.u.dest = intswap(port);
  349.     ulist.udpout.u.source = intswap(retport);
  350.     ulist.tcps.tcplen = ulist.udpout.u.length = intswap(n+sizeof(UDPLAYER));
  351.     movenbytes(ulist.udpout.data,buffer,n);
  352.  
  353. /*
  354. *  put in checksum
  355. */
  356.     ulist.udpout.u.check = 0;
  357.     ulist.udpout.u.check = tcpcheck(&ulist.tcps,&ulist.udpout.u,n+sizeof(UDPLAYER));
  358.  
  359. /*
  360. *   iplayer for send
  361. */
  362.     ulist.udpout.i.tlen = intswap(n+sizeof(IPLAYER)+sizeof(UDPLAYER));
  363.     ulist.udpout.i.ident = intswap(nnipident++);
  364.     ulist.udpout.i.check = 0;
  365.     ulist.udpout.i.check = ipcheck(&ulist.udpout.i,10);
  366. /*
  367. *  send it
  368. */
  369.     return(dlayersend(&ulist.udpout,
  370.         sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(UDPLAYER)+n));
  371.  
  372. }
  373.  
  374. #ifdef notneeded
  375. /***************************************************************************/
  376. /*  neticmpsend
  377. *   Not currently used.  Has not been tested since 9/87.
  378. *   Do not assume this works (TK)
  379. *
  380. *   send out an icmp packet, probably to do a ping operation
  381. *   
  382. *   returns 0 on okay send, nonzero on error
  383. */
  384. neticmpsend(machine,type,code,buffer,n)
  385.     unsigned char *machine,*buffer,type,code;
  386.     int n;
  387.     {
  388.     unsigned char *pc;
  389.  
  390.     if (n > ICMPMAX)
  391.         n = ICMPMAX;
  392. /*
  393. *  make sure that we have the right dlayer address
  394. *
  395. *  this may be re-entrant, needs checking.  Okay, as long as this compare
  396. *  is false when called from netsleep() routines!
  397. *  When called from user routines, we are okay.
  398. */
  399.     if (!comparen(machine,blankicmp.i.ipdest,4)) {
  400.         pc = netdlayer(machine);
  401.         if (pc == NULL) 
  402.             return(-2);
  403.         movebytes(blankicmp.d.dest,pc,DADDLEN);
  404.         movebytes(blankicmp.i.ipdest,machine,4);
  405. /*        movebytes(ulist.tcps.dest,machine,4); */
  406.     }
  407. /*
  408. *  prepare ICMP portion
  409. */
  410.     blankicmp.c.type = type;
  411.     blankicmp.c.code = code;
  412.     movenbytes(&blankicmp.data,buffer,n);
  413.  
  414.     blankicmp.c.check = 0;
  415.     blankicmp.c.check = ipcheck(&blankicmp.c,(sizeof(ICMPLAYER)+n)>>1);
  416.  
  417. /*
  418. *   iplayer for send
  419. */
  420.     blankicmp.i.tlen = intswap(n+sizeof(IPLAYER)+sizeof(ICMPLAYER));
  421.     blankicmp.i.ident = intswap(nnipident++);
  422.     blankicmp.i.check = 0;
  423.     blankicmp.i.check = ipcheck(&blankicmp.i,10);
  424. /*
  425. *  send it
  426. *
  427. *  debug this routine before using
  428. */
  429.     return(dlayersend(&blankicmp,
  430.         sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(ICMPLAYER)+n));
  431.  
  432. }
  433. #endif
  434.  
  435. /***************************************************************************/
  436. /*  neticmpturn
  437. *
  438. *   send out an icmp packet, probably in response to a ping operation
  439. *   interchanges the source and destination addresses of the packet,
  440. *   puts in my addresses for the source and sends it
  441. *
  442. *   does not change any of the ICMP fields, just the IP and dlayers
  443. *   returns 0 on okay send, nonzero on error
  444. */
  445.  
  446. neticmpturn(p,ilen)
  447.     ICMPKT *p;
  448.     int ilen;
  449.     {
  450.     unsigned char *pc;
  451. /*
  452. *  reverse the addresses, dlayer and IP layer
  453. */
  454.     if (comparen(p->d.me,broadaddr,DADDLEN))
  455.         return(0);
  456.  
  457.     movebytes(p->d.dest,p->d.me,DADDLEN);
  458.  
  459. #ifdef MAC
  460. /*
  461. *   look up address in the arp cache if we are using AppleTalk
  462. *   encapsulation.
  463. */
  464.     if (!nnemac) {
  465.         pc = getdlayer(p->i.ipsource);
  466.         if (pc != NULL)
  467.             movebytes(p->d.dest,pc,DADDLEN);
  468.         else
  469.             return(0);        /* no hope this time */
  470.     }
  471. #endif
  472.  
  473.  
  474.     movebytes(p->i.ipdest,p->i.ipsource,4);
  475.     movebytes(p->d.me,nnmyaddr,DADDLEN);
  476.     movebytes(p->i.ipsource,nnipnum,4);
  477. /*
  478. *  prepare ICMP checksum
  479. */
  480.     p->c.check = 0;
  481.     p->c.check = ipcheck(&p->c,ilen>>1);
  482.  
  483. /*
  484. *   iplayer for send
  485. */
  486.     p->i.ident = intswap(nnipident++);
  487.     p->i.check = 0;
  488.     p->i.check = ipcheck(&p->i,10);
  489.  
  490. /*
  491. *  send it
  492. */
  493.     return(dlayersend(p,sizeof(DLAYER)+sizeof(IPLAYER)+ilen));
  494.  
  495. }
  496.