📄 arp.c
字号:
#include "all.h"#include "../ip/ip.h"#define DEBUG if(cons.flags&arpcache.flag)print#define ORDER 1 /* 1 send last frag first, faster */typedef struct Arpentry Arpentry;typedef struct Arpstats Arpstats;typedef struct Arpe Arpe;struct Arpe{ uchar tpa[Pasize]; uchar tha[Easize];};static int ipahash(uchar*);static void cmd_arp(int, char*[]);staticstruct{ Lock; uchar null[Pasize]; int start; int idgen; ulong flag; Msgbuf* unresol; struct { int laste; Arpe arpe[Ne]; } abkt[Nb];} arpcache;intnhgets(uchar *p){ return (p[0]<<8) | p[1];}longnhgetl(uchar *p){ return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];}voidhnputs(uchar *p, int x){ p[0] = x>>8; p[1] = x;}voidhnputl(uchar *p, long x){ p[0] = x>>24; p[1] = x>>16; p[2] = x>>8; p[3] = x;}voidarpstart(void){ if(arpcache.start == 0) { lock(&arpcache); if(arpcache.start == 0) { cmd_install("arp", "subcommand -- arp protocol", cmd_arp); arpcache.flag = flag_install("arp", "-- verbose"); arpcache.start = 1; iprouteinit(); } unlock(&arpcache); }}voidarpreceive(Enpkt *ep, int l, Ifc *ifc){ Ilp* ilp; Arppkt *p, *q; Msgbuf *mb, **mbp; Arpe *a; uchar *tpa; int type, i, h; Timet t; if(l < Ensize+Arpsize) return; p = (Arppkt*)ep; if(nhgets(p->pro) != Iptype || nhgets(p->hrd) != 1 || p->pln != Pasize || p->hln != Easize) return; type = nhgets(p->op); switch(type) { case Arprequest: /* update entry for this source */ h = ipahash(p->spa); a = arpcache.abkt[h].arpe; lock(&arpcache); for(i=0; i<Ne; i++,a++) { if(memcmp(a->tpa, p->spa, Pasize) == 0) { memmove(a->tha, p->sha, Easize); break; } } unlock(&arpcache); if(memcmp(p->tpa, ifc->ipa, Pasize) != 0) break; DEBUG("rcv arp req for %I from %I\n", p->tpa, p->spa); mb = mballoc(Ensize+Arpsize, 0, Mbarp1); q = (Arppkt*)mb->data; memmove(q, p, Ensize+Arpsize); hnputs(q->op, Arpreply); memmove(q->tha, p->sha, Easize); memmove(q->tpa, p->spa, Pasize); memmove(q->sha, ifc->ea, Easize); memmove(q->spa, ifc->ipa, Pasize); memmove(q->d, q->s, Easize); send(ifc->reply, mb); break; case Arpreply: DEBUG("rcv arp rpl for %I is %E\n", p->spa, p->sha); h = ipahash(p->spa); a = arpcache.abkt[h].arpe; lock(&arpcache); for(i=0; i<Ne; i++,a++) { if(memcmp(a->tpa, p->spa, Pasize) == 0) { memmove(a->tha, p->sha, Easize); goto out; } } i = arpcache.abkt[h].laste + 1; if(i < 0 || i >= Ne) i = 0; arpcache.abkt[h].laste = i; a = &arpcache.abkt[h].arpe[i]; memmove(a->tpa, p->spa, Pasize); memmove(a->tha, p->sha, Easize); /* * go thru unresolved queue */ out: t = toytime(); mbp = &arpcache.unresol; for(mb = *mbp; mb; mb = *mbp) { if(t >= mb->param) { *mbp = mb->next; unlock(&arpcache); mbfree(mb); lock(&arpcache); goto out; } ilp = mb->chan->pdata; tpa = ilp->ipgate; if(memcmp(a->tpa, tpa, Pasize) == 0) { *mbp = mb->next; mb->next = 0; unlock(&arpcache); ipsend(mb); lock(&arpcache); goto out; } mbp = &mb->next; } unlock(&arpcache); break; }}staticintipahash(uchar *p){ ulong h; h = p[0]; h = h*7 + p[1]; h = h*7 + p[2]; h = h*7 + p[3]; return h%Nb;}voidipsend1(Msgbuf *mb, Ifc *ifc, uchar *ipgate){ Msgbuf **mbp, *m; Ippkt *p; Arppkt *q; Arpe *a; int i, id, len, dlen, off; Timet t; p = (Ippkt*)mb->data; a = arpcache.abkt[ipahash(ipgate)].arpe; lock(&arpcache); for(i=0; i<Ne; i++,a++) if(memcmp(a->tpa, ipgate, Pasize) == 0) goto found; /* * queue ip pkt to be resolved later */again: i = 0; // q length t = toytime(); mbp = &arpcache.unresol; for(m = *mbp; m; m = *mbp) { if(t >= m->param) { *mbp = m->next; unlock(&arpcache); mbfree(m); lock(&arpcache); goto again; } mbp = &m->next; i++; } if(mb->chan && i < 10) { mb->param = t + SECOND(10); mb->next = 0; *mbp = mb; unlock(&arpcache); } else { unlock(&arpcache); mbfree(mb); } /* * send an arp request */ m = mballoc(Ensize+Arpsize, 0, Mbarp2); q = (Arppkt*)m->data; DEBUG("snd arp req target %I ip dest %I\n", ipgate, p->dst); memset(q->d, 0xff, Easize); /* broadcast */ hnputs(q->type, Arptype); hnputs(q->hrd, 1); hnputs(q->pro, Iptype); q->hln = Easize; q->pln = Pasize; hnputs(q->op, Arprequest); memmove(q->sha, ifc->ea, Easize); memmove(q->spa, ifc->ipa, Pasize); memset(q->tha, 0, Easize); memmove(q->tpa, ipgate, Pasize); send(ifc->reply, m); return;found: len = mb->count; /* includes Ensize+Ipsize+Ilsize */ memmove(p->d, a->tha, Easize); p->vihl = IP_VER|IP_HLEN; p->tos = 0; p->ttl = 255; id = arpcache.idgen; if(id == 0) id = toytime() * 80021; arpcache.idgen = id+1; unlock(&arpcache); hnputs(p->id, id); hnputs(p->type, Iptype); /* * If we dont need to fragment just send it */ if(len <= ETHERMAXTU) { hnputs(p->length, len-Ensize); p->frag[0] = 0; p->frag[1] = 0; p->cksum[0] = 0; p->cksum[1] = 0; hnputs(p->cksum, ipcsum(&p->vihl)); send(ifc->reply, mb); return; } off = 0; len -= Ensize+Ipsize; /* just ip data */ while(len > 0) { dlen = (ETHERMAXTU-(Ensize+Ipsize)) & ~7; if(dlen > len) dlen = len; len -= dlen; /* * use first frag in place, * make copies of subsequent frags * this saves a copy of a MTU-size buffer */ if(ORDER && off == 0) { m = 0; mb->count = (Ensize+Ipsize)+dlen; p = (Ippkt*)mb->data; } else { m = mballoc((Ensize+Ipsize)+dlen, 0, Mbip1); p = (Ippkt*)m->data; memmove(m->data, mb->data, Ensize+Ipsize); memmove(m->data+(Ensize+Ipsize), mb->data+(Ensize+Ipsize)+off, dlen); } hnputs(p->length, dlen+Ipsize); if(len == 0) hnputs(p->frag, off>>3); else hnputs(p->frag, (off>>3)|IP_MF); p->cksum[0] = 0; p->cksum[1] = 0; hnputs(p->cksum, ipcsum(&p->vihl)); if(m) send(ifc->reply, m); off += dlen; } if(ORDER) send(ifc->reply, mb); else mbfree(mb);}voidipsend(Msgbuf *mb){ Ilp *ilp; Chan *cp; cp = mb->chan; if(cp == 0) { print("cp = 0\n"); mbfree(mb); return; } ilp = cp->pdata; ipsend1(mb, cp->ifc, ilp->ipgate);}intipforme(uchar addr[Pasize], Ifc *ifc){ ulong haddr; if(memcmp(addr, ifc->ipa, Pasize) == 0) return 1; haddr = nhgetl(addr); /* My subnet broadcast */ if((haddr&ifc->mask) == (ifc->ipaddr&ifc->mask)) return 1; /* Real ip broadcast */ if(haddr == 0) return 1; /* Old style 255.255.255.255 address */ if(haddr == ~0) return 1; return 0;}/* * ipcsum - Compute internet header checksums */intipcsum(uchar *addr){ int len; ulong sum = 0; len = (addr[0]&0xf) << 2; while(len > 0) { sum += (addr[0]<<8) | addr[1] ; len -= 2; addr += 2; } sum = (sum & 0xffff) + (sum >> 16); sum = (sum & 0xffff) + (sum >> 16); return sum^0xffff;}/* * protcol checksum routine */static short endian = 1;static char* aendian = (char*)&endian;#define LITTLE *aendianintptclcsum(uchar *addr, int len){ ulong losum, hisum, mdsum, x; ulong t1, t2; losum = 0; hisum = 0; mdsum = 0; x = 0; if((ulong)addr & 1) { if(len) { hisum += addr[0]; len--; addr++; } x = 1; } while(len >= 16) { t1 = *(ushort*)(addr+0); t2 = *(ushort*)(addr+2); mdsum += t1; t1 = *(ushort*)(addr+4); mdsum += t2; t2 = *(ushort*)(addr+6); mdsum += t1; t1 = *(ushort*)(addr+8); mdsum += t2; t2 = *(ushort*)(addr+10); mdsum += t1; t1 = *(ushort*)(addr+12); mdsum += t2; t2 = *(ushort*)(addr+14); mdsum += t1; mdsum += t2; len -= 16; addr += 16; } while(len >= 2) { mdsum += *(ushort*)addr; len -= 2; addr += 2; } if(x) { if(len) losum += addr[0]; if(LITTLE) losum += mdsum; else hisum += mdsum; } else { if(len) hisum += addr[0]; if(LITTLE) hisum += mdsum; else losum += mdsum; } losum += hisum >> 8; losum += (hisum & 0xff) << 8; while(hisum = losum>>16) losum = hisum + (losum & 0xffff); return ~losum & 0xffff;}staticvoidcmd_arp(int argc, char *argv[]){ int h, i, j; Arpe *a; if(argc <= 1) { print("arp flush -- clear cache\n"); print("arp print -- print cache\n"); return; } for(i=1; i<argc; i++) { if(strcmp(argv[i], "flush") == 0) { lock(&arpcache); for(h=0; h<Nb; h++) memset(&arpcache.abkt[h], 0, sizeof(arpcache.abkt[0])); unlock(&arpcache); continue; } if(strcmp(argv[i], "print") == 0) { for(h=0; h<Nb; h++) { a = arpcache.abkt[h].arpe; for(j=0; j<Ne; j++,a++) { if(memcmp(arpcache.null, a->tpa, Pasize) == 0) continue; print("%-15I %E\n", a->tpa, a->tha); prflush(); } } continue; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -