2 #include "../port/lib.h"
6 #include "../port/error.h"
12 * address resolution tables
41 Proc *rxmitp; /* neib sol re-transmit proc */
46 char *Ebadarp = "bad arp";
48 #define haship(s) ((s)[IPaddrlen-1]%NHASH)
50 extern int ReTransTimer = RETRANS_TIMER;
52 static void rxmitproc(void *v);
57 f->arp = smalloc(sizeof(Arp));
60 f->arp->dropf = f->arp->dropl = nil;
61 kproc("rxmitproc", rxmitproc, f->arp);
65 * create a new arp entry for an ip address.
68 newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
72 Arpent *a, *e, *f, **l;
76 /* find oldest entry */
77 e = &arp->cache[NCACHE];
80 for(f = a; f < e; f++){
87 /* dump waiting packets */
98 else { /* queue icmp unreachable for rxmitproc later on, w/o arp lock */
100 if(arp->dropl == nil)
103 arp->dropl->list = xp;
105 for(next = xp->list; next; next = next->list)
112 /* take out of current chain */
113 l = &arp->hash[haship(a->ip)];
114 for(f = *l; f; f = f->hash){
122 /* insert into new chain */
123 l = &arp->hash[haship(ip)];
127 memmove(a->ip, ip, sizeof(a->ip));
132 a->rtime = NOW + ReTransTimer;
133 a->rxtsrem = MAX_MULTICAST_SOLICIT;
135 a->ifcid = ifc->ifcid;
137 /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
138 if(!ipismulticast(a->ip) && addrxt){
142 for(f = *l; f; f = f->nextrxt){
149 for(f = *l; f; f = f->nextrxt){
162 /* called with arp qlocked */
165 cleanarpent(Arp *arp, Arpent *a)
174 /* take out of current chain */
175 l = &arp->hash[haship(a->ip)];
176 for(f = *l; f; f = f->hash){
184 /* take out of re-transmit chain */
186 for(f = *l; f; f = f->nextrxt){
201 * fill in the media address if we have it. Otherwise return an
202 * Arpent that represents the state of the address resolution FSM
203 * for ip. Add the packet to be sent onto the list of packets
204 * waiting for ip->mac to be resolved.
207 arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
211 Medium *type = ifc->m;
212 uchar v6ip[IPaddrlen];
221 for(a = arp->hash[hash]; a; a = a->hash){
222 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
228 a = newarp6(arp, ip, ifc, (version != V4));
232 if(a->state == AWAIT){
241 return a; /* return with arp qlocked */
244 memmove(mac, a->mac, a->type->maclen);
246 /* remove old entries */
247 if(NOW - a->ctime > 15*60*1000)
255 * called with arp locked
258 arprelease(Arp *arp, Arpent*)
264 * Copy out the mac address from the Arpent. Return the
265 * block waiting to get sent to this mac address.
267 * called with arp locked
270 arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
277 for(f = *l; f; f = f->nextrxt){
286 memmove(a->mac, mac, type->maclen);
298 arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
306 uchar v6ip[IPaddrlen];
311 // print("arp: len = %d\n", n);
317 r = v4lookup(fs, ip, nil);
322 r = v6lookup(fs, ip, nil);
325 panic("arpenter: version %d", version);
326 return; /* to supress warnings */
330 // print("arp: no route for entry\n");
338 for(a = arp->hash[haship(ip)]; a; a = a->hash){
339 if(a->type != type || (a->state != AWAIT && a->state != AOK))
342 if(ipcmp(a->ip, ip) == 0){
344 memmove(a->mac, mac, type->maclen);
347 /* take out of re-transmit chain */
349 for(f = *l; f; f = f->nextrxt){
359 a->ifcid = ifc->ifcid;
377 ifc->m->bwrite(ifc, bp, version, ip);
391 a = newarp6(arp, ip, ifc, 0);
395 memmove(a->mac, mac, type->maclen);
402 arpwrite(Fs *fs, char *s, int len)
410 char *f[4], buf[256];
411 uchar ip[IPaddrlen], mac[MAClen];
417 if(len >= sizeof(buf))
419 strncpy(buf, s, len);
421 if(len > 0 && buf[len-1] == '\n')
424 n = getfields(buf, f, 4, 1, " ");
425 if(strcmp(f[0], "flush") == 0){
427 for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
428 memset(a->ip, 0, sizeof(a->ip));
429 memset(a->mac, 0, sizeof(a->mac));
433 while(a->hold != nil){
439 memset(arp->hash, 0, sizeof(arp->hash));
440 /* clear all pkts on these lists (rxmt, dropf/l) */
443 while(arp->dropf != nil){
444 bp = arp->dropf->list;
445 freeblist(arp->dropf);
449 } else if(strcmp(f[0], "add") == 0){
454 if (parseip(ip, f[1]) == -1)
457 r = v4lookup(fs, ip+IPv4off, nil);
459 r = v6lookup(fs, ip, nil);
461 error("Destination unreachable");
463 n = parsemac(mac, f[2], m->maclen);
466 m = ipfindmedium(f[1]);
469 if (parseip(ip, f[2]) == -1)
471 n = parsemac(mac, f[3], m->maclen);
478 m->ares(fs, V6, ip, mac, n, 0);
479 } else if(strcmp(f[0], "del") == 0){
483 if (parseip(ip, f[1]) == -1)
487 for(a = arp->hash[haship(ip)]; a; a = a->hash)
488 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
492 while(a->hold != nil){
498 memset(a->ip, 0, sizeof(a->ip));
499 memset(a->mac, 0, sizeof(a->mac));
513 char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
516 convmac(char *p, uchar *mac, int n)
519 p += sprint(p, "%2.2ux", *mac++);
523 arpread(Arp *arp, char *p, ulong offset, int len)
527 char mac[2*MAClen+1];
529 if(offset % Alinelen)
532 offset = offset/Alinelen;
536 for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
545 convmac(mac, a->mac, a->type->maclen);
546 n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac);
560 uchar ipsrc[IPaddrlen];
570 goto dodrops; /* return nrxt; */
572 nrxt = a->rtime - NOW;
573 if(nrxt > 3*ReTransTimer/4)
574 goto dodrops; /* return nrxt; */
576 for(; a; a = a->nextrxt){
579 if((a->rxtsrem <= 0) || !(canrlock(ifc)) || (a->ifcid != ifc->ifcid)){
584 if(arp->dropl == nil)
587 arp->dropl->list = xp;
599 qunlock(arp); /* for icmpns */
600 if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC)
601 icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
606 /* put to the end of re-transmit chain */
608 for(b = *l; b; b = b->nextrxt){
615 for(b = *l; b; b = b->nextrxt){
621 a->rtime = NOW + ReTransTimer;
627 nrxt = a->rtime - NOW;
635 for(; xp; xp = next){
637 icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1);
647 Arp *arp = (Arp *) v;
650 x = ((arp->rxmt != nil) || (arp->dropf != nil));
662 //print("arp rxmitproc started\n");
668 wakeupat = rxmitsols(arp);
670 sleep(&arp->rxmtq, rxready, v);
671 else if(wakeupat > ReTransTimer/4)
672 tsleep(&arp->rxmtq, return0, 0, wakeupat);