arp.c - vx32 - Local 9vx git repository for patches.
(HTM) git clone git://r-36.net/vx32
(DIR) Log
(DIR) Files
(DIR) Refs
---
arp.c (11314B)
---
1 #include "u.h"
2 #include "lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "error.h"
7
8 #include "ip.h"
9 #include "ipv6.h"
10
11 /*
12 * address resolution tables
13 */
14 enum
15 {
16 NHASH = (1<<6),
17 NCACHE = 256,
18
19 AOK = 1,
20 AWAIT = 2,
21 };
22
23 char *arpstate[] =
24 {
25 "UNUSED",
26 "OK",
27 "WAIT",
28 };
29
30 /*
31 * one per Fs
32 */
33 struct Arp
34 {
35 QLock qlock;
36 Fs *f;
37 Arpent *hash[NHASH];
38 Arpent cache[NCACHE];
39 Arpent *rxmt;
40 Proc *rxmitp; /* neib sol re-transmit proc */
41 Rendez rxmtq;
42 Block *dropf, *dropl;
43 };
44
45 char *Ebadarp = "bad arp";
46
47 #define haship(s) ((ulong)((s)[IPaddrlen-1])%NHASH)
48
49 int ReTransTimer = RETRANS_TIMER;
50
51 static void rxmitproc(void *v);
52
53 void
54 arpinit(Fs *f)
55 {
56 f->arp = smalloc(sizeof(Arp));
57 f->arp->f = f;
58 f->arp->rxmt = nil;
59 f->arp->dropf = f->arp->dropl = nil;
60 kproc("rxmitproc", rxmitproc, f->arp);
61 }
62
63 /*
64 * create a new arp entry for an ip address.
65 */
66 static Arpent*
67 newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
68 {
69 uint t;
70 Block *next, *xp;
71 Arpent *a, *e, *f, **l;
72 Medium *m = ifc->m;
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 = m;
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
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*
206 arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
207 {
208 int hash;
209 Arpent *a;
210 Medium *type = ifc->m;
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 for(a = arp->hash[hash]; a; a = a->hash){
221 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
222 if(type == a->type)
223 break;
224 }
225
226 if(a == nil){
227 a = newarp6(arp, ip, ifc, (version != V4));
228 a->state = AWAIT;
229 }
230 a->utime = NOW;
231 if(a->state == AWAIT){
232 if(bp != nil){
233 if(a->hold)
234 a->last->list = bp;
235 else
236 a->hold = bp;
237 a->last = bp;
238 bp->list = nil;
239 }
240 return a; /* return with arp qlocked */
241 }
242
243 memmove(mac, a->mac, a->type->maclen);
244
245 /* remove old entries */
246 if(NOW - a->ctime > 15*60*1000)
247 cleanarpent(arp, a);
248
249 QUNLOCK(arp);
250 return nil;
251 }
252
253 /*
254 * called with arp locked
255 */
256 void
257 arprelease(Arp *arp, Arpent* ae)
258 {
259 QUNLOCK(arp);
260 }
261
262 /*
263 * Copy out the mac address from the Arpent. Return the
264 * block waiting to get sent to this mac address.
265 *
266 * called with arp locked
267 */
268 Block*
269 arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
270 {
271 Block *bp;
272 Arpent *f, **l;
273
274 if(!isv4(a->ip)){
275 l = &arp->rxmt;
276 for(f = *l; f; f = f->nextrxt){
277 if(f == a){
278 *l = a->nextrxt;
279 break;
280 }
281 l = &f->nextrxt;
282 }
283 }
284
285 memmove(a->mac, mac, type->maclen);
286 a->type = type;
287 a->state = AOK;
288 a->utime = NOW;
289 bp = a->hold;
290 a->hold = nil;
291 QUNLOCK(arp);
292
293 return bp;
294 }
295
296 void
297 arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
298 {
299 Arp *arp;
300 Route *r;
301 Arpent *a, *f, **l;
302 Ipifc *ifc;
303 Medium *type;
304 Block *bp, *next;
305 uchar v6ip[IPaddrlen];
306
307 arp = fs->arp;
308
309 if(n != 6){
310 // print("arp: len = %d\n", n);
311 return;
312 }
313
314 switch(version){
315 case V4:
316 r = v4lookup(fs, ip, nil);
317 v4tov6(v6ip, ip);
318 ip = v6ip;
319 break;
320 case V6:
321 r = v6lookup(fs, ip, nil);
322 break;
323 default:
324 panic("arpenter: version %d", version);
325 return; /* to supress warnings */
326 }
327
328 if(r == nil){
329 // print("arp: no route for entry\n");
330 return;
331 }
332
333 ifc = r->ifc;
334 type = ifc->m;
335
336 QLOCK(arp);
337 for(a = arp->hash[haship(ip)]; a; a = a->hash){
338 if(a->type != type || (a->state != AWAIT && a->state != AOK))
339 continue;
340
341 if(ipcmp(a->ip, ip) == 0){
342 a->state = AOK;
343 memmove(a->mac, mac, type->maclen);
344
345 if(version == V6){
346 /* take out of re-transmit chain */
347 l = &arp->rxmt;
348 for(f = *l; f; f = f->nextrxt){
349 if(f == a){
350 *l = a->nextrxt;
351 break;
352 }
353 l = &f->nextrxt;
354 }
355 }
356
357 a->ifc = ifc;
358 a->ifcid = ifc->ifcid;
359 bp = a->hold;
360 a->hold = nil;
361 if(version == V4)
362 ip += IPv4off;
363 a->utime = NOW;
364 a->ctime = a->utime;
365 QUNLOCK(arp);
366
367 while(bp){
368 next = bp->list;
369 if(ifc != nil){
370 if(waserror()){
371 RUNLOCK(ifc);
372 nexterror();
373 }
374 RLOCK(ifc);
375 if(ifc->m != nil)
376 ifc->m->bwrite(ifc, bp, version, ip);
377 else
378 freeb(bp);
379 RUNLOCK(ifc);
380 poperror();
381 } else
382 freeb(bp);
383 bp = next;
384 }
385 return;
386 }
387 }
388
389 if(refresh == 0){
390 a = newarp6(arp, ip, ifc, 0);
391 a->state = AOK;
392 a->type = type;
393 a->ctime = NOW;
394 memmove(a->mac, mac, type->maclen);
395 }
396
397 QUNLOCK(arp);
398 }
399
400 int
401 arpwrite(Fs *fs, char *s, int len)
402 {
403 int n;
404 Route *r;
405 Arp *arp;
406 Block *bp;
407 Arpent *a, *fl, **l;
408 Medium *m;
409 char *f[4], buf[256];
410 uchar ip[IPaddrlen], mac[MAClen];
411
412 arp = fs->arp;
413
414 if(len == 0)
415 error(Ebadarp);
416 if(len >= sizeof(buf))
417 len = sizeof(buf)-1;
418 strncpy(buf, s, len);
419 buf[len] = 0;
420 if(len > 0 && buf[len-1] == '\n')
421 buf[len-1] = 0;
422
423 n = getfields(buf, f, 4, 1, " ");
424 if(strcmp(f[0], "flush") == 0){
425 QLOCK(arp);
426 for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
427 memset(a->ip, 0, sizeof(a->ip));
428 memset(a->mac, 0, sizeof(a->mac));
429 a->hash = nil;
430 a->state = 0;
431 a->utime = 0;
432 while(a->hold != nil){
433 bp = a->hold->list;
434 freeblist(a->hold);
435 a->hold = bp;
436 }
437 }
438 memset(arp->hash, 0, sizeof(arp->hash));
439 /* clear all pkts on these lists (rxmt, dropf/l) */
440 arp->rxmt = nil;
441 arp->dropf = nil;
442 arp->dropl = nil;
443 QUNLOCK(arp);
444 } else if(strcmp(f[0], "add") == 0){
445 switch(n){
446 default:
447 error(Ebadarg);
448 case 3:
449 if (parseip(ip, f[1]) == -1)
450 error(Ebadip);
451 if(isv4(ip))
452 r = v4lookup(fs, ip+IPv4off, nil);
453 else
454 r = v6lookup(fs, ip, nil);
455 if(r == nil)
456 error("Destination unreachable");
457 m = r->ifc->m;
458 n = parsemac(mac, f[2], m->maclen);
459 break;
460 case 4:
461 m = ipfindmedium(f[1]);
462 if(m == nil)
463 error(Ebadarp);
464 if (parseip(ip, f[2]) == -1)
465 error(Ebadip);
466 n = parsemac(mac, f[3], m->maclen);
467 break;
468 }
469
470 if(m->ares == nil)
471 error(Ebadarp);
472
473 m->ares(fs, V6, ip, mac, n, 0);
474 } else if(strcmp(f[0], "del") == 0){
475 if(n != 2)
476 error(Ebadarg);
477
478 if (parseip(ip, f[1]) == -1)
479 error(Ebadip);
480 QLOCK(arp);
481
482 l = &arp->hash[haship(ip)];
483 for(a = *l; a; a = a->hash){
484 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0){
485 *l = a->hash;
486 break;
487 }
488 l = &a->hash;
489 }
490
491 if(a){
492 /* take out of re-transmit chain */
493 l = &arp->rxmt;
494 for(fl = *l; fl; fl = fl->nextrxt){
495 if(fl == a){
496 *l = a->nextrxt;
497 break;
498 }
499 l = &fl->nextrxt;
500 }
501
502 a->nextrxt = nil;
503 a->hash = nil;
504 a->hold = nil;
505 a->last = nil;
506 a->ifc = nil;
507 memset(a->ip, 0, sizeof(a->ip));
508 memset(a->mac, 0, sizeof(a->mac));
509 }
510 QUNLOCK(arp);
511 } else
512 error(Ebadarp);
513
514 return len;
515 }
516
517 enum
518 {
519 Alinelen= 90,
520 };
521
522 char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
523
524 static void
525 convmac(char *p, uchar *mac, int n)
526 {
527 while(n-- > 0)
528 p += sprint(p, "%2.2ux", *mac++);
529 }
530
531 int
532 arpread(Arp *arp, char *p, ulong offset, int len)
533 {
534 Arpent *a;
535 int n;
536 char mac[2*MAClen+1];
537
538 if(offset % Alinelen)
539 return 0;
540
541 offset = offset/Alinelen;
542 len = len/Alinelen;
543
544 n = 0;
545 for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
546 if(a->state == 0)
547 continue;
548 if(offset > 0){
549 offset--;
550 continue;
551 }
552 len--;
553 QLOCK(arp);
554 convmac(mac, a->mac, a->type->maclen);
555 n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac);
556 QUNLOCK(arp);
557 }
558
559 return n;
560 }
561
562 extern int
563 rxmitsols(Arp *arp)
564 {
565 uint sflag;
566 Block *next, *xp;
567 Arpent *a, *b, **l;
568 Fs *f;
569 uchar ipsrc[IPaddrlen];
570 Ipifc *ifc = nil;
571 long nrxt;
572
573 QLOCK(arp);
574 f = arp->f;
575
576 a = arp->rxmt;
577 if(a==nil){
578 nrxt = 0;
579 goto dodrops; /* return nrxt; */
580 }
581 nrxt = a->rtime - NOW;
582 if(nrxt > 3*ReTransTimer/4)
583 goto dodrops; /* return nrxt; */
584
585 for(; a; a = a->nextrxt){
586 ifc = a->ifc;
587 assert(ifc != nil);
588 if((a->rxtsrem <= 0) || !(CANRLOCK(ifc)) || (a->ifcid != ifc->ifcid)){
589 xp = a->hold;
590 a->hold = nil;
591
592 if(xp){
593 if(arp->dropl == nil)
594 arp->dropf = xp;
595 else
596 arp->dropl->list = xp;
597 }
598
599 cleanarpent(arp, a);
600 }
601 else
602 break;
603 }
604 if(a == nil)
605 goto dodrops;
606
607
608 QUNLOCK(arp); /* for icmpns */
609 if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC)
610 icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
611
612 RUNLOCK(ifc);
613 QLOCK(arp);
614
615 /* put to the end of re-transmit chain */
616 l = &arp->rxmt;
617 for(b = *l; b; b = b->nextrxt){
618 if(b == a){
619 *l = a->nextrxt;
620 break;
621 }
622 l = &b->nextrxt;
623 }
624 for(b = *l; b; b = b->nextrxt){
625 l = &b->nextrxt;
626 }
627 *l = a;
628 a->rxtsrem--;
629 a->nextrxt = nil;
630 a->rtime = NOW + ReTransTimer;
631
632 a = arp->rxmt;
633 if(a==nil)
634 nrxt = 0;
635 else
636 nrxt = a->rtime - NOW;
637
638 dodrops:
639 xp = arp->dropf;
640 arp->dropf = nil;
641 arp->dropl = nil;
642 QUNLOCK(arp);
643
644 for(; xp; xp = next){
645 next = xp->list;
646 icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1);
647 }
648
649 return nrxt;
650
651 }
652
653 static int
654 rxready(void *v)
655 {
656 Arp *arp = (Arp *) v;
657 int x;
658
659 x = ((arp->rxmt != nil) || (arp->dropf != nil));
660
661 return x;
662 }
663
664 static void
665 rxmitproc(void *v)
666 {
667 Arp *arp = v;
668 long wakeupat;
669
670 arp->rxmitp = up;
671 //print("arp rxmitproc started\n");
672 if(waserror()){
673 arp->rxmitp = 0;
674 pexit("hangup", 1);
675 }
676 for(;;){
677 wakeupat = rxmitsols(arp);
678 if(wakeupat == 0)
679 sleep(&arp->rxmtq, rxready, v);
680 else if(wakeupat > ReTransTimer/4)
681 tsleep(&arp->rxmtq, return0, 0, wakeupat);
682 }
683 }
684