1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7
8 #include "ip.h"
9 #include "ipv6.h"
10
11 /*
12 * address resolution tables
13 */
14
15 enum
16 {
17 NHASH = (1<<6),
18 NCACHE = 256,
19
20 AOK = 1,
21 AWAIT = 2,
22 };
23
24 char *arpstate[] =
25 {
26 "UNUSED",
27 "OK",
28 "WAIT",
29 };
30
31 /*
32 * one per Fs
33 */
34 struct Arp
35 {
36 QLock;
37 Fs *f;
38 Arpent *hash[NHASH];
39 Arpent cache[NCACHE];
40 Arpent *rxmt;
41 Proc *rxmitp; /* neib sol re-transmit proc */
42 Rendez rxmtq;
43 Block *dropf, *dropl;
44 };
45
46 char *Ebadarp = "bad arp";
47
48 #define haship(s) ((s)[IPaddrlen-1]%NHASH)
49
50 extern int ReTransTimer = RETRANS_TIMER;
51
52 static void rxmitproc(void *v);
53
54 void
arpinit(Fs * f)55 arpinit(Fs *f)
56 {
57 f->arp = smalloc(sizeof(Arp));
58 f->arp->f = f;
59 f->arp->rxmt = nil;
60 f->arp->dropf = f->arp->dropl = nil;
61 kproc("rxmitproc", rxmitproc, f->arp);
62 }
63
64 /*
65 * create a new arp entry for an ip address.
66 */
67 static Arpent*
newarp6(Arp * arp,uchar * ip,Ipifc * ifc,int addrxt)68 newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
69 {
70 uint t;
71 Block *next, *xp;
72 Arpent *a, *e, *f, **l;
73 int empty;
74
75 /* find oldest entry */
76 e = &arp->cache[NCACHE];
77 a = arp->cache;
78 t = a->utime;
79 for(f = a; f < e; f++){
80 if(f->utime < t){
81 t = f->utime;
82 a = f;
83 }
84 }
85
86 /* dump waiting packets */
87 xp = a->hold;
88 a->hold = nil;
89
90 if(isv4(a->ip)){
91 while(xp){
92 next = xp->list;
93 freeblist(xp);
94 xp = next;
95 }
96 }
97 else { /* queue icmp unreachable for rxmitproc later on, w/o arp lock */
98 if(xp){
99 if(arp->dropl == nil)
100 arp->dropf = xp;
101 else
102 arp->dropl->list = xp;
103
104 for(next = xp->list; next; next = next->list)
105 xp = next;
106 arp->dropl = xp;
107 wakeup(&arp->rxmtq);
108 }
109 }
110
111 /* take out of current chain */
112 l = &arp->hash[haship(a->ip)];
113 for(f = *l; f; f = f->hash){
114 if(f == a){
115 *l = a->hash;
116 break;
117 }
118 l = &f->hash;
119 }
120
121 /* insert into new chain */
122 l = &arp->hash[haship(ip)];
123 a->hash = *l;
124 *l = a;
125
126 memmove(a->ip, ip, sizeof(a->ip));
127 a->utime = NOW;
128 a->ctime = 0;
129 a->type = ifc->medium;
130
131 a->rtime = NOW + ReTransTimer;
132 a->rxtsrem = MAX_MULTICAST_SOLICIT;
133 a->ifc = ifc;
134 a->ifcid = ifc->ifcid;
135
136 /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
137 if(!ipismulticast(a->ip) && addrxt){
138 l = &arp->rxmt;
139 empty = (*l==nil);
140
141 for(f = *l; f; f = f->nextrxt){
142 if(f == a){
143 *l = a->nextrxt;
144 break;
145 }
146 l = &f->nextrxt;
147 }
148 for(f = *l; f; f = f->nextrxt){
149 l = &f->nextrxt;
150 }
151 *l = a;
152 if(empty)
153 wakeup(&arp->rxmtq);
154 }
155
156 a->nextrxt = nil;
157
158 return a;
159 }
160
161 /* called with arp qlocked */
162
163 void
cleanarpent(Arp * arp,Arpent * a)164 cleanarpent(Arp *arp, Arpent *a)
165 {
166 Arpent *f, **l;
167
168 a->utime = 0;
169 a->ctime = 0;
170 a->type = 0;
171 a->state = 0;
172
173 /* take out of current chain */
174 l = &arp->hash[haship(a->ip)];
175 for(f = *l; f; f = f->hash){
176 if(f == a){
177 *l = a->hash;
178 break;
179 }
180 l = &f->hash;
181 }
182
183 /* take out of re-transmit chain */
184 l = &arp->rxmt;
185 for(f = *l; f; f = f->nextrxt){
186 if(f == a){
187 *l = a->nextrxt;
188 break;
189 }
190 l = &f->nextrxt;
191 }
192 a->nextrxt = nil;
193 a->hash = nil;
194 a->hold = nil;
195 a->last = nil;
196 a->ifc = nil;
197 }
198
199 /*
200 * fill in the media address if we have it. Otherwise return an
201 * Arpent that represents the state of the address resolution FSM
202 * for ip. Add the packet to be sent onto the list of packets
203 * waiting for ip->mac to be resolved.
204 */
205 Arpent*
arpget(Arp * arp,Block * bp,int version,Ipifc * ifc,uchar * ip,uchar * mac)206 arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
207 {
208 int hash;
209 Arpent *a;
210 Medium *type;
211 uchar v6ip[IPaddrlen];
212
213 if(version == V4){
214 v4tov6(v6ip, ip);
215 ip = v6ip;
216 }
217
218 qlock(arp);
219 hash = haship(ip);
220 type = ifc->medium;
221 for(a = arp->hash[hash]; a; a = a->hash){
222 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
223 if(type == a->type)
224 break;
225 }
226
227 if(a == nil){
228 a = newarp6(arp, ip, ifc, (version != V4));
229 a->state = AWAIT;
230 }
231 a->utime = NOW;
232 if(a->state == AWAIT){
233 if(bp != nil){
234 if(a->hold)
235 a->last->list = bp;
236 else
237 a->hold = bp;
238 a->last = bp;
239 bp->list = nil;
240 }
241 return a; /* return with arp qlocked */
242 }
243
244 memmove(mac, a->mac, a->type->maclen);
245
246 /* remove old entries */
247 if(NOW - a->ctime > 15*60*1000)
248 cleanarpent(arp, a);
249
250 qunlock(arp);
251 return nil;
252 }
253
254 /*
255 * called with arp locked
256 */
257 void
arprelease(Arp * arp,Arpent *)258 arprelease(Arp *arp, Arpent*)
259 {
260 qunlock(arp);
261 }
262
263 /*
264 * Copy out the mac address from the Arpent. Return the
265 * block waiting to get sent to this mac address.
266 *
267 * called with arp locked
268 */
269 Block*
arpresolve(Arp * arp,Arpent * a,Medium * type,uchar * mac)270 arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
271 {
272 Block *bp;
273 Arpent *f, **l;
274
275 if(!isv4(a->ip)){
276 l = &arp->rxmt;
277 for(f = *l; f; f = f->nextrxt){
278 if(f == a){
279 *l = a->nextrxt;
280 break;
281 }
282 l = &f->nextrxt;
283 }
284 }
285
286 memmove(a->mac, mac, type->maclen);
287 a->type = type;
288 a->state = AOK;
289 a->utime = NOW;
290 bp = a->hold;
291 a->hold = nil;
292 qunlock(arp);
293
294 return bp;
295 }
296
297 void
arpenter(Fs * fs,int version,uchar * ip,uchar * mac,int n,int refresh)298 arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
299 {
300 Arp *arp;
301 Route *r;
302 Arpent *a, *f, **l;
303 Ipifc *ifc;
304 Medium *type;
305 Block *bp, *next;
306 uchar v6ip[IPaddrlen];
307
308 arp = fs->arp;
309
310 if(n != 6){
311 // print("arp: len = %d\n", n);
312 return;
313 }
314
315 switch(version){
316 case V4:
317 r = v4lookup(fs, ip, nil);
318 v4tov6(v6ip, ip);
319 ip = v6ip;
320 break;
321 case V6:
322 r = v6lookup(fs, ip, nil);
323 break;
324 default:
325 panic("arpenter: version %d", version);
326 return; /* to supress warnings */
327 }
328
329 if(r == nil){
330 // print("arp: no route for entry\n");
331 return;
332 }
333
334 ifc = r->ifc;
335 type = ifc->medium;
336
337 qlock(arp);
338 for(a = arp->hash[haship(ip)]; a; a = a->hash){
339 if(a->type != type || (a->state != AWAIT && a->state != AOK))
340 continue;
341
342 if(ipcmp(a->ip, ip) == 0){
343 a->state = AOK;
344 memmove(a->mac, mac, type->maclen);
345
346 if(version == V6){
347 /* take out of re-transmit chain */
348 l = &arp->rxmt;
349 for(f = *l; f; f = f->nextrxt){
350 if(f == a){
351 *l = a->nextrxt;
352 break;
353 }
354 l = &f->nextrxt;
355 }
356 }
357
358 a->ifc = ifc;
359 a->ifcid = ifc->ifcid;
360 bp = a->hold;
361 a->hold = nil;
362 if(version == V4)
363 ip += IPv4off;
364 a->utime = NOW;
365 a->ctime = a->utime;
366 qunlock(arp);
367
368 while(bp){
369 next = bp->list;
370 if(ifc != nil){
371 if(waserror()){
372 runlock(ifc);
373 nexterror();
374 }
375 rlock(ifc);
376 if(ifc->medium != nil)
377 ifc->medium->bwrite(ifc, bp, version, ip);
378 else
379 freeb(bp);
380 runlock(ifc);
381 poperror();
382 } else
383 freeb(bp);
384 bp = next;
385 }
386 return;
387 }
388 }
389
390 if(refresh == 0){
391 a = newarp6(arp, ip, ifc, 0);
392 a->state = AOK;
393 a->type = type;
394 a->ctime = NOW;
395 memmove(a->mac, mac, type->maclen);
396 }
397
398 qunlock(arp);
399 }
400
401 int
arpwrite(Fs * fs,char * s,int len)402 arpwrite(Fs *fs, char *s, int len)
403 {
404 int n;
405 Route *r;
406 Arp *arp;
407 Block *bp;
408 Arpent *a, *fl, **l;
409 Medium *type;
410 char *f[4], buf[256];
411 uchar ip[IPaddrlen], mac[MAClen];
412
413 arp = fs->arp;
414
415 if(len == 0)
416 error(Ebadarp);
417 if(len >= sizeof(buf))
418 len = sizeof(buf)-1;
419 strncpy(buf, s, len);
420 buf[len] = 0;
421 if(len > 0 && buf[len-1] == '\n')
422 buf[len-1] = 0;
423
424 n = getfields(buf, f, 4, 1, " ");
425 if(strcmp(f[0], "flush") == 0){
426 qlock(arp);
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));
430 a->hash = nil;
431 a->state = 0;
432 a->utime = 0;
433 while(a->hold != nil){
434 bp = a->hold->list;
435 freeblist(a->hold);
436 a->hold = bp;
437 }
438 }
439 memset(arp->hash, 0, sizeof(arp->hash));
440 /* clear all pkts on these lists (rxmt, dropf/l) */
441 arp->rxmt = nil;
442 arp->dropf = nil;
443 arp->dropl = nil;
444 qunlock(arp);
445 } else if(strcmp(f[0], "add") == 0){
446 switch(n){
447 default:
448 error(Ebadarg);
449 case 3:
450 if (parseip(ip, f[1]) == -1)
451 error(Ebadip);
452 if(isv4(ip))
453 r = v4lookup(fs, ip+IPv4off, nil);
454 else
455 r = v6lookup(fs, ip, nil);
456 if(r == nil)
457 error("Destination unreachable");
458 type = r->ifc->medium;
459 n = parsemac(mac, f[2], type->maclen);
460 break;
461 case 4:
462 type = ipfindmedium(f[1]);
463 if(type == nil)
464 error(Ebadarp);
465 if (parseip(ip, f[2]) == -1)
466 error(Ebadip);
467 n = parsemac(mac, f[3], type->maclen);
468 break;
469 }
470
471 if(type->ares == nil)
472 error(Ebadarp);
473
474 type->ares(fs, V6, ip, mac, n, 0);
475 } else if(strcmp(f[0], "del") == 0){
476 if(n != 2)
477 error(Ebadarg);
478
479 if (parseip(ip, f[1]) == -1)
480 error(Ebadip);
481 qlock(arp);
482
483 l = &arp->hash[haship(ip)];
484 for(a = *l; a; a = a->hash){
485 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0){
486 *l = a->hash;
487 break;
488 }
489 l = &a->hash;
490 }
491
492 if(a){
493 /* take out of re-transmit chain */
494 l = &arp->rxmt;
495 for(fl = *l; fl; fl = fl->nextrxt){
496 if(fl == a){
497 *l = a->nextrxt;
498 break;
499 }
500 l = &fl->nextrxt;
501 }
502
503 a->nextrxt = nil;
504 a->hash = nil;
505 a->hold = nil;
506 a->last = nil;
507 a->ifc = nil;
508 memset(a->ip, 0, sizeof(a->ip));
509 memset(a->mac, 0, sizeof(a->mac));
510 }
511 qunlock(arp);
512 } else
513 error(Ebadarp);
514
515 return len;
516 }
517
518 enum
519 {
520 Alinelen= 90,
521 };
522
523 char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
524
525 static void
convmac(char * p,char * ep,uchar * mac,int n)526 convmac(char *p, char *ep, uchar *mac, int n)
527 {
528 while(n-- > 0)
529 p = seprint(p, ep, "%2.2ux", *mac++);
530 }
531
532 int
arpread(Arp * arp,char * p,ulong offset,int len)533 arpread(Arp *arp, char *p, ulong offset, int len)
534 {
535 Arpent *a;
536 int n;
537 char mac[2*MAClen+1];
538
539 if(offset % Alinelen)
540 return 0;
541
542 offset = offset/Alinelen;
543 len = len/Alinelen;
544
545 n = 0;
546 for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
547 if(a->state == 0)
548 continue;
549 if(offset > 0){
550 offset--;
551 continue;
552 }
553 len--;
554 qlock(arp);
555 convmac(mac, &mac[sizeof mac], a->mac, a->type->maclen);
556 n += snprint(p+n, Alinelen+1, aformat, a->type->name,
557 arpstate[a->state], a->ip, mac); /* +1 for NUL */
558 qunlock(arp);
559 }
560
561 return n;
562 }
563
564 extern int
rxmitsols(Arp * arp)565 rxmitsols(Arp *arp)
566 {
567 uint sflag;
568 Block *next, *xp;
569 Arpent *a, *b, **l;
570 Fs *f;
571 uchar ipsrc[IPaddrlen];
572 Ipifc *ifc = nil;
573 long nrxt;
574
575 qlock(arp);
576 f = arp->f;
577
578 a = arp->rxmt;
579 if(a==nil){
580 nrxt = 0;
581 goto dodrops; /* return nrxt; */
582 }
583 nrxt = a->rtime - NOW;
584 if(nrxt > 3*ReTransTimer/4)
585 goto dodrops; /* return nrxt; */
586
587 for(; a; a = a->nextrxt){
588 ifc = a->ifc;
589 assert(ifc != nil);
590 if((a->rxtsrem <= 0) || !(canrlock(ifc)) || (a->ifcid != ifc->ifcid)){
591 xp = a->hold;
592 a->hold = nil;
593
594 if(xp){
595 if(arp->dropl == nil)
596 arp->dropf = xp;
597 else
598 arp->dropl->list = xp;
599 }
600
601 cleanarpent(arp, a);
602 }
603 else
604 break;
605 }
606 if(a == nil)
607 goto dodrops;
608
609
610 qunlock(arp); /* for icmpns */
611 if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC)
612 icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
613
614 runlock(ifc);
615 qlock(arp);
616
617 /* put to the end of re-transmit chain */
618 l = &arp->rxmt;
619 for(b = *l; b; b = b->nextrxt){
620 if(b == a){
621 *l = a->nextrxt;
622 break;
623 }
624 l = &b->nextrxt;
625 }
626 for(b = *l; b; b = b->nextrxt){
627 l = &b->nextrxt;
628 }
629 *l = a;
630 a->rxtsrem--;
631 a->nextrxt = nil;
632 a->rtime = NOW + ReTransTimer;
633
634 a = arp->rxmt;
635 if(a==nil)
636 nrxt = 0;
637 else
638 nrxt = a->rtime - NOW;
639
640 dodrops:
641 xp = arp->dropf;
642 arp->dropf = nil;
643 arp->dropl = nil;
644 qunlock(arp);
645
646 for(; xp; xp = next){
647 next = xp->list;
648 icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1);
649 }
650
651 return nrxt;
652
653 }
654
655 static int
rxready(void * v)656 rxready(void *v)
657 {
658 Arp *arp = (Arp *) v;
659 int x;
660
661 x = ((arp->rxmt != nil) || (arp->dropf != nil));
662
663 return x;
664 }
665
666 static void
rxmitproc(void * v)667 rxmitproc(void *v)
668 {
669 Arp *arp = v;
670 long wakeupat;
671
672 arp->rxmitp = up;
673 //print("arp rxmitproc started\n");
674 if(waserror()){
675 arp->rxmitp = 0;
676 pexit("hangup", 1);
677 }
678 for(;;){
679 wakeupat = rxmitsols(arp);
680 if(wakeupat == 0)
681 sleep(&arp->rxmtq, rxready, v);
682 else if(wakeupat > ReTransTimer/4)
683 tsleep(&arp->rxmtq, return0, 0, wakeupat);
684 }
685 }
686
687