FreeBSD/Linux Kernel Cross Reference
sys/ip/arp.c
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
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*
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 Medium *m = ifc->m;
74 int empty;
75
76 /* find oldest entry */
77 e = &arp->cache[NCACHE];
78 a = arp->cache;
79 t = a->utime;
80 for(f = a; f < e; f++){
81 if(f->utime < t){
82 t = f->utime;
83 a = f;
84 }
85 }
86
87 /* dump waiting packets */
88 xp = a->hold;
89 a->hold = nil;
90
91 if(isv4(a->ip)){
92 while(xp){
93 next = xp->list;
94 freeblist(xp);
95 xp = next;
96 }
97 }
98 else { /* queue icmp unreachable for rxmitproc later on, w/o arp lock */
99 if(xp){
100 if(arp->dropl == nil)
101 arp->dropf = xp;
102 else
103 arp->dropl->list = xp;
104
105 for(next = xp->list; next; next = next->list)
106 xp = next;
107 arp->dropl = xp;
108 wakeup(&arp->rxmtq);
109 }
110 }
111
112 /* take out of current chain */
113 l = &arp->hash[haship(a->ip)];
114 for(f = *l; f; f = f->hash){
115 if(f == a){
116 *l = a->hash;
117 break;
118 }
119 l = &f->hash;
120 }
121
122 /* insert into new chain */
123 l = &arp->hash[haship(ip)];
124 a->hash = *l;
125 *l = a;
126
127 memmove(a->ip, ip, sizeof(a->ip));
128 a->utime = NOW;
129 a->ctime = 0;
130 a->type = m;
131
132 a->rtime = NOW + ReTransTimer;
133 a->rxtsrem = MAX_MULTICAST_SOLICIT;
134 a->ifc = ifc;
135 a->ifcid = ifc->ifcid;
136
137 /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
138 if(!ipismulticast(a->ip) && addrxt){
139 l = &arp->rxmt;
140 empty = (*l==nil);
141
142 for(f = *l; f; f = f->nextrxt){
143 if(f == a){
144 *l = a->nextrxt;
145 break;
146 }
147 l = &f->nextrxt;
148 }
149 for(f = *l; f; f = f->nextrxt){
150 l = &f->nextrxt;
151 }
152 *l = a;
153 if(empty)
154 wakeup(&arp->rxmtq);
155 }
156
157 a->nextrxt = nil;
158
159 return a;
160 }
161
162 /* called with arp qlocked */
163
164 void
165 cleanarpent(Arp *arp, Arpent *a)
166 {
167 Arpent *f, **l;
168
169 a->utime = 0;
170 a->ctime = 0;
171 a->type = 0;
172 a->state = 0;
173
174 /* take out of current chain */
175 l = &arp->hash[haship(a->ip)];
176 for(f = *l; f; f = f->hash){
177 if(f == a){
178 *l = a->hash;
179 break;
180 }
181 l = &f->hash;
182 }
183
184 /* take out of re-transmit chain */
185 l = &arp->rxmt;
186 for(f = *l; f; f = f->nextrxt){
187 if(f == a){
188 *l = a->nextrxt;
189 break;
190 }
191 l = &f->nextrxt;
192 }
193 a->nextrxt = nil;
194 a->hash = nil;
195 a->hold = nil;
196 a->last = nil;
197 a->ifc = nil;
198 }
199
200 /*
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.
205 */
206 Arpent*
207 arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
208 {
209 int hash;
210 Arpent *a;
211 Medium *type = ifc->m;
212 uchar v6ip[IPaddrlen];
213
214 if(version == V4){
215 v4tov6(v6ip, ip);
216 ip = v6ip;
217 }
218
219 qlock(arp);
220 hash = haship(ip);
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
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*
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
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->m;
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->m != nil)
377 ifc->m->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
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 *m;
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 m = r->ifc->m;
459 n = parsemac(mac, f[2], m->maclen);
460 break;
461 case 4:
462 m = ipfindmedium(f[1]);
463 if(m == nil)
464 error(Ebadarp);
465 if (parseip(ip, f[2]) == -1)
466 error(Ebadip);
467 n = parsemac(mac, f[3], m->maclen);
468 break;
469 }
470
471 if(m->ares == nil)
472 error(Ebadarp);
473
474 m->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
526 convmac(char *p, uchar *mac, int n)
527 {
528 while(n-- > 0)
529 p += sprint(p, "%2.2ux", *mac++);
530 }
531
532 int
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, a->mac, a->type->maclen);
556 n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac);
557 qunlock(arp);
558 }
559
560 return n;
561 }
562
563 extern int
564 rxmitsols(Arp *arp)
565 {
566 uint sflag;
567 Block *next, *xp;
568 Arpent *a, *b, **l;
569 Fs *f;
570 uchar ipsrc[IPaddrlen];
571 Ipifc *ifc = nil;
572 long nrxt;
573
574 qlock(arp);
575 f = arp->f;
576
577 a = arp->rxmt;
578 if(a==nil){
579 nrxt = 0;
580 goto dodrops; /* return nrxt; */
581 }
582 nrxt = a->rtime - NOW;
583 if(nrxt > 3*ReTransTimer/4)
584 goto dodrops; /* return nrxt; */
585
586 for(; a; a = a->nextrxt){
587 ifc = a->ifc;
588 assert(ifc != nil);
589 if((a->rxtsrem <= 0) || !(canrlock(ifc)) || (a->ifcid != ifc->ifcid)){
590 xp = a->hold;
591 a->hold = nil;
592
593 if(xp){
594 if(arp->dropl == nil)
595 arp->dropf = xp;
596 else
597 arp->dropl->list = xp;
598 }
599
600 cleanarpent(arp, a);
601 }
602 else
603 break;
604 }
605 if(a == nil)
606 goto dodrops;
607
608
609 qunlock(arp); /* for icmpns */
610 if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC)
611 icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
612
613 runlock(ifc);
614 qlock(arp);
615
616 /* put to the end of re-transmit chain */
617 l = &arp->rxmt;
618 for(b = *l; b; b = b->nextrxt){
619 if(b == a){
620 *l = a->nextrxt;
621 break;
622 }
623 l = &b->nextrxt;
624 }
625 for(b = *l; b; b = b->nextrxt){
626 l = &b->nextrxt;
627 }
628 *l = a;
629 a->rxtsrem--;
630 a->nextrxt = nil;
631 a->rtime = NOW + ReTransTimer;
632
633 a = arp->rxmt;
634 if(a==nil)
635 nrxt = 0;
636 else
637 nrxt = a->rtime - NOW;
638
639 dodrops:
640 xp = arp->dropf;
641 arp->dropf = nil;
642 arp->dropl = nil;
643 qunlock(arp);
644
645 for(; xp; xp = next){
646 next = xp->list;
647 icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1);
648 }
649
650 return nrxt;
651
652 }
653
654 static int
655 rxready(void *v)
656 {
657 Arp *arp = (Arp *) v;
658 int x;
659
660 x = ((arp->rxmt != nil) || (arp->dropf != nil));
661
662 return x;
663 }
664
665 static void
666 rxmitproc(void *v)
667 {
668 Arp *arp = v;
669 long wakeupat;
670
671 arp->rxmitp = up;
672 //print("arp rxmitproc started\n");
673 if(waserror()){
674 arp->rxmitp = 0;
675 pexit("hangup", 1);
676 }
677 for(;;){
678 wakeupat = rxmitsols(arp);
679 if(wakeupat == 0)
680 sleep(&arp->rxmtq, rxready, v);
681 else if(wakeupat > ReTransTimer/4)
682 tsleep(&arp->rxmtq, return0, 0, wakeupat);
683 }
684 }
685
Cache object: 3da79301596d5ecaae99208a963ce44e
|