home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Commun⁄Network / Telnet 2.5.src.ThinkC / source / NCSA Driver / ip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-14  |  14.2 KB  |  553 lines  |  [TEXT/MPS ]

  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. /*  reset the TTL in the returned packet     /* BYU 2.4.13 */
  164.                                             /* BYU 2.4.13 */
  165.     p->i.ttl = 0x3C;                        /* BYU 2.4.13 */
  166.  
  167. /*
  168. *  prepare ICMP checksum
  169. */
  170.     p->c.check = 0;
  171.     p->c.check = ipcheck(&p->c,ilen>>1);
  172.  
  173. /*
  174. *   iplayer for send
  175. */
  176.     p->i.ident = intswap(nnipident++);
  177.     p->i.check = 0;
  178.     p->i.check = ipcheck(&p->i,10);
  179.  
  180. /*
  181. *  send it
  182. */
  183.     return(dlayersend(p,sizeof(DLAYER)+sizeof(IPLAYER)+ilen,fromSLIP));    /* BYU 2.4.15 */
  184.  
  185. } /* neticmpturn */
  186.  
  187. /****************************************************************************/
  188. /*  icmpinterpret
  189. *   interpret the icmp message that just came in
  190. */
  191. int icmpinterpret
  192.   (
  193.     ICMPKT *p,
  194.     int icmplen,                /* BYU 2.4.15 */
  195.     short fromSLIP                /* BYU 2.4.15 */
  196.   )
  197.     {
  198.     uint i,hisck;
  199.     IPLAYER *iptr;
  200.  
  201.     i = p->c.type;
  202.     netposterr(600 + i);        /* provide info for higher layer user */
  203.  
  204. #ifdef oldway
  205.     hisck = p->c.check;
  206.     p->c.check = 0;
  207. #else
  208. #pragma unused(hisck)
  209. #endif
  210.  
  211.     if (p->c.check) {            /* ignore if chksum = 0 */
  212.         if (ipcheck(&p->c,icmplen>>1)) {
  213.             netposterr(699);
  214.             return(-1);
  215.         }
  216.     }
  217.  
  218.     switch (i) {
  219.         case 8:                            /* ping request sent to me */
  220.             p->c.type = 0;                /* echo reply type */
  221.             neticmpturn(p,icmplen,fromSLIP);    /* BYU 2.4.15 - send back */
  222.             break;
  223.  
  224.         case 5:                            /* ICMP redirect */
  225.             iptr = (IPLAYER *)p->data;
  226.             netputuev(ICMPCLASS,IREDIR,0);        /* event to be picked up */
  227.  
  228.             movebytes(nnicmpsave,iptr->ipdest,4);        /* dest address */
  229.             memmove(nnicmpnew,&p->c.part1,4);            /* BYU LSC = new gateway */
  230.             break;
  231.  
  232.         default:
  233.             break;
  234.     }
  235.  
  236.     return(0);
  237. } /* icmpinterpret */
  238.  
  239. /***************************************************************************/
  240. /*  ipinterpret
  241. *   Called by the reception routine with a new IP packet.  Check the checksum,
  242. *   addressing and protocol type and call appropriate routines.
  243. */
  244.  
  245. int ipinterpret
  246.   (
  247.     IPKT *p,                            /* BYU 2.4.15 */
  248.     short fromSLIP                        /* BYU 2.4.15 */
  249.   )
  250.     {
  251.     int iplen,i;
  252.  
  253. /*
  254. *  We cannot handle fragmented IP packets yet, return an error
  255. */
  256.     if (p->i.frags & 0x20) {
  257.         netposterr(304);
  258.         return(1);
  259.     }
  260.  
  261. /*
  262. *  checksum verification of IP header
  263. */
  264.  
  265.     if (p->i.check) {             /* no IP checksumming if check=0 */
  266.         if (ipcheck(&p->i.versionandhdrlen,(p->i.versionandhdrlen & 0x0f) << 1))  {
  267.             netposterr(300);    /* bad IP checksum */
  268.             return(1);             /* drop packet */
  269.         }
  270.     }
  271.  
  272. /*
  273. *  check to make sure that the packet is for me.
  274. *  Throws out all packets which are not directed to my IP address.
  275. *
  276. *  This code is incomplete.  It does not pass broadcast IP addresses up
  277. *  to higher layers.  It used to report packets which were incorrectly
  278. *  addressed, but no longer does.  Needs proper check for broadcast 
  279. *  addresses.
  280. */
  281.     if (fromSLIP) {                                    /* BYU 2.4.15 */
  282.         if (!comparen(SLIP_ip_number,p->i.ipdest,4))/* BYU 2.4.15 - potential non-match */
  283.             return(1);                                /* BYU 2.4.15 - drop packet */
  284.     } else {                                        /* BYU 2.4.15 */
  285.         if (!comparen(nnipnum,p->i.ipdest,4))        /* BYU 2.4.15 - potential non-match */
  286.             return(1);                                /* BYU 2.4.15 - drop packet */
  287.     }                                                /* BYU 2.4.15 */
  288.  
  289. /*
  290. *  Extract total length of packet
  291. */
  292.     iplen = intswap(p->i.tlen);
  293.  
  294. /*
  295. *  See if there are any IP options to be handled.
  296. *  We don't understand IP options, post a warning to the user and drop
  297. *  the packet.
  298. */
  299.     i = (p->i.versionandhdrlen & 0x0f)<<2;
  300.  
  301.     if (i > 20) {
  302.         netposterr(302);                /* packet with options */
  303.         return(1);
  304.     }
  305.  
  306.     switch (p->i.protocol) {        /* which protocol to handle this packet? */
  307.         case PROTUDP:
  308.             return(udpinterpret((UDPKT *) p,iplen-i));
  309.         case PROTTCP:
  310.             return(tcpinterpret((TCPKT *) p,iplen-i,fromSLIP));        /* BYU 2.4.15 - pass tcplen on to TCP */
  311.         case PROTICMP:
  312.             return(icmpinterpret((ICMPKT *) p,iplen-i,fromSLIP));    /* BYU 2.4.15 */
  313.         default:
  314.             netposterr(303);
  315.             return(1);
  316.     }
  317.  
  318.     return(0);
  319. } /* ipinterpret */
  320.  
  321. #ifdef NNDEBUG
  322. ipdump(p)
  323.     IPKT *p;
  324.     {
  325.     uint16 iplen,iid;
  326.  
  327.     iid = intswap(p->i.ident);
  328.  
  329.     iplen = intswap(p->i.tlen);
  330.  
  331.     puts("found IP packet:");
  332.  
  333.     printf("Version+hdr: %x     service %d      tlen %u   \015",    /* BYU 2.4.18 - changed \n to \015 */
  334.             p->i.versionandhdrlen,p->i.service,iplen);
  335.     printf("Ident: %u    frags: %4x    ttl: %d    prot: %d  \015",    /* BYU 2.4.18 - changed \n to \015 */
  336.             iid,p->i.frags,p->i.ttl,p->i.protocol);
  337.     printf("addresses: s: %d.%d.%d.%d    t: %d.%d.%d.%d \015",        /* BYU 2.4.18 - changed \n to \015 */
  338.         p->i.ipsource[0],p->i.ipsource[1],p->i.ipsource[2],p->i.ipsource[3],
  339.         p->i.ipdest[0],p->i.ipdest[1],p->i.ipdest[2],p->i.ipdest[3]);
  340.  
  341.  
  342.     puts("\015");            /* BYU 2.4.18 - changed \n to \015 */
  343.     
  344. }
  345.  
  346. /***************************************************************************/
  347. /*  ipsend   THIS ROUTINE HAS NOT BEEN TESTED, NEVER USED!
  348. *   generic send of an IP packet according to parameters.  Use of this
  349. *   procedure is discouraged.  Terribly inefficient, but may be useful for
  350. *   tricky or diagnostic situations.  Unused for TCP.
  351. *
  352. *   usage:  ipsend(data,ident,prot,options,hdrlen)
  353. *        data is a pointer to the data to be sent
  354. *       ident is the 16 bit identifier
  355. *       prot is the protocol type, PROTUDP or PROTTCP or other
  356. *       hlen is in bytes, total header length, 20 is minimum
  357. *       dlen is the length of the data field, in bytes
  358. *        who is ip address of recipient
  359. *       options must be included in hlen and hidden in the data stream
  360. */
  361. ipsend(data,dlen,iid,iprot,who,hlen)
  362.     unsigned char *data,iprot,*who;
  363.     int iid,dlen,hlen;
  364.     {
  365.     int iplen;
  366.  
  367.     if (dlen > 512)
  368.         dlen = 512;
  369.  
  370.     iplen = hlen+dlen;                         /* total length of packet */
  371.     blankip.i.tlen = intswap(iplen);            /* byte swap */
  372.  
  373.     blankip.i.versionandhdrlen = 0x40 | (hlen>>2);
  374.  
  375.     blankip.i.ident = intswap(iid);           /* byte swap */
  376.  
  377.     blankip.i.protocol = iprot;
  378.  
  379.     blankip.i.check = 0;                    /* set to 0 before calculating */
  380.  
  381.     movebytes(blankip.i.ipdest,who,4);
  382.     movebytes(blankip.d.me,myaddr,DADDLEN);
  383.  
  384.     movenbytes(blankip.x.data,data,dlen);  /* might be header options data */
  385.  
  386.     blankip.i.check = ipcheck(&blankip.i.versionandhdrlen,hlen>>1);
  387.                                         /* checks based on words */
  388.  
  389.  
  390. /* resolve knowledge of Ethernet hardware addresses */
  391.  
  392. /*
  393. *  This is commented out because I know that this procedure is broken!
  394. *  If you use it, debug it first.
  395.  
  396.     dlayersend(&blankip,iplen+14,0);    /* BYU 2.4.15 */
  397. */
  398.  
  399.     return(0);
  400. } /* ipsend */
  401.  
  402. #endif
  403.  
  404. /****************************************************************************/
  405. /*  neturead
  406. *   get the data from the UDP buffer
  407. *   Returns the number of bytes transferred into your buffer, -1 if none here
  408. *   This needs work.
  409. */
  410. int neturead
  411.   (
  412.     char *buffer
  413.   )
  414.     {
  415.     if (ulist.stale)
  416.         return(-1);
  417.  
  418.     memmove(buffer,ulist.data,ulist.length);    /* BYU LSC */
  419.     ulist.stale = 1;
  420.  
  421.     return(ulist.length);
  422. } /* neturead */
  423.  
  424. /***************************************************************************/
  425. /*  netulisten
  426. *   Specify which UDP port number to listen to.
  427. *   Can only listen to one at a time.
  428. */
  429. void netulisten
  430.   (
  431.     int port
  432.   )
  433.     {
  434.     ulist.listen = port;
  435. }
  436.  
  437. /***************************************************************************/
  438. /*  netusend
  439. *   send some data out in a UDP packet
  440. *   uses the preinitialized data in the port packet ulist.udpout
  441. *   
  442. *   returns 0 on okay send, nonzero on error
  443. */
  444. int netusend
  445.   (
  446.     unsigned char *machine,
  447.     unsigned int port,
  448.     unsigned int retport,
  449.     unsigned char *buffer,
  450.     int n
  451.   )
  452.     {
  453.     unsigned char *pc;
  454.  
  455.     if (n > UMAXLEN)
  456.         n = UMAXLEN;
  457. /*
  458. *  make sure that we have the right dlayer address
  459. */
  460.     if (!comparen(machine,ulist.udpout.i.ipdest,4)) {
  461.         pc = netdlayer(machine);
  462.         if (pc == NULL) 
  463.             return(-2);
  464.         movebytes(ulist.udpout.d.dest,pc,DADDLEN);
  465.         movebytes(ulist.udpout.i.ipdest,machine,4);
  466.         movebytes(ulist.tcps.dest,machine,4);
  467.     }
  468.  
  469.     ulist.udpout.u.dest = intswap(port);
  470.     ulist.udpout.u.source = intswap(retport);
  471.     ulist.tcps.tcplen = ulist.udpout.u.length = intswap(n+sizeof(UDPLAYER));
  472.     movenbytes(ulist.udpout.data,buffer,n);
  473.  
  474. /*
  475. *  put in checksum
  476. */
  477.     ulist.udpout.u.check = 0;
  478.     ulist.udpout.u.check = tcpcheck(&ulist.tcps,&ulist.udpout.u,n+sizeof(UDPLAYER));
  479.  
  480. /*
  481. *   iplayer for send
  482. */
  483.     ulist.udpout.i.tlen = intswap(n+sizeof(IPLAYER)+sizeof(UDPLAYER));
  484.     ulist.udpout.i.ident = intswap(nnipident++);
  485.     ulist.udpout.i.check = 0;
  486.     ulist.udpout.i.check = ipcheck(&ulist.udpout.i,10);
  487. /*
  488. *  send it
  489. */
  490.     return(dlayersend(&ulist.udpout,
  491.         sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(UDPLAYER)+n,0));    /* BYU 2.4.15 */
  492. } /* netusend */
  493.  
  494. #ifdef notneeded
  495. /***************************************************************************/
  496. /*  neticmpsend
  497. *   Not currently used.  Has not been tested since 9/87.
  498. *   Do not assume this works (TK)
  499. *
  500. *   send out an icmp packet, probably to do a ping operation
  501. *   
  502. *   returns 0 on okay send, nonzero on error
  503. */
  504. neticmpsend(machine,type,code,buffer,n)
  505.     unsigned char *machine,*buffer,type,code;
  506.     int n;
  507.     {
  508.     unsigned char *pc;
  509.  
  510.     if (n > ICMPMAX)
  511.         n = ICMPMAX;
  512. /*
  513. *  make sure that we have the right dlayer address
  514. *
  515. *  this may be re-entrant, needs checking.  Okay, as long as this compare
  516. *  is false when called from netsleep() routines!
  517. *  When called from user routines, we are okay.
  518. */
  519.     if (!comparen(machine,blankicmp.i.ipdest,4)) {
  520.         pc = netdlayer(machine);
  521.         if (pc == NULL) 
  522.             return(-2);
  523.         movebytes(blankicmp.d.dest,pc,DADDLEN);
  524.         movebytes(blankicmp.i.ipdest,machine,4);
  525. /*        movebytes(ulist.tcps.dest,machine,4); */
  526.     }
  527. /*
  528. *  prepare ICMP portion
  529. */
  530.     blankicmp.c.type = type;
  531.     blankicmp.c.code = code;
  532.     movenbytes(&blankicmp.data,buffer,n);
  533.  
  534.     blankicmp.c.check = 0;
  535.     blankicmp.c.check = ipcheck(&blankicmp.c,(sizeof(ICMPLAYER)+n)>>1);
  536.  
  537. /*
  538. *   iplayer for send
  539. */
  540.     blankicmp.i.tlen = intswap(n+sizeof(IPLAYER)+sizeof(ICMPLAYER));
  541.     blankicmp.i.ident = intswap(nnipident++);
  542.     blankicmp.i.check = 0;
  543.     blankicmp.i.check = ipcheck(&blankicmp.i,10);
  544. /*
  545. *  send it
  546. */
  547.     return(dlayersend(&blankicmp,
  548.         sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(ICMPLAYER)+n,0));        /* BYU 2.4.15 */
  549.  
  550. }
  551. #endif
  552.