Subversion Repositories planix.SVN

Rev

Details | 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
 
10
static void	walkadd(Fs*, Route**, Route*);
11
static void	addnode(Fs*, Route**, Route*);
12
static void	calcd(Route*);
13
 
14
/* these are used for all instances of IP */
15
static Route*	v4freelist;
16
static Route*	v6freelist;
17
static RWlock	routelock;
18
static ulong	v4routegeneration, v6routegeneration;
19
 
20
static void
21
freeroute(Route *r)
22
{
23
	Route **l;
24
 
25
	r->left = nil;
26
	r->right = nil;
27
	if(r->type & Rv4)
28
		l = &v4freelist;
29
	else
30
		l = &v6freelist;
31
	r->mid = *l;
32
	*l = r;
33
}
34
 
35
static Route*
36
allocroute(int type)
37
{
38
	Route *r;
39
	int n;
40
	Route **l;
41
 
42
	if(type & Rv4){
43
		n = sizeof(RouteTree) + sizeof(V4route);
44
		l = &v4freelist;
45
	} else {
46
		n = sizeof(RouteTree) + sizeof(V6route);
47
		l = &v6freelist;
48
	}
49
 
50
	r = *l;
51
	if(r != nil){
52
		*l = r->mid;
53
	} else {
54
		r = malloc(n);
55
		if(r == nil)
56
			panic("out of routing nodes");
57
	}
58
	memset(r, 0, n);
59
	r->type = type;
60
	r->ifc = nil;
61
	r->ref = 1;
62
 
63
	return r;
64
}
65
 
66
static void
67
addqueue(Route **q, Route *r)
68
{
69
	Route *l;
70
 
71
	if(r == nil)
72
		return;
73
 
74
	l = allocroute(r->type);
75
	l->mid = *q;
76
	*q = l;
77
	l->left = r;
78
}
79
 
80
/*
81
 *   compare 2 v6 addresses
82
 */
83
static int
84
lcmp(ulong *a, ulong *b)
85
{
86
	int i;
87
 
88
	for(i = 0; i < IPllen; i++){
89
		if(a[i] > b[i])
90
			return 1;
91
		if(a[i] < b[i])
92
			return -1;
93
	}
94
	return 0;
95
}
96
 
97
/*
98
 *  compare 2 v4 or v6 ranges
99
 */
100
enum
101
{
102
	Rpreceeds,
103
	Rfollows,
104
	Requals,
105
	Rcontains,
106
	Rcontained,
107
};
108
 
109
static int
110
rangecompare(Route *a, Route *b)
111
{
112
	if(a->type & Rv4){
113
		if(a->v4.endaddress < b->v4.address)
114
			return Rpreceeds;
115
 
116
		if(a->v4.address > b->v4.endaddress)
117
			return Rfollows;
118
 
119
		if(a->v4.address <= b->v4.address
120
		&& a->v4.endaddress >= b->v4.endaddress){
121
			if(a->v4.address == b->v4.address
122
			&& a->v4.endaddress == b->v4.endaddress)
123
				return Requals;
124
			return Rcontains;
125
		}
126
		return Rcontained;
127
	}
128
 
129
	if(lcmp(a->v6.endaddress, b->v6.address) < 0)
130
		return Rpreceeds;
131
 
132
	if(lcmp(a->v6.address, b->v6.endaddress) > 0)
133
		return Rfollows;
134
 
135
	if(lcmp(a->v6.address, b->v6.address) <= 0
136
	&& lcmp(a->v6.endaddress, b->v6.endaddress) >= 0){
137
		if(lcmp(a->v6.address, b->v6.address) == 0
138
		&& lcmp(a->v6.endaddress, b->v6.endaddress) == 0)
139
				return Requals;
140
		return Rcontains;
141
	}
142
 
143
	return Rcontained;
144
}
145
 
146
static void
147
copygate(Route *old, Route *new)
148
{
149
	if(new->type & Rv4)
150
		memmove(old->v4.gate, new->v4.gate, IPv4addrlen);
151
	else
152
		memmove(old->v6.gate, new->v6.gate, IPaddrlen);
153
}
154
 
155
/*
156
 *  walk down a tree adding nodes back in
157
 */
158
static void
159
walkadd(Fs *f, Route **root, Route *p)
160
{
161
	Route *l, *r;
162
 
163
	l = p->left;
164
	r = p->right;
165
	p->left = 0;
166
	p->right = 0;
167
	addnode(f, root, p);
168
	if(l)
169
		walkadd(f, root, l);
170
	if(r)
171
		walkadd(f, root, r);
172
}
173
 
174
/*
175
 *  calculate depth
176
 */
177
static void
178
calcd(Route *p)
179
{
180
	Route *q;
181
	int d;
182
 
183
	if(p) {
184
		d = 0;
185
		q = p->left;
186
		if(q)
187
			d = q->depth;
188
		q = p->right;
189
		if(q && q->depth > d)
190
			d = q->depth;
191
		q = p->mid;
192
		if(q && q->depth > d)
193
			d = q->depth;
194
		p->depth = d+1;
195
	}
196
}
197
 
198
/*
199
 *  balance the tree at the current node
200
 */
201
static void
202
balancetree(Route **cur)
203
{
204
	Route *p, *l, *r;
205
	int dl, dr;
206
 
207
	/*
208
	 * if left and right are
209
	 * too out of balance,
210
	 * rotate tree node
211
	 */
212
	p = *cur;
213
	dl = 0; if(l = p->left) dl = l->depth;
214
	dr = 0; if(r = p->right) dr = r->depth;
215
 
216
	if(dl > dr+1) {
217
		p->left = l->right;
218
		l->right = p;
219
		*cur = l;
220
		calcd(p);
221
		calcd(l);
222
	} else
223
	if(dr > dl+1) {
224
		p->right = r->left;
225
		r->left = p;
226
		*cur = r;
227
		calcd(p);
228
		calcd(r);
229
	} else
230
		calcd(p);
231
}
232
 
233
/*
234
 *  add a new node to the tree
235
 */
236
static void
237
addnode(Fs *f, Route **cur, Route *new)
238
{
239
	Route *p;
240
 
241
	p = *cur;
242
	if(p == 0) {
243
		*cur = new;
244
		new->depth = 1;
245
		return;
246
	}
247
 
248
	switch(rangecompare(new, p)){
249
	case Rpreceeds:
250
		addnode(f, &p->left, new);
251
		break;
252
	case Rfollows:
253
		addnode(f, &p->right, new);
254
		break;
255
	case Rcontains:
256
		/*
257
		 *  if new node is superset
258
		 *  of tree node,
259
		 *  replace tree node and
260
		 *  queue tree node to be
261
		 *  merged into root.
262
		 */
263
		*cur = new;
264
		new->depth = 1;
265
		addqueue(&f->queue, p);
266
		break;
267
	case Requals:
268
		/*
269
		 *  supercede the old entry if the old one isn't
270
		 *  a local interface.
271
		 */
272
		if((p->type & Rifc) == 0){
273
			p->type = new->type;
274
			p->ifcid = -1;
275
			copygate(p, new);
276
		} else if(new->type & Rifc)
277
			p->ref++;
278
		freeroute(new);
279
		break;
280
	case Rcontained:
281
		addnode(f, &p->mid, new);
282
		break;
283
	}
284
 
285
	balancetree(cur);
286
}
287
 
288
#define	V4H(a)	((a&0x07ffffff)>>(32-Lroot-5))
289
 
290
void
291
v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
292
{
293
	Route *p;
294
	ulong sa;
295
	ulong m;
296
	ulong ea;
297
	int h, eh;
298
 
299
	m = nhgetl(mask);
300
	sa = nhgetl(a) & m;
301
	ea = sa | ~m;
302
 
303
	eh = V4H(ea);
304
	for(h=V4H(sa); h<=eh; h++) {
305
		p = allocroute(Rv4 | type);
306
		p->v4.address = sa;
307
		p->v4.endaddress = ea;
308
		memmove(p->v4.gate, gate, sizeof(p->v4.gate));
309
		memmove(p->tag, tag, sizeof(p->tag));
310
 
311
		wlock(&routelock);
312
		addnode(f, &f->v4root[h], p);
313
		while(p = f->queue) {
314
			f->queue = p->mid;
315
			walkadd(f, &f->v4root[h], p->left);
316
			freeroute(p);
317
		}
318
		wunlock(&routelock);
319
	}
320
	v4routegeneration++;
321
 
322
	ipifcaddroute(f, Rv4, a, mask, gate, type);
323
}
324
 
325
#define	V6H(a)	(((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5))
326
#define ISDFLT(a, mask, tag) ((ipcmp((a),v6Unspecified)==0) && (ipcmp((mask),v6Unspecified)==0) && (strcmp((tag), "ra")!=0))
327
 
328
void
329
v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
330
{
331
	Route *p;
332
	ulong sa[IPllen], ea[IPllen];
333
	ulong x, y;
334
	int h, eh;
335
 
336
	/*
337
	if(ISDFLT(a, mask, tag))
338
		f->v6p->cdrouter = -1;
339
	*/
340
 
341
 
342
	for(h = 0; h < IPllen; h++){
343
		x = nhgetl(a+4*h);
344
		y = nhgetl(mask+4*h);
345
		sa[h] = x & y;
346
		ea[h] = x | ~y;
347
	}
348
 
349
	eh = V6H(ea);
350
	for(h = V6H(sa); h <= eh; h++) {
351
		p = allocroute(type);
352
		memmove(p->v6.address, sa, IPaddrlen);
353
		memmove(p->v6.endaddress, ea, IPaddrlen);
354
		memmove(p->v6.gate, gate, IPaddrlen);
355
		memmove(p->tag, tag, sizeof(p->tag));
356
 
357
		wlock(&routelock);
358
		addnode(f, &f->v6root[h], p);
359
		while(p = f->queue) {
360
			f->queue = p->mid;
361
			walkadd(f, &f->v6root[h], p->left);
362
			freeroute(p);
363
		}
364
		wunlock(&routelock);
365
	}
366
	v6routegeneration++;
367
 
368
	ipifcaddroute(f, 0, a, mask, gate, type);
369
}
370
 
371
Route**
372
looknode(Route **cur, Route *r)
373
{
374
	Route *p;
375
 
376
	for(;;){
377
		p = *cur;
378
		if(p == 0)
379
			return 0;
380
 
381
		switch(rangecompare(r, p)){
382
		case Rcontains:
383
			return 0;
384
		case Rpreceeds:
385
			cur = &p->left;
386
			break;
387
		case Rfollows:
388
			cur = &p->right;
389
			break;
390
		case Rcontained:
391
			cur = &p->mid;
392
			break;
393
		case Requals:
394
			return cur;
395
		}
396
	}
397
}
398
 
399
void
400
v4delroute(Fs *f, uchar *a, uchar *mask, int dolock)
401
{
402
	Route **r, *p;
403
	Route rt;
404
	int h, eh;
405
	ulong m;
406
 
407
	m = nhgetl(mask);
408
	rt.v4.address = nhgetl(a) & m;
409
	rt.v4.endaddress = rt.v4.address | ~m;
410
	rt.type = Rv4;
411
 
412
	eh = V4H(rt.v4.endaddress);
413
	for(h=V4H(rt.v4.address); h<=eh; h++) {
414
		if(dolock)
415
			wlock(&routelock);
416
		r = looknode(&f->v4root[h], &rt);
417
		if(r) {
418
			p = *r;
419
			if(--(p->ref) == 0){
420
				*r = 0;
421
				addqueue(&f->queue, p->left);
422
				addqueue(&f->queue, p->mid);
423
				addqueue(&f->queue, p->right);
424
				freeroute(p);
425
				while(p = f->queue) {
426
					f->queue = p->mid;
427
					walkadd(f, &f->v4root[h], p->left);
428
					freeroute(p);
429
				}
430
			}
431
		}
432
		if(dolock)
433
			wunlock(&routelock);
434
	}
435
	v4routegeneration++;
436
 
437
	ipifcremroute(f, Rv4, a, mask);
438
}
439
 
440
void
441
v6delroute(Fs *f, uchar *a, uchar *mask, int dolock)
442
{
443
	Route **r, *p;
444
	Route rt;
445
	int h, eh;
446
	ulong x, y;
447
 
448
	for(h = 0; h < IPllen; h++){
449
		x = nhgetl(a+4*h);
450
		y = nhgetl(mask+4*h);
451
		rt.v6.address[h] = x & y;
452
		rt.v6.endaddress[h] = x | ~y;
453
	}
454
	rt.type = 0;
455
 
456
	eh = V6H(rt.v6.endaddress);
457
	for(h=V6H(rt.v6.address); h<=eh; h++) {
458
		if(dolock)
459
			wlock(&routelock);
460
		r = looknode(&f->v6root[h], &rt);
461
		if(r) {
462
			p = *r;
463
			if(--(p->ref) == 0){
464
				*r = 0;
465
				addqueue(&f->queue, p->left);
466
				addqueue(&f->queue, p->mid);
467
				addqueue(&f->queue, p->right);
468
				freeroute(p);
469
				while(p = f->queue) {
470
					f->queue = p->mid;
471
					walkadd(f, &f->v6root[h], p->left);
472
					freeroute(p);
473
				}
474
			}
475
		}
476
		if(dolock)
477
			wunlock(&routelock);
478
	}
479
	v6routegeneration++;
480
 
481
	ipifcremroute(f, 0, a, mask);
482
}
483
 
484
Route*
485
v4lookup(Fs *f, uchar *a, Conv *c)
486
{
487
	Route *p, *q;
488
	ulong la;
489
	uchar gate[IPaddrlen];
490
	Ipifc *ifc;
491
 
492
	if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v4routegeneration)
493
		return c->r;
494
 
495
	la = nhgetl(a);
496
	q = nil;
497
	for(p=f->v4root[V4H(la)]; p;)
498
		if(la >= p->v4.address) {
499
			if(la <= p->v4.endaddress) {
500
				q = p;
501
				p = p->mid;
502
			} else
503
				p = p->right;
504
		} else
505
			p = p->left;
506
 
507
	if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
508
		if(q->type & Rifc) {
509
			hnputl(gate+IPv4off, q->v4.address);
510
			memmove(gate, v4prefix, IPv4off);
511
		} else
512
			v4tov6(gate, q->v4.gate);
513
		ifc = findipifc(f, gate, q->type);
514
		if(ifc == nil)
515
			return nil;
516
		q->ifc = ifc;
517
		q->ifcid = ifc->ifcid;
518
	}
519
 
520
	if(c != nil){
521
		c->r = q;
522
		c->rgen = v4routegeneration;
523
	}
524
 
525
	return q;
526
}
527
 
528
Route*
529
v6lookup(Fs *f, uchar *a, Conv *c)
530
{
531
	Route *p, *q;
532
	ulong la[IPllen];
533
	int h;
534
	ulong x, y;
535
	uchar gate[IPaddrlen];
536
	Ipifc *ifc;
537
 
538
	if(memcmp(a, v4prefix, IPv4off) == 0){
539
		q = v4lookup(f, a+IPv4off, c);
540
		if(q != nil)
541
			return q;
542
	}
543
 
544
	if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v6routegeneration)
545
		return c->r;
546
 
547
	for(h = 0; h < IPllen; h++)
548
		la[h] = nhgetl(a+4*h);
549
 
550
	q = 0;
551
	for(p=f->v6root[V6H(la)]; p;){
552
		for(h = 0; h < IPllen; h++){
553
			x = la[h];
554
			y = p->v6.address[h];
555
			if(x == y)
556
				continue;
557
			if(x < y){
558
				p = p->left;
559
				goto next;
560
			}
561
			break;
562
		}
563
		for(h = 0; h < IPllen; h++){
564
			x = la[h];
565
			y = p->v6.endaddress[h];
566
			if(x == y)
567
				continue;
568
			if(x > y){
569
				p = p->right;
570
				goto next;
571
			}
572
			break;
573
		}
574
		q = p;
575
		p = p->mid;
576
next:		;
577
	}
578
 
579
	if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
580
		if(q->type & Rifc) {
581
			for(h = 0; h < IPllen; h++)
582
				hnputl(gate+4*h, q->v6.address[h]);
583
			ifc = findipifc(f, gate, q->type);
584
		} else
585
			ifc = findipifc(f, q->v6.gate, q->type);
586
		if(ifc == nil)
587
			return nil;
588
		q->ifc = ifc;
589
		q->ifcid = ifc->ifcid;
590
	}
591
	if(c != nil){
592
		c->r = q;
593
		c->rgen = v6routegeneration;
594
	}
595
 
596
	return q;
597
}
598
 
599
void
600
routetype(int type, char *p)
601
{
602
	memset(p, ' ', 4);
603
	p[4] = 0;
604
	if(type & Rv4)
605
		*p++ = '4';
606
	else
607
		*p++ = '6';
608
	if(type & Rifc)
609
		*p++ = 'i';
610
	if(type & Runi)
611
		*p++ = 'u';
612
	else if(type & Rbcast)
613
		*p++ = 'b';
614
	else if(type & Rmulti)
615
		*p++ = 'm';
616
	if(type & Rptpt)
617
		*p = 'p';
618
}
619
 
620
static char *rformat = "%-15I %-4M %-15I %4.4s %4.4s %3s\n";
621
 
