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