📄 arp.c
字号:
/* arpstuff.c: * This code supports some basic arp/rarp stuff. * * General notice: * This code is part of a boot-monitor package developed as a generic base * platform for embedded system designs. As such, it is likely to be * distributed to various projects beyond the control of the original * author. Please notify the author of any enhancements made or bugs found * so that all may benefit from the changes. In addition, notification back * to the author will allow the new user to pick up changes that may have * been made by other users after this version of the code was distributed. * * Note1: the majority of this code was edited with 4-space tabs. * Note2: as more and more contributions are accepted, the term "author" * is becoming a mis-representation of credit. * * Original author: Ed Sutter * Email: esutter@lucent.com * Phone: 908-582-2351 */#include "config.h"#if INCLUDE_ETHERNET#include "endian.h"#include "genlib.h"#include "ether.h"#include "stddefs.h"#include "cli.h"void ArpFlush(void), ArpShow(char *);int ArpStore(uchar *,uchar *);int IpIsOnThisNet(uchar *);/* arpcache[]: * Used to store the most recent set of IP-to-MAC address correlations. */struct arpcache { uchar ip[4]; uchar ether[6];} ArpCache[SIZEOFARPCACHE];/* ArpIdx & ArpTot: * Used for keeping track of current arp cache content. */int ArpIdx, ArpTot;/* ArpStore(): * Called with binary ip and ethernet addresses. * It will store that set away in the cache. */intArpStore(uchar *ip,uchar *ether){ if (EtherFromCache(ip)) return(0); if (ArpIdx >= SIZEOFARPCACHE) ArpIdx=0; memcpy((char *)ArpCache[ArpIdx].ip,(char *)ip,4); memcpy((char *)ArpCache[ArpIdx].ether,(char *)ether,6); ArpIdx++; ArpTot++; return(0);}/* EtherFromCache(): * Called with a binary (4-byte) ip address. If a match is found * in the cache, return a pointer to that ethernet address; else * return NULL. */uchar *EtherFromCache(uchar *ip){ int i, max; if (ArpTot >= SIZEOFARPCACHE) max = SIZEOFARPCACHE; else max = ArpTot; for(i=0;i<SIZEOFARPCACHE;i++) { if (!memcmp(ArpCache[i].ip,ip,4)) return(ArpCache[i].ether); } return(0);}voidArpFlush(void){ int i; for(i=0;i<SIZEOFARPCACHE;i++) { memset(ArpCache[i].ip,0,4); memset(ArpCache[i].ether,0,6); } ArpIdx = ArpTot = 0;}/* ArpShow(): * Dump the content of the current arp cache. */voidArpShow(char *ip){ struct arpcache *ap, *end; if (ArpTot < SIZEOFARPCACHE) end = &ArpCache[ArpTot]; else end = &ArpCache[SIZEOFARPCACHE]; for (ap=ArpCache;ap<end;ap++) { if ((!ip) || (!memcmp(ip,ap->ip,4))) { printf("%02x:%02x:%02x:%02x:%02x:%02x = ", ap->ether[0], ap->ether[1], ap->ether[2], ap->ether[3], ap->ether[4], ap->ether[5]); printf("%d.%d.%d.%d\n", ap->ip[0], ap->ip[1], ap->ip[2], ap->ip[3]); } }}/* SendArpResp(): * Called in response to an ARP REQUEST. The incoming ethernet * header pointer points to the memory area that contains the incoming * ethernet packet that this function is called in response to. * In other words, it is used to fill the majority of the response * packet fields. */intSendArpResp(struct ether_header *re){ struct ether_header *te; struct arphdr *ta, *ra; te = (struct ether_header *) getXmitBuffer(); memcpy((char *)&(te->ether_shost),BinEnetAddr,6); memcpy((char *)&(te->ether_dhost),(char *)&(re->ether_shost),6); te->ether_type = ecs(ETHERTYPE_ARP); ta = (struct arphdr *) (te + 1); ra = (struct arphdr *) (re + 1); ta->hardware = ra->hardware; ta->protocol = ra->protocol; ta->hlen = ra->hlen; ta->plen = ra->plen; ta->operation = ARP_RESPONSE; memcpy(ta->senderha,BinEnetAddr,6); memcpy(ta->senderia,ra->targetia,4); memcpy(ta->targetha,ra->senderha,6); memcpy(ta->targetia,ra->senderia,4); self_ecs(ta->hardware); self_ecs(ta->protocol); self_ecs(ta->operation); sendBuffer(ARPSIZE); return(0);}/* SendArpRequest(): */intSendArpRequest(uchar *ip){ struct ether_header *te; struct arphdr *ta; /* Populate the ethernet header: */ te = (struct ether_header *) getXmitBuffer(); memcpy((char *)&(te->ether_shost),BinEnetAddr,6); memcpy((char *)&(te->ether_dhost),BroadcastAddr,6); te->ether_type = ecs(ETHERTYPE_ARP); /* Populate the arp header: */ ta = (struct arphdr *) (te + 1); ta->hardware = ecs(1); /* 1 for ethernet */ ta->protocol = ecs(ETHERTYPE_IP); ta->hlen = 6; /* Length of hdware (ethernet) address */ ta->plen = 4; /* Length of protocol (ip) address */ ta->operation = ecs(ARP_REQUEST); memcpy(ta->senderha,BinEnetAddr,6); memcpy(ta->senderia,BinIpAddr,4); memcpy(ta->targetha,BroadcastAddr,6); memcpy(ta->targetia,ip,4); sendBuffer(ARPSIZE); return(0);}/* IpIsOnThisNet(): * Return 1 if the incoming ip is on this subnet; else 0. * For each bit in the netmask that is set to 1... * If the corresponding bits in the incoming IP and this board's IP * do not match, return 0; else return 1. * * Since this function needs a netmask, if NETMASK is not set, then * it uses the default based on the upper 3 bits of the IP address * (refer to TCP/IP Illustrated Volume 1 Pg8 for details). */intIpIsOnThisNet(uchar *ip){ static int printedwarning; int i; char *nm, *class; uchar binnetmask[8]; nm = getenv("NETMASK"); if (!nm) { memset(binnetmask,0xff,4); if ((BinIpAddr[0] & 0xe0) == 0xc0) { /* Class C */ binnetmask[3] = 0; class = "C"; } else if ((BinIpAddr[0] & 0xc0) == 0x80) { /* Class B */ binnetmask[3] = 0; binnetmask[2] = 0; class = "B"; } else if ((BinIpAddr[0] & 0x80) == 0x00) { /* Class A */ binnetmask[3] = 0; binnetmask[2] = 0; binnetmask[1] = 0; class = "A"; } else class = "???"; if (!printedwarning) { printf("Warning: NETMASK not set, defaulting to class %s ",class); printf("(%d.%d.%d.%d)\n", binnetmask[0],binnetmask[1],binnetmask[2],binnetmask[3]); printedwarning = 1; } } else IpToBin(nm,binnetmask); for(i=0;i<4;i++) { if ((ip[i] & binnetmask[i]) != (BinIpAddr[i] & binnetmask[i])) { return(0); } } return(1);}/* Arp(): * If no args, just dump the arp cache. * If arg is present, then assume it to be an ip address. * Check the arp cache for the presence of that ip<->correlation, if * present, print it; else issue and arp request for that IP and wait * for a response. */char *ArpHelp[] = { "Address resolution protocol", "-[fps:v] [IP]", " -f flush cache", " -p proxy arp", " -s{eadr} store eadr/IP into cache", " -v verbose", 0,};intArp(int argc,char *argv[]){ int opt, proxyarp; char binip[8], binether[8], *storeether; proxyarp = 0; storeether = (char *)0; while ((opt=getopt(argc,argv,"fps:v")) != -1) { switch(opt) { case 'f': /* Flush current arp cache */ ArpFlush(); break; case 's': /* Store specified IP/MAC combination in arp cache. */ storeether = optarg; break; case 'p': /* Assume gateway will run proxy arp */ proxyarp = 1; break; case 'v': /* Enable verbosity for ARP. */ EtherVerbose |= SHOW_ARP; break; default: return(CMD_PARAM_ERROR); } } if (argc == (optind+1)) { IpToBin(argv[optind],binip); if (storeether) { EtherToBin(storeether,binether); ArpStore(binip,binether); } else { if (ArpEther(binip,0,proxyarp)) ArpShow(binip); } } else ArpShow(0); EtherVerbose &= ~ SHOW_ARP; return(CMD_SUCCESS);}/* ArpEther(): * Retrieve the ethernet address that corresponds to the incoming IP * address. First check the local ArpCache[], then if not found issue * an ARP request... If the incoming IP is on this net, then issue the * request for the MAC address of that IP; otherwise, issue the request * for this net's GATEWAY. */uchar *ArpEther(uchar *binip, uchar *ecpy, int proxyarp){ int timeoutsecs, timeoutloops, retry; char *gip; uchar gbinip[8], *Ip, *ep; /* First check local cache. If found, return with pointer to MAC. */ ep = EtherFromCache(binip); if (ep) { if (ecpy) { memcpy(ecpy,ep,6); ep = ecpy; } return(ep); } retry = 0; RetransmitDelay(DELAY_INIT_ARP); while(1) { /* If IP is not on this net, the get the GATEWAY IP address. */ if (!proxyarp && !IpIsOnThisNet(binip)) { gip = getenv("GIPADD"); if (gip) { IpToBin(gip,gbinip); if (!IpIsOnThisNet(gbinip)) { printf("GIPADD/IPADD subnet confusion.\n"); return(0); } ep = EtherFromCache(gbinip); if (ep) { if (ecpy) { memcpy(ecpy,ep,6); ep = ecpy; } return(ep); } SendArpRequest(gbinip); Ip = gbinip; } else { SendArpRequest(binip); Ip = binip; } } else { SendArpRequest(binip); Ip = binip; } if (retry) { ulong ip; memcpy((char *)&ip,binip,4); printf(" ARP Retry #%d (%I)\n",retry,ip); } /* Now that the request has been issued, wait for a while to see if * the ARP cache is loaded with the result of the request. */ timeoutsecs = RetransmitDelay(DELAY_OR_TIMEOUT_RETURN); if (timeoutsecs == RETRANSMISSION_TIMEOUT) break; timeoutloops = LoopsPerSecond*timeoutsecs; while(timeoutloops > 0) { ep = EtherFromCache(Ip); if (ep) break; pollethernet(); timeoutloops--; } if (ep) { if (ecpy) { memcpy(ecpy,ep,6); ep = ecpy; } return(ep); } RetransmitDelay(DELAY_INCREMENT); retry++; } if ((EtherVerbose & SHOW_ARP) && (retry)) printf(" ARP giving up\n"); return(0);}/* processRARP(); * Called by the fundamental ethernet driver code to process a RARP * request. */intprocessRARP(struct ether_header *ehdr,ushort size){ struct arphdr *arpp; arpp = (struct arphdr *)(ehdr+1); self_ecs(arpp->hardware); self_ecs(arpp->protocol); self_ecs(arpp->operation); switch(arpp->operation) { case RARP_RESPONSE: if (!memcmp(arpp->targetha,BinEnetAddr,6)) { if (EtherVerbose & SHOW_ARP) { printf(" RARP Response from %d.%d.%d.%d\n", arpp->senderia[0],arpp->senderia[1], arpp->senderia[2],arpp->senderia[3]); printf(" MY IP: from %d.%d.%d.%d\n", arpp->targetia[0],arpp->targetia[1], arpp->targetia[2],arpp->targetia[3]); } memcpy(BinIpAddr,arpp->targetia,6); } break; case RARP_REQUEST: break; default: printf(" Invalid RARP operation: 0x%x\n",arpp->operation); return(-1); } return(0);}/* processARP(); * Called by the fundamental ethernet driver code to process a ARP * request. */char *processARP(struct ether_header *ehdr,ushort size){ struct arphdr *arpp; arpp = (struct arphdr *)(ehdr+1); self_ecs(arpp->hardware); self_ecs(arpp->protocol); self_ecs(arpp->operation); switch(arpp->operation) { case ARP_REQUEST: if (!memcmp(arpp->targetia,BinIpAddr,4)) { ArpStore(arpp->senderia,arpp->senderha); SendArpResp(ehdr); } break; case ARP_RESPONSE: if (!memcmp(arpp->targetia,BinIpAddr,4)) { ArpStore(arpp->senderia,arpp->senderha); } break; default: printf(" Invalid ARP operation: 0x%x\n",arpp->operation); return((char *)0); } return((char *)(arpp + 1));}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -