home *** CD-ROM | disk | FTP | other *** search
/ GRIPS 2: Government Rast…rocessing Software & Data / GRIPS_2.cdr / dos / ncsa_tel / contribu / byu_tel2.hqx / tcpip / ip.c < prev    next >
Text File  |  1989-06-22  |  13KB  |  500 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. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  18. *                                                                          *
  19. ****************************************************************************
  20. *  Revision history:
  21. *
  22. *  10/87  Initial source release, Tim Krauskopf
  23. *  2/88  typedefs of integer lengths, TK
  24. */
  25.  
  26. #include "stdio.h"
  27. #include "protocol.h"
  28. #include "data.h"
  29.  
  30. uint16 ipcheck(),tcpcheck();
  31.  
  32. /***************************************************************************/
  33. /*  ipinterpret
  34. *   Called by the reception routine with a new IP packet.  Check the checksum,
  35. *   addressing and protocol type and call appropriate routines.
  36. */
  37.  
  38. ipinterpret(p)
  39.     IPKT *p;
  40.     {
  41.     int hischeck,iplen,i;
  42.  
  43. /*
  44. *  We cannot handle fragmented IP packets yet, return an error
  45. */
  46.     if (p->i.frags & 0x20) {
  47.         netposterr(304);
  48.         return(1);
  49.     }
  50.  
  51. /*
  52. *  checksum verification of IP header
  53. */
  54.  
  55.     if (p->i.check) {             /* no IP checksumming if check=0 */
  56.         if (ipcheck(&p->i.versionandhdrlen,(p->i.versionandhdrlen & 0x0f) << 1))  {
  57.             netposterr(300);    /* bad IP checksum */
  58.             return(1);             /* drop packet */
  59.         }
  60.     }
  61.  
  62. /*
  63. *  check to make sure that the packet is for me.
  64. *  Throws out all packets which are not directed to my IP address.
  65. *
  66. *  This code is incomplete.  It does not pass broadcast IP addresses up
  67. *  to higher layers.  It used to report packets which were incorrectly
  68. *  addressed, but no longer does.  Needs proper check for broadcast 
  69. *  addresses.
  70. */
  71.     if (!comparen(nnipnum,p->i.ipdest,4)) {     /* potential non-match */
  72.         return(1);                /* drop packet */
  73.     }
  74. /*
  75. *  Extract total length of packet
  76. */
  77.     iplen = intswap(p->i.tlen);
  78.  
  79. /*
  80. *  See if there are any IP options to be handled.
  81. *  We don't understand IP options, post a warning to the user and drop
  82. *  the packet.
  83. */
  84.     i = (p->i.versionandhdrlen & 0x0f)<<2;
  85.  
  86.     if (i > 20) {
  87.         netposterr(302);                /* packet with options */
  88.         return(1);
  89.     }
  90.  
  91.     switch (p->i.protocol) {        /* which protocol to handle this packet? */
  92.         case PROTUDP:
  93.             return(udpinterpret(p,iplen-i));
  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. #ifdef oldway
  204.     hisck = p->c.check;
  205.     p->c.check = 0;
  206. #endif
  207.  
  208.     if (p->c.check) {            /* ignore if chksum = 0 */
  209.         if (ipcheck(&p->c,icmplen>>1)) {
  210.             netposterr(699);
  211.             return(-1);
  212.         }
  213.     }
  214.  
  215.     switch (i) {
  216.         case 8:                            /* ping request sent to me */
  217.             p->c.type = 0;                /* echo reply type */
  218.             neticmpturn(p,icmplen);        /* send back */
  219.             break;
  220.  
  221.         case 5:                            /* ICMP redirect */
  222.             iptr = (IPLAYER *)p->data;
  223.             netputuev(ICMPCLASS,IREDIR,0);        /* event to be picked up */
  224.  
  225.             movebytes(nnicmpsave,iptr->ipdest,4);        /* dest address */
  226.             movebytes(nnicmpnew,&p->c.part1,4);            /* new gateway */
  227.             break;
  228.  
  229.         default:
  230.             break;
  231.     }
  232.  
  233.     return(0);
  234. }
  235.  
  236. /****************************************************************************/
  237. /*  udpinterpret
  238. *   take incoming UDP packets and make them available to the user level
  239. *   routines.  Currently keeps the last packet coming in to a port.
  240. *
  241. *   Limitations:
  242. *   Can only listen to one UDP port at a time.  Only saves the last packet
  243. *   received on that port.
  244. *   Port numbers should be assigned like TCP ports are (future).
  245. */
  246. udpinterpret(p,ulen)
  247.     UDPKT *p;
  248.     int ulen;
  249.     {
  250.     uint hischeck,mycheck;
  251. /*
  252. *  did we want this data ?  If not, then let it go, no comment
  253. *  If we want it, copy the relevent information into our structure
  254. */
  255.     if (intswap(p->u.dest) != ulist.listen) 
  256.         return(1);
  257.  
  258. /*
  259. *  first compute the checksum to see if it is a valid packet
  260. */
  261.     hischeck = p->u.check;
  262.     p->u.check = 0;
  263.  
  264.     if (hischeck) {
  265.         movebytes(tcps.source,p->i.ipsource,8);
  266.         tcps.z = 0;
  267.         tcps.proto = p->i.protocol;
  268.  
  269.         tcps.tcplen = intswap(ulen);
  270.  
  271.  
  272.         mycheck = tcpcheck(&tcps,&p->u,ulen);
  273.  
  274.         if (hischeck != mycheck) {
  275.             netposterr(700);
  276.             return(2);
  277.         }
  278.  
  279.         p->u.check = hischeck;                    /* put it back */
  280.     }
  281.  
  282.     ulen -= 8;                        /* account for header */
  283.     if (ulen > UMAXLEN)                /* most data that we can accept */
  284.         ulen = UMAXLEN;
  285.  
  286.     movebytes(ulist.who,p->i.ipsource,4);
  287.     movebytes(ulist.data,p->data,ulen);
  288.     ulist.length = ulen;
  289.     ulist.stale = 0;
  290.     netputuev(USERCLASS,UDPDATA,ulist.listen);        /* post that it is here */
  291.  
  292.     return(0);
  293. }
  294.  
  295.  
  296. /****************************************************************************/
  297. /*  neturead
  298. *   get the data from the UDP buffer
  299. *   Returns the number of bytes transferred into your buffer, -1 if none here
  300. *   This needs work.
  301. */
  302. neturead(buffer)
  303.     char *buffer;
  304.     {
  305.     if (ulist.stale)
  306.         return(-1);
  307.  
  308.     movebytes(buffer,ulist.data,ulist.length);
  309.     ulist.stale = 1;
  310.  
  311.     return(ulist.length);
  312. }
  313.  
  314. /***************************************************************************/
  315. /*  netulisten
  316. *   Specify which UDP port number to listen to.
  317. *   Can only listen to one at a time.
  318. */
  319. netulisten(port)
  320.     int port;
  321.     {
  322.     ulist.listen = port;
  323. }
  324.  
  325. /***************************************************************************/
  326. /*  netusend
  327. *   send some data out in a UDP packet
  328. *   uses the preinitialized data in the port packet ulist.udpout
  329. *   
  330. *   returns 0 on okay send, nonzero on error
  331. */
  332. netusend(machine,port,retport,buffer,n)
  333.     unsigned char *machine,*buffer;
  334.     unsigned int port,retport;
  335.     int n;
  336.     {
  337.     unsigned char *pc;
  338.  
  339.     if (n > UMAXLEN)
  340.         n = UMAXLEN;
  341. /*
  342. *  make sure that we have the right dlayer address
  343. */
  344.     if (!comparen(machine,ulist.udpout.i.ipdest,4)) {
  345.         pc = netdlayer(machine);
  346.         if (pc == NULL) 
  347.             return(-2);
  348.         movebytes(ulist.udpout.d.dest,pc,DADDLEN);
  349.         movebytes(ulist.udpout.i.ipdest,machine,4);
  350.         movebytes(ulist.tcps.dest,machine,4);
  351.     }
  352.  
  353.     ulist.udpout.u.dest = intswap(port);
  354.     ulist.udpout.u.source = intswap(retport);
  355.     ulist.tcps.tcplen = ulist.udpout.u.length = intswap(n+sizeof(UDPLAYER));
  356.     movenbytes(ulist.udpout.data,buffer,n);
  357.  
  358. /*
  359. *  put in checksum
  360. */
  361.     ulist.udpout.u.check = 0;
  362.     ulist.udpout.u.check = tcpcheck(&ulist.tcps,&ulist.udpout.u,n+sizeof(UDPLAYER));
  363.  
  364. /*
  365. *   iplayer for send
  366. */
  367.     ulist.udpout.i.tlen = intswap(n+sizeof(IPLAYER)+sizeof(UDPLAYER));
  368.     ulist.udpout.i.ident = intswap(nnipident++);
  369.     ulist.udpout.i.check = 0;
  370.     ulist.udpout.i.check = ipcheck(&ulist.udpout.i,10);
  371. /*
  372. *  send it
  373. */
  374.     return(dlayersend(&ulist.udpout,
  375.         sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(UDPLAYER)+n));
  376.  
  377. }
  378.  
  379. #ifdef notneeded
  380. /***************************************************************************/
  381. /*  neticmpsend
  382. *   Not currently used.  Has not been tested since 9/87.
  383. *   Do not assume this works (TK)
  384. *
  385. *   send out an icmp packet, probably to do a ping operation
  386. *   
  387. *   returns 0 on okay send, nonzero on error
  388. */
  389. neticmpsend(machine,type,code,buffer,n)
  390.     unsigned char *machine,*buffer,type,code;
  391.     int n;
  392.     {
  393.     unsigned char *pc;
  394.  
  395.     if (n > ICMPMAX)
  396.         n = ICMPMAX;
  397. /*
  398. *  make sure that we have the right dlayer address
  399. *
  400. *  this may be re-entrant, needs checking.  Okay, as long as this compare
  401. *  is false when called from netsleep() routines!
  402. *  When called from user routines, we are okay.
  403. */
  404.     if (!comparen(machine,blankicmp.i.ipdest,4)) {
  405.         pc = netdlayer(machine);
  406.         if (pc == NULL) 
  407.             return(-2);
  408.         movebytes(blankicmp.d.dest,pc,DADDLEN);
  409.         movebytes(blankicmp.i.ipdest,machine,4);
  410. /*        movebytes(ulist.tcps.dest,machine,4); */
  411.     }
  412. /*
  413. *  prepare ICMP portion
  414. */
  415.     blankicmp.c.type = type;
  416.     blankicmp.c.code = code;
  417.     movenbytes(&blankicmp.data,buffer,n);
  418.  
  419.     blankicmp.c.check = 0;
  420.     blankicmp.c.check = ipcheck(&blankicmp.c,(sizeof(ICMPLAYER)+n)>>1);
  421.  
  422. /*
  423. *   iplayer for send
  424. */
  425.     blankicmp.i.tlen = intswap(n+sizeof(IPLAYER)+sizeof(ICMPLAYER));
  426.     blankicmp.i.ident = intswap(nnipident++);
  427.     blankicmp.i.check = 0;
  428.     blankicmp.i.check = ipcheck(&blankicmp.i,10);
  429. /*
  430. *  send it
  431. */
  432.     return(dlayersend(&blankicmp,
  433.         sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(ICMPLAYER)+n));
  434.  
  435. }
  436. #endif
  437.  
  438. /***************************************************************************/
  439. /*  neticmpturn
  440. *
  441. *   send out an icmp packet, probably in response to a ping operation
  442. *   interchanges the source and destination addresses of the packet,
  443. *   puts in my addresses for the source and sends it
  444. *
  445. *   does not change any of the ICMP fields, just the IP and dlayers
  446. *   returns 0 on okay send, nonzero on error
  447. */
  448.  
  449. neticmpturn(p,ilen)
  450.     ICMPKT *p;
  451.     int ilen;
  452.     {
  453.     unsigned char *pc;
  454. /*
  455. *  reverse the addresses, dlayer and IP layer
  456. */
  457.     if (comparen(p->d.me,broadaddr,DADDLEN))
  458.         return(0);
  459.  
  460.     movebytes(p->d.dest,p->d.me,DADDLEN);
  461.  
  462. #ifdef MAC
  463. /*
  464. *   look up address in the arp cache if we are using AppleTalk
  465. *   encapsulation.
  466. */
  467.     if (!nnemac) {
  468.         pc = getdlayer(p->i.ipsource);
  469.         if (pc != NULL)
  470.             movebytes(p->d.dest,pc,DADDLEN);
  471.         else
  472.             return(0);        /* no hope this time */
  473.     }
  474. #endif
  475.  
  476.  
  477.     movebytes(p->i.ipdest,p->i.ipsource,4);
  478.     movebytes(p->d.me,nnmyaddr,DADDLEN);
  479.     movebytes(p->i.ipsource,nnipnum,4);
  480. /*
  481. *  prepare ICMP checksum
  482. */
  483.     p->c.check = 0;
  484.     p->c.check = ipcheck(&p->c,ilen>>1);
  485.  
  486. /*
  487. *   iplayer for send
  488. */
  489.     p->i.ident = intswap(nnipident++);
  490.     p->i.check = 0;
  491.     p->i.check = ipcheck(&p->i,10);
  492.  
  493. /*
  494. *  send it
  495. */
  496.     return(dlayersend(p,sizeof(DLAYER)+sizeof(IPLAYER)+ilen));
  497.  
  498. }
  499.