home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / ncsat.cpt / Telnet2.5 final / tcpip / dlayer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-05  |  10.7 KB  |  422 lines

  1. /*   
  2. *     DLAYER
  3. *     Hardware level routines, data link layer
  4. *
  5. ****************************************************************************
  6. *                                                                          *
  7. *      part of:                                                            *
  8. *      TCP/IP kernel for NCSA Telnet                                       *
  9. *      by Tim Krauskopf                                                    *
  10. *                                                                          *
  11. *      National Center for Supercomputing Applications                     *
  12. *      152 Computing Applications Building                                 *
  13. *      605 E. Springfield Ave.                                             *
  14. *      Champaign, IL  61820                                                *
  15. *                                                                          *
  16. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  17. *                                                                          *
  18. ****************************************************************************
  19. */
  20. #include <stdio.h>
  21. #include <String.h>
  22. #include <Events.h>
  23. #include <AppleTalk.h>
  24.  
  25. #include "protocol.h"
  26. #include "data.h"
  27. #include "mactools.h"
  28. #include "tools.h"
  29. #include "croft.h"
  30.  
  31. extern int EtherNet;        /* BYU 2.4.12 */
  32.  
  33. /************************************************************************/
  34. /*
  35. *   Address Resolution Protocol handling.  This can be looked at as
  36. *   Ethernet-dependent, but the data structure can handle any ARP
  37. *   hardware, with minor changes here.
  38. *
  39. */
  40. replyarp(thardware,tipnum)
  41.     uint8 *thardware,*tipnum;
  42.     {
  43.     uint8 *pc;
  44.  
  45.     movebytes(&arp.tha,thardware,DADDLEN);   /* who this goes to */
  46.  
  47.     movebytes(&arp.tpa,tipnum,4);        /* requester's IP address */
  48.     arp.op = intswap(ARPREP);            /* byte swapped reply opcode */
  49.  
  50.     movebytes(arp.d.dest,thardware,DADDLEN);    /* hardware place to send to */
  51.  
  52.     dlayersend(&arp,sizeof(arp),0);        /* BYU 2.4.15 */
  53.  
  54. /*
  55. *  check for conflicting IP number with your own
  56. */
  57.     if (comparen(tipnum,nnipnum,4))    {     /* we are in trouble */
  58.         pc = neterrstring(-1);
  59.         sprintf(pc,"Conflict with Ethernet hardware address: %2x:%2x:%2x:%2x:%2x:%2x",
  60.         thardware[0],thardware[1],thardware[2],thardware[3],thardware[4],thardware[5]);
  61.         netposterr(-1);
  62.         netposterr(102);
  63.         return(-3);
  64.     }
  65.  
  66. }
  67.  
  68. /*************************************************************************/
  69. /* cacheupdate
  70. *  We just received an ARP, or reply to ARP and need to add the information
  71. *  to the cache.
  72. *
  73. *  Reset arptime so that another machine may be ARPed.  This timer keeps
  74. *  ARPs from going out more than one a second unless we receive a reply.
  75. */
  76. static int32 arptime=0L;
  77.  
  78. int cacheupdate
  79.   (
  80.     uint8 *ipn,
  81.     uint8 *hrdn
  82.   )
  83.     {
  84.     int i,found;
  85.     int32 timer;
  86.  
  87.     found = -1;
  88. /*
  89. * linear search to see if we already have this entry
  90. */
  91.     for (i=0; found < 0 && i < CACHELEN; i++) 
  92.         if (comparen(ipn,&arpc[i].ip,4))
  93.             found = i;
  94.  
  95. /*
  96. *  if that IP number is not already here, take the oldest entry.
  97. *  If it is already here, update the info and reset the timer.
  98. *  These were pre-initialized to 0, so if any are blank, they will be
  99. *  taken first because they are faked to be oldest.
  100. */
  101.     if (found < 0) {
  102.         timer = arpc[0].tm;
  103.         found = 0;
  104.  
  105.         for (i=1; i < CACHELEN; i++) 
  106.             if (arpc[i].tm < timer && !arpc[i].gate) {/* exclude gateways */
  107.                 found = i;
  108.                 timer = arpc[i].tm;
  109.             }
  110.     }
  111. /*
  112. *   do the update to the cache
  113. */
  114.  
  115.     movebytes(&arpc[found].hrd,hrdn,DADDLEN);
  116.     movebytes(&arpc[found].ip,ipn,4);
  117.     arpc[found].tm = time(NULL);
  118.  
  119.     arptime = 0L;                    /* reset, allow more arps */
  120.     return(found);
  121.  
  122. }
  123.  
  124. /************************************************************************/
  125. /*  reqarp
  126. *    put out an ARP request packet, doesn't wait for response
  127. */
  128. int reqarp
  129.   (
  130.     uint8 *tipnum
  131.   )
  132.     {
  133.  
  134. #ifdef MAC
  135.     if (!EtherNet) {                        /* BYU 2.4.12 - was KIP */
  136.         if (0 < KIParp(tipnum, (AddrBlock *) &arp.tha))
  137.             cacheupdate(tipnum, &arp.tha);
  138.         return(0);
  139.     }
  140. #endif MAC
  141.  
  142.     movebytes(&arp.tha,broadaddr,DADDLEN); 
  143.     movebytes(&arp.tpa,tipnum,4);              /* put in IP address we want */
  144.     arp.op = intswap(ARPREQ);                /* request packet */
  145.  
  146.     movebytes(arp.d.dest,broadaddr,DADDLEN);        /* send to everyone */
  147.  
  148.     if (dlayersend(&arp,sizeof(arp),0))        /* BYU 2.4.15 */
  149.         return(1);                          /* error return */
  150.  
  151.     return(0);
  152. }
  153.  
  154. /************************************************************************/
  155. /*  interpret ARP packets
  156. *   Look at incoming ARP packet and make required assessment of usefulness,
  157. *   check to see if we requested this packet, clear all appropriate flags.
  158. */
  159. int arpinterpret
  160.   (
  161.     ARPKT *p
  162.   )
  163.     {
  164.  
  165. /*
  166. *  check packet's desired IP address translation to see if it wants
  167. *  me to answer.
  168. */
  169.     if (p->op == intswap(ARPREQ) && (comparen(&p->tpa,nnipnum,4))) { 
  170.  
  171.         cacheupdate(&p->spa,&p->sha);   /* keep her address for me */
  172.  
  173.         replyarp(&p->sha,&p->spa);        /* proper reply */
  174.         return(0);
  175.     }
  176. /*
  177. *  Check for a RARP reply.  If present, call netsetip()
  178. */
  179.     else if (p->op == intswap(RARPR) && (comparen(&p->tha,nnmyaddr,DADDLEN))) {
  180.         movebytes(nnipnum,&p->tpa,4);
  181.         return(0);
  182.     }
  183.  
  184. /* 
  185. *  Check for a reply that I probably asked for.
  186. */
  187.     if (comparen(&p->tpa,nnipnum,4)) {
  188.         if (p->op == intswap(ARPREP) &&
  189.             p->hrd == intswap(HTYPE) &&       /* consistency checking */
  190.             p->hln == DADDLEN &&
  191.             p->pln == 4 ) {
  192.             cacheupdate(&p->spa,&p->sha);
  193.             return(0);
  194.         }
  195.     }
  196.  
  197.     return(1);
  198.  
  199. }
  200.  
  201. /*************************************************************************/
  202. /* rarp
  203. *  Send a rarp request to look up my IP number
  204. */
  205. rarp()
  206.     {
  207. /*
  208. *  our other fields should already be loaded
  209. */
  210.     movebytes(&arp.tha,nnmyaddr,DADDLEN);   /* address to look up (me) */
  211.     movebytes(&arp.sha,nnmyaddr,DADDLEN);   /* address to look up (me) */
  212.     arp.op = intswap(RARPQ);                /* request packet */
  213.  
  214.     movebytes(arp.d.dest,broadaddr,DADDLEN);        /* send to everyone */
  215.     arp.d.type = ERARP;
  216.  
  217.     if (dlayersend(&arp,sizeof(arp),0))        /* BYU 2.4.15 */
  218.         return(1);                          /* error return */
  219.  
  220.     arp.d.type = EARP;                        /* set back for ARP to use */
  221.     return(0);
  222.  
  223. }
  224.  
  225. /*************************************************************************/
  226. /*  cachelook
  227. *   look up information in the cache
  228. *   returns the cache entry number for the IP number given.
  229. *   Returns -1 on no valid entry, also if the entry present is too old.
  230. *
  231. *   doarp is a flag for non-gateway requests which determines whether an
  232. *   arp will be sent or not.
  233. */
  234.  
  235. int cachelook
  236.   (
  237.     uint8 *ipn,
  238.     int gate,
  239.     int doarp
  240.   )
  241.     {
  242.     int i,haveg;
  243. /*
  244. *  First option, we are not looking for a gateway, but a host on our
  245. *  local network.
  246. */
  247.     if (!gate) {
  248.         for (i=0; i<CACHELEN; i++)
  249.             if (comparen(ipn,&arpc[i].ip,4) && 
  250.                 arpc[i].tm + CACHETO > time(NULL)) 
  251.                 return(i);
  252. /*
  253. *  no valid entry, send an ARP
  254. */
  255.         if (time(NULL) >= arptime && doarp) {    /* check time limit */
  256.             reqarp(ipn);                /* put out a broadcast request */
  257.             arptime = time(NULL)+ARPTO;
  258.         }
  259.         return(-1);
  260.     }
  261.     else {
  262. /*
  263. *  Second option, we need a gateway.
  264. *  if there is a gateway with a current ARP, use it.
  265. *  if not, arp all of the gateways and return an error.  Next call will
  266. *  probably catch the result of the ARP.
  267. */
  268.         haveg = 0;
  269.         for (i=CACHELEN-1; i >= 0; i--)
  270.             if (arpc[i].gate && arpc[i].tm + CACHETO > time(NULL))
  271.                 return(i);
  272.  
  273.         if (time(NULL) >= arptime) {    
  274.             for (i=CACHELEN-1; i >= 0; i--)
  275.                 if (arpc[i].gate) {
  276.                     haveg = 1;
  277.                     reqarp(&arpc[i].ip);    /* put out a broadcast request */
  278.                 }
  279.  
  280.             if (!haveg)             /* blind luck, try ARPing even for */
  281.                 reqarp(ipn);        /* a node not on our net. (proxy ARP)*/
  282.  
  283.             arptime = time(NULL)+ARPTO;
  284.         }
  285.  
  286.         return(-1);
  287.     }
  288.  
  289. }
  290.  
  291. /***************************************************************************/
  292. /*  netdlayer
  293. *       get data layer address for insertion into outgoing packets.
  294. *   searches based on ip number.  If it finds the address, ok, else . . .
  295. *
  296. *   Checks to see if the address is on the same network.  If it is,
  297. *   then ARPs the machine to get address.  Forces pause between sending
  298. *   arps to guarantee not saturating network.
  299. *
  300. *   If not on the same network, it needs the ether address of a 
  301. *   gateway.  Searches the list of machines for a gateway flag.
  302. *   Returns the first gateway found with an Ethernet address. 
  303. *
  304. *   Returns NULL if not here, or pointer to ether address
  305. *   If we don't have it, this also sends an ARP request so that the
  306. *   next time we are called, the ARP reply may be here by then.
  307. *
  308. */
  309. uint8
  310. *netdlayer(tipnum)
  311.     uint8 *tipnum;
  312.     {
  313.     int32 t;
  314.     uint8 *pc;
  315.  
  316.     t = time(NULL) + nndto*TICKSPERSEC;            /* some seconds time out */
  317.     pc = NULL;
  318.     do {
  319.         if (t <= time(NULL))                     /* timed out */
  320.             return(NULL);
  321.         pc = getdlayer(tipnum);
  322.         netsleep(0);                            /* can't have deadlock */
  323.     } while (pc == NULL);
  324.  
  325.     return(pc);
  326. }
  327.  
  328. /***************************************************************************/
  329. /*  netgetrarp
  330. *   Look for a RARP response to arrive
  331. *   wait for nndto seconds before returning failure.
  332. *   If response arrives, return success.
  333. */
  334. int netgetrarp
  335.   (
  336.     void
  337.   )
  338.   {
  339.     int32 t,tr;
  340.  
  341.     t = time(NULL) + nndto*TICKSPERSEC*3;        /* some seconds time out */
  342.     tr = 0L;                                    /* one second retry */
  343.  
  344.     do {
  345.         if (tr <= time(NULL)) {                    /* need retry? */
  346.             rarp();
  347.             tr = time(NULL) + TICKSPERSEC;
  348.         }
  349.  
  350.         if (t <= time(NULL)) {                    /* timed out */
  351.             netposterr(103);
  352.             return(-1);
  353.         }
  354.  
  355.         netsleep(0);                            /* can't have deadlock */
  356.     } while (comparen(nnipnum,"RARP",4));        /* until RARP is served */
  357.  
  358.     return(0);
  359.   }
  360.  
  361. /***************************************************************************/
  362. /*  getdlayer
  363. *   check for the hardware address one time
  364. */
  365. uint8
  366. *getdlayer(tipnum)
  367.     uint8 *tipnum;
  368.     {
  369.     int needgate,i;
  370.  
  371.     needgate = 0;
  372.  
  373. /*
  374. *  Check to see if we need to go through a gateway.
  375. *  If the machine is on our network, then assume that we can send an ARP
  376. *  to that machine, otherwise, send the ARP to the gateway.
  377. *
  378. *  Uses internet standard subnet mask method, RFC950
  379. *  if subnets are not in use, netmask has been pre-set to the appropriate 
  380. *  network addressing mask.
  381. */ 
  382.     for (i=3; i >= 0; i--)
  383.         if ((nnmask[i] & tipnum[i]) != (nnmask[i] & nnipnum[i]))
  384.             needgate = 1;
  385.  
  386.     if (needgate && (0 <= (i = cachelook(tipnum,1,1)))) 
  387.         return(&arpc[i].hrd);
  388.  
  389.     if (!needgate && (0 <= (i = cachelook(tipnum,0,1))))
  390.         return(&arpc[i].hrd);
  391.  
  392.     return(NULL);
  393. }
  394.  
  395. /***************************************************************************/
  396. /*  netsetgate
  397. *   Establish an IP number to use as a gateway.
  398. *   They are added in the order that they arrive and there is a limit on
  399. *   the number of gateways equal to CACHELEN/2.
  400. *   ARPs them as they are added so that the Cache will get pre-filled
  401. *   with gateways.
  402. *
  403. *   returns 0 if ok, -1 on error (full)
  404. */
  405. int netsetgate
  406.   (
  407.     uint8 *ipn
  408.   )
  409.     {
  410.     int i;
  411.  
  412.     for (i=CACHELEN-1 ; i >= CACHELEN/2 ; i--)
  413.         if (!arpc[i].gate) {
  414.             arpc[i].gate = 1;
  415.             movebytes(&arpc[i].ip,ipn,4);
  416.             reqarp(ipn);
  417.             return(0);
  418.         }
  419.  
  420.     return(-1);
  421. }
  422.