/* arp.c */ /* * Includes */ #include #include "vtcpip.h" #include "dfault.h" #include "evtdef.h" #include "hstdef.h" #include "prodef.h" #include "prodat.h" #include "tcpdat.h" #include "bytprc.h" #include "cticks.h" #include "suspnd.h" /* * replyarp * * Address Resolution Protocol handling. This can be looked at as * Ethernet-dependent, but the data structure can handle any ARP * hardware, with minor changes here. * */ int replyarp(thardware,tipnum) register char *thardware,*tipnum; { register char *pc; /* * who this goes to */ movebytes(arp.tha,thardware,DADDLEN); /* * requester's IP address */ movebytes(arp.tpa,tipnum,4); /* * byte swapped reply opcode */ arp.op = intswap(ARPREP); /* * hardware place to send to */ movebytes(arp.d.dest,thardware,DADDLEN); #ifdef DEBUGOPTION if(debug&0x24) { dmpfil("arprep",(DLAYER *)&arp,sizeof(arp)); } #endif dlsend((DLAYER *)&arp,sizeof(arp)); /* * check for conflicting IP number with your own */ if(comparen(tipnum,nnipnum,4)) { pc = nterrstring(-1); sprintf(pc, "Conflict with Ethernet hardware address: %2x:%2x:%2x:%2x:%2x:%2x", thardware[0],thardware[1], thardware[2],thardware[3], thardware[4],thardware[5]); ntposterr(-1); ntposterr(102); return(-3); } return(0); } /* * reqarp * * put out an ARP request packet, doesn't wait for response */ int reqarp(tipnum) register char *tipnum; { movebytes(arp.tha,broadaddr,DADDLEN); /* * put in IP address we want */ movebytes(arp.tpa,tipnum,4); /* * request packet */ arp.op = intswap(ARPREQ); /* * send to everyone */ movebytes(arp.d.dest,broadaddr,DADDLEN); #ifdef DEBUGOPTION if(debug&0x24) { dmpfil("arpout",(DLAYER *)&arp,sizeof(arp)); } #endif if(dlsend((DLAYER *)&arp,sizeof(arp))) return(1); return(0); } /* * arpinterpret * * interpret ARP packets * Look at incoming ARP packet and make required assessment of usefulness, * check to see if we requested this packet, clear all appropriate flags. */ int arpinterpret(pkt) register ARPKT *pkt; { /* * check packet's desired IP address translation * to see if it wants me to answer. */ if(pkt->op==intswap(ARPREQ) && (comparen(pkt->tpa,nnipnum,4))) { #ifdef DEBUGOPTION if(debug&0x24) { dmpfil("arpreq",(ARPKT *)pkt,sizeof(ARPKT)); } #endif /* * keep her address for me */ cacheupdate(pkt->spa,pkt->sha); /* * proper reply */ replyarp(pkt->sha,pkt->spa); return(0); } /* * Check for a RARP reply. */ if(pkt->op==intswap(RARPR) && comparen(pkt->tha,nnmyaddr,DADDLEN)) { movebytes(nnipnum,pkt->tpa,4); #ifdef DEBUGOPTION if(debug&0x24) { dmpfil("rarpr",(ARPKT *)pkt,sizeof(ARPKT)); } #endif return(0); } /* * Check for a reply that I probably asked for. */ if(comparen(pkt->tpa,nnipnum,4) && pkt->op==intswap(ARPREP) && pkt->hrd==intswap(HTYPE) && pkt->hln==DADDLEN && pkt->pln==4) { cacheupdate(pkt->spa,pkt->sha); #ifdef DEBUGOPTION if(debug&0x24) { dmpfil("arprep",(ARPKT *)pkt,sizeof(ARPKT)); } #endif return(0); } #ifdef DEBUGOPTION if(debug&0x04) { dmpfil("arpinp",(ARPKT *)pkt,sizeof(ARPKT)); } #endif return(1); } /* * rarp * * Send a rarp request to look up my IP number */ int rarp() { /* * our other fields should already be loaded * address to look up (me) */ movebytes(arp.tha,nnmyaddr,DADDLEN); movebytes(arp.sha,nnmyaddr,DADDLEN); /* * request packet */ arp.op = intswap(RARPQ); /* * send to everyone */ movebytes(arp.d.dest,broadaddr,DADDLEN); #ifdef DEBUGOPTION if(debug&0x24) { dmpfil("rarpq",(DLAYER *)&arp,sizeof(arp)); } #endif arp.d.type = ERARP; if(dlsend((DLAYER *)&arp,sizeof(arp))) return(1); arp.d.type = EARP; return(0); } /* * cacheupdate * * We just received an ARP, or reply to ARP * and need to add the information to the cache. * * Reset arptime so that another machine may be ARPed. This timer keeps * ARPs from going out more than one a second unless we receive a reply. */ static long arptime = 0L; int cacheupdate(ipn,hrdn) register char *ipn,*hrdn; { int i,found; long timer; found = -1; /* * linear search to see if we already have this entry */ for(i=0; found<0 && i nnarpto*TICKSPERSEC && doarp) { /* * put out a broadcast request */ reqarp(ipn); arptime = cticks(NULL); } return(-1); } else { /* * Second option, we need a gateway. * if there is a gateway with a current ARP, use it. * if not, arp all of the gateways and return an error. * Next call will probably catch the result of the ARP. */ haveg = 0; for(i=CACHELEN-1; i>=0; i--) if(arpc[i].gate && elapsed(arpc[i].tm) < CACHETO) return(i); if(elapsed(arptime) > nnarpto*TICKSPERSEC) { for(i=CACHELEN-1; i>=0; i--) if(arpc[i].gate) { haveg = 1; /* * put out a broadcast request */ reqarp(arpc[i].ip); } /* * blind luck, try ARPing even for * a node not on our net. (proxy ARP) */ if(!haveg) reqarp(ipn); arptime = cticks(NULL); } return(-1); } } /* * getdlayer * * check for the hardware address one time */ char *getdlayer(tipnum) register char *tipnum; { int needgate,i; /* * Check to see if we need to go through a gateway. If the machine * is on our network, then assume that we can send an ARP * to that machine, otherwise, send the ARP to the gateway. * * Uses internet standard subnet mask method, RFC950. If subnets * are not in use, netmask has been pre-set to the appropriate * network addressing mask. */ needgate = 0; for(i=3; i>=0; i--) if((nnmask[i] & tipnum[i])!=(nnmask[i] & nnipnum[i])) needgate = 1; if(0<=(i = cachelook(tipnum,needgate,1))) return(arpc[i].hrd); return(NULL); } /* * ntdlayer * * get data layer address for insertion into outgoing packets. * searches based on ip number. If it finds the address, ok, else . . . * * Checks to see if the address is on the same network. If it is, * then ARPs the machine to get address. Forces pause between sending * arps to guarantee not saturating network. * * If not on the same network, it needs the ether address of a * gateway. Searches the list of machines for a gateway flag. * Returns the first gateway found with an Ethernet address. * * Returns NULL if not here, or pointer to ether address if here. * If we don't have it, this also sends an ARP request so that the * next time we are called, the ARP reply may be here by then. */ char *ntdlayer(tipnum) register char *tipnum; { long start,t; char *pc; /* * some seconds time out */ start = cticks(NULL); t = nndto*TICKSPERSEC; pc = NULL; while(((pc = getdlayer(tipnum)) == NULL) && (elapsed(start) < t)) { /* * can't have deadlock */ suspnd(0); ntsleep(0); } return(pc); } /* * ntgtrarp * * Look for a RARP response to arrive * wait for nnarpto seconds before returning failure. * If response arrives, return success. */ int ntgtrarp() { long start,t,tr; /* * some seconds time out */ start = cticks(NULL); t = nnarpto*TICKSPERSEC; tr = 0L; do { if(elapsed(start) >= tr) { rarp(); tr += TICKSPERSEC; } if(elapsed(start) > t) { ntposterr(103); return(-1); } suspnd(0); ntsleep(0); } while(comparen(nnipnum,"RARP",4)); return(0); } /* * ntstgate * * Establish an IP number to use as a gateway. * They are added in the order that they arrive and there is a limit on * the number of gateways equal to CACHELEN/2. * ARPs them as they are added so that the Cache will get pre-filled * with gateways. * * returns 0 if ok, -1 on error(full) */ int ntstgate(ipn) register char *ipn; { int i; for(i=CACHELEN-1 ; i>=CACHELEN/2 ; i--) { if(!arpc[i].gate) { arpc[i].gate = 1; movebytes(arpc[i].ip,ipn,4); reqarp(ipn); return(0); } } return(-1); }