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