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 freeblistchain(Block *bp)
77 * create a new arp entry for an ip address.
80 newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
84 Arpent *a, *e, *f, **l;
88 /* find oldest entry */
89 e = &arp->cache[NCACHE];
92 for(f = a; f < e; f++){
99 /* dump waiting packets */
104 else { /* queue icmp unreachable for rxmitproc later on, w/o arp lock */
106 if(arp->dropf == nil)
109 arp->dropl->list = xp;
110 arp->dropl = a->last;
116 /* take out of current chain */
117 l = &arp->hash[haship(a->ip)];
118 for(f = *l; f != nil; f = f->hash){
126 /* insert into new chain */
127 l = &arp->hash[haship(ip)];
131 memmove(a->ip, ip, sizeof(a->ip));
136 a->rtime = NOW + ReTransTimer;
137 a->rxtsrem = MAX_MULTICAST_SOLICIT;
139 a->ifcid = ifc->ifcid;
141 /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
142 if(!ipismulticast(a->ip) && addrxt){
146 for(f = *l; f != nil; f = f->nextrxt){
153 for(f = *l; f != nil; f = f->nextrxt)
166 /* called with arp qlocked */
169 cleanarpent(Arp *arp, Arpent *a)
178 /* take out of current chain */
179 l = &arp->hash[haship(a->ip)];
180 for(f = *l; f != nil; f = f->hash){
188 /* take out of re-transmit chain */
190 for(f = *l; f != nil; f = f->nextrxt){
199 freeblistchain(a->hold);
200 a->hold = a->last = nil;
205 * fill in the media address if we have it. Otherwise return an
206 * Arpent that represents the state of the address resolution FSM
207 * for ip. Add the packet to be sent onto the list of packets
208 * waiting for ip->mac to be resolved.
211 arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
215 Medium *type = ifc->m;
216 uchar v6ip[IPaddrlen];
225 for(a = arp->hash[hash]; a != nil; a = a->hash){
226 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
232 a = newarp6(arp, ip, ifc, (version != V4));
236 if(a->state == AWAIT){
245 return a; /* return with arp qlocked */
248 memmove(mac, a->mac, a->type->maclen);
250 /* remove old entries */
251 if(NOW - a->ctime > 15*60*1000)
259 * called with arp locked
262 arprelease(Arp *arp, Arpent*)
268 * Copy out the mac address from the Arpent. Return the
269 * block waiting to get sent to this mac address.
271 * called with arp locked
274 arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
281 for(f = *l; f != nil; f = f->nextrxt){
290 memmove(a->mac, mac, type->maclen);
295 assert(bp->list == nil);
296 a->hold = a->last = nil;
303 arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
311 uchar v6ip[IPaddrlen];
320 r = v4lookup(fs, ip, nil);
325 r = v6lookup(fs, ip, nil);
328 panic("arpenter: version %d", version);
329 return; /* to supress warnings */
339 for(a = arp->hash[haship(ip)]; a != nil; a = a->hash){
340 if(a->type != type || (a->state != AWAIT && a->state != AOK))
343 if(ipcmp(a->ip, ip) == 0){
345 memmove(a->mac, mac, type->maclen);
348 /* take out of re-transmit chain */
350 for(f = *l; f != nil; f = f->nextrxt){
360 a->ifcid = ifc->ifcid;
362 a->hold = a->last = nil;
372 freeblistchain(next);
378 ifc->m->bwrite(ifc, bp, version, ip);
390 a = newarp6(arp, ip, ifc, 0);
394 memmove(a->mac, mac, type->maclen);
401 arpwrite(Fs *fs, char *s, int len)
408 char *f[4], buf[256];
409 uchar ip[IPaddrlen], mac[MAClen];
415 if(len >= sizeof(buf))
417 strncpy(buf, s, len);
419 if(len > 0 && buf[len-1] == '\n')
422 n = getfields(buf, f, 4, 1, " ");
423 if(strcmp(f[0], "flush") == 0){
425 for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
426 memset(a->ip, 0, sizeof(a->ip));
427 memset(a->mac, 0, sizeof(a->mac));
431 freeblistchain(a->hold);
432 a->hold = a->last = nil;
434 memset(arp->hash, 0, sizeof(arp->hash));
435 /* clear all pkts on these lists (rxmt, dropf/l) */
437 freeblistchain(arp->dropf);
438 arp->dropf = arp->dropl = nil;
440 } else if(strcmp(f[0], "add") == 0){
445 if (parseip(ip, f[1]) == -1)
448 r = v4lookup(fs, ip+IPv4off, nil);
450 r = v6lookup(fs, ip, nil);
452 error("Destination unreachable");
454 n = parsemac(mac, f[2], m->maclen);
457 m = ipfindmedium(f[1]);
460 if (parseip(ip, f[2]) == -1)
462 n = parsemac(mac, f[3], m->maclen);
469 m->ares(fs, V6, ip, mac, n, 0);
470 } else if(strcmp(f[0], "del") == 0){
474 if (parseip(ip, f[1]) == -1)
478 for(a = arp->hash[haship(ip)]; a != nil; a = a->hash)
479 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
484 memset(a->ip, 0, sizeof(a->ip));
485 memset(a->mac, 0, sizeof(a->mac));
499 char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
502 convmac(char *p, uchar *mac, int n)
505 p += sprint(p, "%2.2ux", *mac++);
509 arpread(Arp *arp, char *p, ulong offset, int len)
513 char mac[2*MAClen+1];
515 if(offset % Alinelen)
518 offset = offset/Alinelen;
522 for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
531 convmac(mac, a->mac, a->type->maclen);
532 n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac);
546 uchar ipsrc[IPaddrlen];
556 goto dodrops; /* return nrxt; */
558 nrxt = a->rtime - NOW;
559 if(nrxt > 3*ReTransTimer/4)
560 goto dodrops; /* return nrxt; */
562 for(; a != nil; a = a->nextrxt){
564 if(a->rxtsrem > 0 && ifc != nil && canrlock(ifc)){
565 if(a->ifcid == ifc->ifcid)
572 if(arp->dropf == nil)
575 arp->dropl->list = xp;
576 arp->dropl = a->last;
584 qunlock(arp); /* for icmpns */
585 if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC)
586 icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
591 /* put to the end of re-transmit chain */
593 for(b = *l; b != nil; b = b->nextrxt){
600 for(b = *l; b != nil; b = b->nextrxt)
606 a->rtime = NOW + ReTransTimer;
612 nrxt = a->rtime - NOW;
616 arp->dropf = arp->dropl = nil;
619 for(; xp != nil; xp = next){
621 icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1);
631 Arp *arp = (Arp *) v;
633 return arp->rxmt != nil || arp->dropf != nil;
648 wakeupat = rxmitsols(arp);
650 sleep(&arp->rxmtq, rxready, v);
651 else if(wakeupat > ReTransTimer/4)
652 tsleep(&arp->rxmtq, return0, 0, wakeupat);