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 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 on ifc.
80 newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
84 Arpent *a, *e, *f, **l;
87 /* find oldest entry */
88 e = &arp->cache[NCACHE];
91 for(f = a; f < e; f++){
98 /* dump waiting packets */
103 else { /* queue icmp unreachable for rxmitproc later on, w/o arp lock */
105 if(arp->dropf == nil)
108 arp->dropl->list = xp;
109 arp->dropl = a->last;
115 /* take out of current chain */
116 l = &arp->hash[haship(a->ip)];
117 for(f = *l; f != nil; f = f->hash){
125 /* insert into new chain */
126 l = &arp->hash[haship(ip)];
134 a->rtime = NOW + ReTransTimer;
135 a->rxtsrem = MAX_MULTICAST_SOLICIT;
137 a->ifcid = ifc->ifcid;
139 /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
140 if(!ipismulticast(a->ip) && addrxt){
144 for(f = *l; f != nil; f = f->nextrxt){
151 for(f = *l; f != nil; f = f->nextrxt)
164 /* called with arp qlocked */
167 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;
204 * fill in the media address if we have it. Otherwise return an
205 * Arpent that represents the state of the address resolution FSM
206 * for ip. Add the packet to be sent onto the list of packets
207 * waiting for ip->mac to be resolved.
210 arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
214 uchar v6ip[IPaddrlen];
223 for(a = arp->hash[hash]; a != nil; a = a->hash){
224 if(a->ifc == ifc && a->ifcid == ifc->ifcid && ipcmp(ip, 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, ifc->m->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 != nil; f = f->nextrxt){
285 memmove(a->mac, mac, type->maclen);
289 a->hold = a->last = nil;
296 arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *src, int refresh)
304 uchar v6ip[IPaddrlen];
309 r = v4lookup(fs, ip, src, nil);
314 r = v6lookup(fs, ip, src, nil);
317 panic("arpenter: version %d", version);
318 return -1; /* to supress warnings */
320 if(r == nil || (ifc = r->ifc) == nil || (m = ifc->m) == nil || m->maclen != n || m->maclen == 0)
324 for(a = arp->hash[haship(ip)]; a != nil; a = a->hash){
325 if(a->state != AWAIT && a->state != AOK)
327 if(a->ifc != ifc || a->ifcid != ifc->ifcid)
329 if(ipcmp(a->ip, ip) == 0){
331 memmove(a->mac, mac, n);
334 /* take out of re-transmit chain */
336 for(f = *l; f != nil; f = f->nextrxt){
346 a->hold = a->last = nil;
367 freeblistchain(next);
370 m->bwrite(ifc, concatblock(bp), version, ip);
381 a = newarp6(arp, ip, ifc, 0);
384 memmove(a->mac, mac, n);
392 arpwrite(Fs *fs, char *s, int len)
398 char *f[5], buf[256];
399 uchar ip[IPaddrlen], src[IPaddrlen], mac[MAClen];
405 if(len >= sizeof(buf))
407 strncpy(buf, s, len);
409 if(len > 0 && buf[len-1] == '\n')
412 n = getfields(buf, f, nelem(f), 1, " ");
413 if(strcmp(f[0], "flush") == 0){
415 for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
416 memset(a->ip, 0, sizeof(a->ip));
417 memset(a->mac, 0, sizeof(a->mac));
423 freeblistchain(a->hold);
424 a->hold = a->last = nil;
426 memset(arp->hash, 0, sizeof(arp->hash));
427 /* clear all pkts on these lists (rxmt, dropf/l) */
429 freeblistchain(arp->dropf);
430 arp->dropf = arp->dropl = nil;
432 } else if(strcmp(f[0], "add") == 0){
437 if(parseip(ip, f[1]) == -1)
439 if((n = parsemac(mac, f[2], sizeof(mac))) <= 0)
441 findlocalip(fs, src, ip);
444 m = ipfindmedium(f[1]);
445 if(m == nil || m->maclen == 0)
447 if(parseip(ip, f[2]) == -1)
449 if((n = parsemac(mac, f[3], sizeof(mac))) != m->maclen)
451 findlocalip(fs, src, ip);
454 m = ipfindmedium(f[1]);
455 if(m == nil || m->maclen == 0)
457 if(parseip(ip, f[2]) == -1)
459 if((n = parsemac(mac, f[3], sizeof(mac))) != m->maclen)
461 if(parseip(src, f[4]) == -1)
465 if(arpenter(fs, V6, ip, mac, n, src, 0) <= 0)
466 error("destination unreachable");
467 } else if(strcmp(f[0], "del") == 0){
470 if (parseip(ip, f[1]) == -1)
473 for(a = arp->hash[haship(ip)]; a != nil; a = x){
475 if(ipcmp(ip, a->ip) == 0){
477 memset(a->ip, 0, sizeof(a->ip));
478 memset(a->mac, 0, sizeof(a->mac));
489 convmac(char *p, uchar *mac, int n)
492 p += sprint(p, "%2.2ux", *mac++);
496 arpread(Arp *arp, char *s, ulong offset, int len)
498 uchar ip[IPaddrlen], src[IPaddrlen];
499 char mac[2*MAClen+1], *p, *state;
506 for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
507 if(a->state == 0 || (ifc = a->ifc) == nil || a->ifcid != ifc->ifcid)
511 state = arpstate[a->state];
513 convmac(mac, a->mac, ifc->m->maclen);
516 ipv6local(ifc, src, ip);
517 n = snprint(p, len, "%-6.6s %-4.4s %-40.40I %-16.16s %I\n",
518 ifc->m->name, state, ip, mac, src);
521 memmove(p, p-o, n+o);
533 ndpsendsol(Fs *f, Ipifc *ifc, Arpent *a)
535 uchar targ[IPaddrlen], src[IPaddrlen];
540 ipmove(src, ((Ip6hdr*)a->last->rp)->src);
541 arprelease(f->arp, a);
543 if(iplocalonifc(ifc, src) != nil || ipproxyifc(f, ifc, src))
546 arprelease(f->arp, a);
549 if(!ipv6local(ifc, src, targ))
552 icmpns(f, src, SRC_UNI, targ, TARG_MULTI, ifc->mac);
570 goto dodrops; /* return nrxt; */
572 nrxt = a->rtime - NOW;
573 if(nrxt > 3*ReTransTimer/4)
574 goto dodrops; /* return nrxt; */
576 for(; a != nil; a = a->nextrxt){
578 if(a->rxtsrem > 0 && ifc != nil && canrlock(ifc)){
579 if(a->ifcid == ifc->ifcid)
586 if(arp->dropf == nil)
589 arp->dropl->list = xp;
590 arp->dropl = a->last;
597 ndpsendsol(f, ifc, a); /* unlocks arp */
602 /* put to the end of re-transmit chain */
604 for(b = *l; b != nil; b = b->nextrxt){
611 for(b = *l; b != nil; b = b->nextrxt)
617 a->rtime = NOW + ReTransTimer;
623 nrxt = a->rtime - NOW;
627 arp->dropf = arp->dropl = nil;
630 for(; xp != nil; xp = next){
632 icmphostunr6(f, ifc, xp, Icmp6_adr_unreach, 1);
643 Arp *arp = (Arp *) v;
645 return arp->rxmt != nil || arp->dropf != nil;
660 wakeupat = rxmitsols(arp);
662 sleep(&arp->rxmtq, rxready, v);
663 else if(wakeupat > ReTransTimer/4)
664 tsleep(&arp->rxmtq, return0, 0, wakeupat);