622
void
623
convroute(Route *r, uchar *addr, uchar *mask, uchar *gate, char *t, int *nifc)
624
{
625
	int i;
626
 
627
	if(r->type & Rv4){
628
		memmove(addr, v4prefix, IPv4off);
629
		hnputl(addr+IPv4off, r->v4.address);
630
		memset(mask, 0xff, IPv4off);
631
		hnputl(mask+IPv4off, ~(r->v4.endaddress ^ r->v4.address));
632
		memmove(gate, v4prefix, IPv4off);
633
		memmove(gate+IPv4off, r->v4.gate, IPv4addrlen);
634
	} else {
635
		for(i = 0; i < IPllen; i++){
636
			hnputl(addr + 4*i, r->v6.address[i]);
637
			hnputl(mask + 4*i, ~(r->v6.endaddress[i] ^ r->v6.address[i]));
638
		}
639
		memmove(gate, r->v6.gate, IPaddrlen);
640
	}
641
 
642
	routetype(r->type, t);
643
 
644
	if(r->ifc)
645
		*nifc = r->ifc->conv->x;
646
	else
647
		*nifc = -1;
648
}
649
 
650
/*
651
 *  this code is not in rr to reduce stack size
652
 */
653
static void
654
sprintroute(Route *r, Routewalk *rw)
655
{
656
	int nifc, n;
657
	char t[5], *iname, ifbuf[5];
658
	uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen];
659
	char *p;
660
 
661
	convroute(r, addr, mask, gate, t, &nifc);
662
	iname = "-";
663
	if(nifc != -1) {
664
		iname = ifbuf;
665
		snprint(ifbuf, sizeof ifbuf, "%d", nifc);
666
	}
667
	p = seprint(rw->p, rw->e, rformat, addr, mask, gate, t, r->tag, iname);
668
	if(rw->o < 0){
669
		n = p - rw->p;
670
		if(n > -rw->o){
671
			memmove(rw->p, rw->p-rw->o, n+rw->o);
672
			rw->p = p + rw->o;
673
		}
674
		rw->o += n;
675
	} else
676
		rw->p = p;
677
}
678
 
679
/*
680
 *  recurse descending tree, applying the function in Routewalk
681
 */
682
static int
683
rr(Route *r, Routewalk *rw)
684
{
685
	int h;
686
 
687
	if(rw->e <= rw->p)
688
		return 0;
689
	if(r == nil)
690
		return 1;
691
 
692
	if(rr(r->left, rw) == 0)
693
		return 0;
694
 
695
	if(r->type & Rv4)
696
		h = V4H(r->v4.address);
697
	else
698
		h = V6H(r->v6.address);
699
 
700
	if(h == rw->h)
701
		rw->walk(r, rw);
702
 
703
	if(rr(r->mid, rw) == 0)
704
		return 0;
705
 
706
	return rr(r->right, rw);
707
}
708
 
709
void
710
ipwalkroutes(Fs *f, Routewalk *rw)
711
{
712
	rlock(&routelock);
713
	if(rw->e > rw->p) {
714
		for(rw->h = 0; rw->h < nelem(f->v4root); rw->h++)
715
			if(rr(f->v4root[rw->h], rw) == 0)
716
				break;
717
	}
718
	if(rw->e > rw->p) {
719
		for(rw->h = 0; rw->h < nelem(f->v6root); rw->h++)
720
			if(rr(f->v6root[rw->h], rw) == 0)
721
				break;
722
	}
723
	runlock(&routelock);
724
}
725
 
726
long
727
routeread(Fs *f, char *p, ulong offset, int n)
728
{
729
	Routewalk rw;
730
 
731
	rw.p = p;
732
	rw.e = p+n;
733
	rw.o = -offset;
734
	rw.walk = sprintroute;
735
 
736
	ipwalkroutes(f, &rw);
737
 
738
	return rw.p - p;
739
}
740
 
741
/*
742
 *  this code is not in routeflush to reduce stack size
743
 */
744
void
745
delroute(Fs *f, Route *r, int dolock)
746
{
747
	uchar addr[IPaddrlen];
748
	uchar mask[IPaddrlen];
749
	uchar gate[IPaddrlen];
750
	char t[5];
751
	int nifc;
752
 
753
	convroute(r, addr, mask, gate, t, &nifc);
754
	if(r->type & Rv4)
755
		v4delroute(f, addr+IPv4off, mask+IPv4off, dolock);
756
	else
757
		v6delroute(f, addr, mask, dolock);
758
}
759
 
760
/*
761
 *  recurse until one route is deleted
762
 *    returns 0 if nothing is deleted, 1 otherwise
763
 */
