123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- #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*[]);
- static
- struct
- {
- Lock;
- uchar null[Pasize];
- int start;
- int idgen;
- ulong flag;
- Msgbuf* unresol;
- struct
- {
- int laste;
- Arpe arpe[Ne];
- } abkt[Nb];
- } arpcache;
- int
- nhgets(uchar *p)
- {
- return (p[0]<<8) | p[1];
- }
- long
- nhgetl(uchar *p)
- {
- return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
- }
- void
- hnputs(uchar *p, int x)
- {
- p[0] = x>>8;
- p[1] = x;
- }
- void
- hnputl(uchar *p, long x)
- {
- p[0] = x>>24;
- p[1] = x>>16;
- p[2] = x>>8;
- p[3] = x;
- }
- void
- arpstart(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);
- }
- }
- void
- arpreceive(Enpkt *ep, int l, Ifc *ifc)
- {
- Ilp* ilp;
- Arppkt *p, *q;
- Msgbuf *mb, **mbp;
- Arpe *a;
- uchar *tpa;
- int type, i, h;
- ulong 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;
- }
- }
- static
- int
- ipahash(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;
- }
- void
- ipsend1(Msgbuf *mb, Ifc *ifc, uchar *ipgate)
- {
- Msgbuf **mbp, *m;
- Ippkt *p;
- Arppkt *q;
- Arpe *a;
- int i, id, len, dlen, off;
- ulong 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);
- }
- void
- ipsend(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);
- }
- int
- ipforme(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
- */
- int
- ipcsum(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 *aendian
- int
- ptclcsum(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;
- }
- static
- void
- cmd_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;
- }
- }
- }
|