home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / t / tel2305s.zip / ENGINE / ARP.C next >
C/C++ Source or Header  |  1992-02-22  |  11KB  |  381 lines

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