764
int
765
routeflush(Fs *f, Route *r, char *tag)
766
{
767
	if(r == nil)
768
		return 0;
769
	if(routeflush(f, r->mid, tag))
770
		return 1;
771
	if(routeflush(f, r->left, tag))
772
		return 1;
773
	if(routeflush(f, r->right, tag))
774
		return 1;
775
	if((r->type & Rifc) == 0){
776
		if(tag == nil || strncmp(tag, r->tag, sizeof(r->tag)) == 0){
777
			delroute(f, r, 0);
778
			return 1;
779
		}
780
	}
781
	return 0;
782
}
783
 
784
Route *
785
iproute(Fs *fs, uchar *ip)
786
{
787
	if(isv4(ip))
788
		return v4lookup(fs, ip+IPv4off, nil);
789
	else
790
		return v6lookup(fs, ip, nil);
791
}
792
 
793
static void
794
printroute(Route *r)
795
{
796
	int nifc;
797
	char t[5], *iname, ifbuf[5];
798
	uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen];
799
 
800
	convroute(r, addr, mask, gate, t, &nifc);
801
	iname = "-";
802
	if(nifc != -1) {
803
		iname = ifbuf;
804
		snprint(ifbuf, sizeof ifbuf, "%d", nifc);
805
	}
806
	print(rformat, addr, mask, gate, t, r->tag, iname);
807
}
808
 
809
long
810
routewrite(Fs *f, Chan *c, char *p, int n)
811
{
812
	int h, changed;
813
	char *tag;
814
	Cmdbuf *cb;
815
	uchar addr[IPaddrlen];
816
	uchar mask[IPaddrlen];
817
	uchar gate[IPaddrlen];
818
	IPaux *a, *na;
819
	Route *q;
820
 
821
	cb = parsecmd(p, n);
822
	if(waserror()){
823
		free(cb);
824
		nexterror();
825
	}
826
 
827
	if(strcmp(cb->f[0], "flush") == 0){
828
		tag = cb->f[1];
829
		for(h = 0; h < nelem(f->v4root); h++)
830
			for(changed = 1; changed;){
831
				wlock(&routelock);
832
				changed = routeflush(f, f->v4root[h], tag);
833
				wunlock(&routelock);
834
			}
835
		for(h = 0; h < nelem(f->v6root); h++)
836
			for(changed = 1; changed;){
837
				wlock(&routelock);
838
				changed = routeflush(f, f->v6root[h], tag);
839
				wunlock(&routelock);
840
			}
841
	} else if(strcmp(cb->f[0], "remove") == 0){
842
		if(cb->nf < 3)
843
			error(Ebadarg);
844
		if (parseip(addr, cb->f[1]) == -1)
845
			error(Ebadip);
846
		parseipmask(mask, cb->f[2]);
847
		if(memcmp(addr, v4prefix, IPv4off) == 0)
848
			v4delroute(f, addr+IPv4off, mask+IPv4off, 1);
849
		else
850
			v6delroute(f, addr, mask, 1);
851
	} else if(strcmp(cb->f[0], "add") == 0){
852
		if(cb->nf < 4)
853
			error(Ebadarg);
854
		if(parseip(addr, cb->f[1]) == -1 ||
855
		    parseip(gate, cb->f[3]) == -1)
856
			error(Ebadip);
857
		parseipmask(mask, cb->f[2]);
858
		tag = "none";
859
		if(c != nil){
860
			a = c->aux;
861
			tag = a->tag;
862
		}
863
		if(memcmp(addr, v4prefix, IPv4off) == 0)
864
			v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0);
865
		else
866
			v6addroute(f, tag, addr, mask, gate, 0);
867
	} else if(strcmp(cb->f[0], "tag") == 0) {
868
		if(cb->nf < 2)
869
			error(Ebadarg);
870
 
871
		a = c->aux;
872
		na = newipaux(a->owner, cb->f[1]);
873
		c->aux = na;
874
		free(a);
875
	} else if(strcmp(cb->f[0], "route") == 0) {
876
		if(cb->nf < 2)
877
			error(Ebadarg);
878
		if (parseip(addr, cb->f[1]) == -1)
879
			error(Ebadip);
880
 
881
		q = iproute(f, addr);
882
		print("%I: ", addr);
883
		if(q == nil)
884
			print("no route\n");
885
		else
886
			printroute(q);
887
	}
888
 
889
	poperror();
890
	free(cb);
891
	return n;
892
}