Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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, char *ep, uchar *mac, int n)
527
{
528
	while(n-- > 0)
529
		p = seprint(p, ep, "%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, &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
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
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
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