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
freeroute(Route * r)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*
allocroute(int type)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
addqueue(Route ** q,Route * r)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
lcmp(ulong * a,ulong * b)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
rangecompare(Route * a,Route * b)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
copygate(Route * old,Route * new)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
walkadd(Fs * f,Route ** root,Route * p)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
calcd(Route * p)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
balancetree(Route ** cur)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
addnode(Fs * f,Route ** cur,Route * new)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
v4addroute(Fs * f,char * tag,uchar * a,uchar * mask,uchar * gate,int type)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
v6addroute(Fs * f,char * tag,uchar * a,uchar * mask,uchar * gate,int type)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**
looknode(Route ** cur,Route * r)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 static void
del1route(Fs * f,Route ** root,Route * rtp,int h,int dolock)400 del1route(Fs *f, Route **root, Route *rtp, int h, int dolock)
401 {
402 Route **r, *p;
403
404 if(dolock)
405 wlock(&routelock);
406 r = looknode(&root[h], rtp);
407 if(r) {
408 p = *r;
409 if(--(p->ref) == 0){
410 *r = 0;
411 addqueue(&f->queue, p->left);
412 addqueue(&f->queue, p->mid);
413 addqueue(&f->queue, p->right);
414 freeroute(p);
415 while(p = f->queue) {
416 f->queue = p->mid;
417 walkadd(f, &root[h], p->left);
418 freeroute(p);
419 }
420 }
421 }
422 if(dolock)
423 wunlock(&routelock);
424 }
425
426 void
v4delroute(Fs * f,uchar * a,uchar * mask,int dolock)427 v4delroute(Fs *f, uchar *a, uchar *mask, int dolock)
428 {
429 Route rt;
430 int h, eh;
431 ulong m;
432
433 m = nhgetl(mask);
434 rt.v4.address = nhgetl(a) & m;
435 rt.v4.endaddress = rt.v4.address | ~m;
436 rt.type = Rv4;
437
438 eh = V4H(rt.v4.endaddress);
439 for(h=V4H(rt.v4.address); h<=eh; h++)
440 del1route(f, f->v4root, &rt, h, dolock);
441 v4routegeneration++;
442
443 ipifcremroute(f, Rv4, a, mask);
444 }
445
446 void
v6delroute(Fs * f,uchar * a,uchar * mask,int dolock)447 v6delroute(Fs *f, uchar *a, uchar *mask, int dolock)
448 {
449 Route rt;
450 int h, eh;
451 ulong x, y;
452
453 for(h = 0; h < IPllen; h++){
454 x = nhgetl(a+4*h);
455 y = nhgetl(mask+4*h);
456 rt.v6.address[h] = x & y;
457 rt.v6.endaddress[h] = x | ~y;
458 }
459 rt.type = 0;
460
461 eh = V6H(rt.v6.endaddress);
462 for(h=V6H(rt.v6.address); h<=eh; h++)
463 del1route(f, f->v6root, &rt, h, dolock);
464 v6routegeneration++;
465
466 ipifcremroute(f, 0, a, mask);
467 }
468
469 Route*
v4lookup(Fs * f,uchar * a,Conv * c)470 v4lookup(Fs *f, uchar *a, Conv *c)
471 {
472 Route *p, *q;
473 ulong la;
474 uchar gate[IPaddrlen];
475 Ipifc *ifc;
476
477 if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v4routegeneration)
478 return c->r;
479
480 la = nhgetl(a);
481 again:
482 q = nil;
483 for(p=f->v4root[V4H(la)]; p;)
484 if(la >= p->v4.address) {
485 if(la <= p->v4.endaddress) {
486 q = p;
487 p = p->mid;
488 } else
489 p = p->right;
490 } else
491 p = p->left;
492
493 if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
494 if(q->type & Rifc) {
495 hnputl(gate+IPv4off, q->v4.address);
496 memmove(gate, v4prefix, IPv4off);
497 } else
498 v4tov6(gate, q->v4.gate);
499 ifc = findipifc(f, gate, q->type);
500 if(ifc == nil){
501 /* find a direct attached route */
502 if(q->v4.address == 0 && q->v4.endaddress == ~0){
503 la = nhgetl(q->v4.gate);
504 goto again;
505 }
506 return nil;
507 }
508 q->ifc = ifc;
509 q->ifcid = ifc->ifcid;
510 }
511
512 if(c != nil){
513 c->r = q;
514 c->rgen = v4routegeneration;
515 }
516
517 return q;
518 }
519
520 Route*
v6lookup(Fs * f,uchar * a,Conv * c)521 v6lookup(Fs *f, uchar *a, Conv *c)
522 {
523 Route *p, *q;
524 ulong la[IPllen];
525 int h;
526 ulong x, y;
527 uchar gate[IPaddrlen];
528 Ipifc *ifc;
529
530 if(memcmp(a, v4prefix, IPv4off) == 0){
531 q = v4lookup(f, a+IPv4off, c);
532 if(q != nil)
533 return q;
534 }
535
536 if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v6routegeneration)
537 return c->r;
538
539 for(h = 0; h < IPllen; h++)
540 la[h] = nhgetl(a+4*h);
541
542 q = 0;
543 for(p=f->v6root[V6H(la)]; p;){
544 for(h = 0; h < IPllen; h++){
545 x = la[h];
546 y = p->v6.address[h];
547 if(x == y)
548 continue;
549 if(x < y){
550 p = p->left;
551 goto next;
552 }
553 break;
554 }
555 for(h = 0; h < IPllen; h++){
556 x = la[h];
557 y = p->v6.endaddress[h];
558 if(x == y)
559 continue;
560 if(x > y){
561 p = p->right;
562 goto next;
563 }
564 break;
565 }
566 q = p;
567 p = p->mid;
568 next: ;
569 }
570
571 if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
572 if(q->type & Rifc) {
573 for(h = 0; h < IPllen; h++)
574 hnputl(gate+4*h, q->v6.address[h]);
575 ifc = findipifc(f, gate, q->type);
576 } else
577 ifc = findipifc(f, q->v6.gate, q->type);
578 if(ifc == nil)
579 return nil;
580 q->ifc = ifc;
581 q->ifcid = ifc->ifcid;
582 }
583 if(c != nil){
584 c->r = q;
585 c->rgen = v6routegeneration;
586 }
587
588 return q;
589 }
590
591 void
routetype(int type,char * p)592 routetype(int type, char *p)
593 {
594 memset(p, ' ', 4);
595 p[4] = 0;
596 if(type & Rv4)
597 *p++ = '4';
598 else
599 *p++ = '6';
600 if(type & Rifc)
601 *p++ = 'i';
602 if(type & Runi)
603 *p++ = 'u';
604 else if(type & Rbcast)
605 *p++ = 'b';
606 else if(type & Rmulti)
607 *p++ = 'm';
608 if(type & Rptpt)
609 *p = 'p';
610 }
611
612 static char *rformat = "%-15I %-4M %-15I %4.4s %4.4s %3s\n";
613
614 void
convroute(Route * r,uchar * addr,uchar * mask,uchar * gate,char * t,int * nifc)615 convroute(Route *r, uchar *addr, uchar *mask, uchar *gate, char *t, int *nifc)
616 {
617 int i;
618
619 if(r->type & Rv4){
620 memmove(addr, v4prefix, IPv4off);
621 hnputl(addr+IPv4off, r->v4.address);
622 memset(mask, 0xff, IPv4off);
623 hnputl(mask+IPv4off, ~(r->v4.endaddress ^ r->v4.address));
624 memmove(gate, v4prefix, IPv4off);
625 memmove(gate+IPv4off, r->v4.gate, IPv4addrlen);
626 } else {
627 for(i = 0; i < IPllen; i++){
628 hnputl(addr + 4*i, r->v6.address[i]);
629 hnputl(mask + 4*i, ~(r->v6.endaddress[i] ^ r->v6.address[i]));
630 }
631 memmove(gate, r->v6.gate, IPaddrlen);
632 }
633
634 routetype(r->type, t);
635
636 if(r->ifc)
637 *nifc = r->ifc->conv->x;
638 else
639 *nifc = -1;
640 }
641
642 /*
643 * this code is not in rr to reduce stack size
644 */
645 static void
sprintroute(Route * r,Routewalk * rw)646 sprintroute(Route *r, Routewalk *rw)
647 {
648 int nifc, n;
649 char t[5], *iname, ifbuf[5];
650 uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen];
651 char *p;
652
653 convroute(r, addr, mask, gate, t, &nifc);
654 iname = "-";
655 if(nifc != -1) {
656 iname = ifbuf;
657 snprint(ifbuf, sizeof ifbuf, "%d", nifc);
658 }
659 p = seprint(rw->p, rw->e, rformat, addr, mask, gate, t, r->tag, iname);
660 if(rw->o < 0){
661 n = p - rw->p;
662 if(n > -rw->o){
663 memmove(rw->p, rw->p-rw->o, n+rw->o);
664 rw->p = p + rw->o;
665 }
666 rw->o += n;
667 } else
668 rw->p = p;
669 }
670
671 /*
672 * recurse descending tree, applying the function in Routewalk
673 */
674 static int
rr(Route * r,Routewalk * rw)675 rr(Route *r, Routewalk *rw)
676 {
677 int h;
678
679 if(rw->e <= rw->p)
680 return 0;
681 if(r == nil)
682 return 1;
683
684 if(rr(r->left, rw) == 0)
685 return 0;
686
687 if(r->type & Rv4)
688 h = V4H(r->v4.address);
689 else
690 h = V6H(r->v6.address);
691
692 if(h == rw->h)
693 rw->walk(r, rw);
694
695 if(rr(r->mid, rw) == 0)
696 return 0;
697
698 return rr(r->right, rw);
699 }
700
701 void
ipwalkroutes(Fs * f,Routewalk * rw)702 ipwalkroutes(Fs *f, Routewalk *rw)
703 {
704 rlock(&routelock);
705 if(rw->e > rw->p) {
706 for(rw->h = 0; rw->h < nelem(f->v4root); rw->h++)
707 if(rr(f->v4root[rw->h], rw) == 0)
708 break;
709 }
710 if(rw->e > rw->p) {
711 for(rw->h = 0; rw->h < nelem(f->v6root); rw->h++)
712 if(rr(f->v6root[rw->h], rw) == 0)
713 break;
714 }
715 runlock(&routelock);
716 }
717
718 long
routeread(Fs * f,char * p,ulong offset,int n)719 routeread(Fs *f, char *p, ulong offset, int n)
720 {
721 Routewalk rw;
722
723 rw.p = p;
724 rw.e = p+n;
725 rw.o = -offset;
726 rw.walk = sprintroute;
727
728 ipwalkroutes(f, &rw);
729
730 return rw.p - p;
731 }
732
733 /*
734 * this code is not in routeflush to reduce stack size
735 */
736 void
delroute(Fs * f,Route * r,int dolock)737 delroute(Fs *f, Route *r, int dolock)
738 {
739 uchar addr[IPaddrlen];
740 uchar mask[IPaddrlen];
741 uchar gate[IPaddrlen];
742 char t[5];
743 int nifc;
744
745 convroute(r, addr, mask, gate, t, &nifc);
746 if(r->type & Rv4)
747 v4delroute(f, addr+IPv4off, mask+IPv4off, dolock);
748 else
749 v6delroute(f, addr, mask, dolock);
750 }
751
752 /*
753 * recurse until one route is deleted
754 * returns 0 if nothing is deleted, 1 otherwise
755 */
756 int
routeflush(Fs * f,Route * r,char * tag)757 routeflush(Fs *f, Route *r, char *tag)
758 {
759 if(r == nil)
760 return 0;
761 if(routeflush(f, r->mid, tag))
762 return 1;
763 if(routeflush(f, r->left, tag))
764 return 1;
765 if(routeflush(f, r->right, tag))
766 return 1;
767 if((r->type & Rifc) == 0){
768 if(tag == nil || strncmp(tag, r->tag, sizeof(r->tag)) == 0){
769 delroute(f, r, 0);
770 return 1;
771 }
772 }
773 return 0;
774 }
775
776 Route *
iproute(Fs * fs,uchar * ip)777 iproute(Fs *fs, uchar *ip)
778 {
779 if(isv4(ip))
780 return v4lookup(fs, ip+IPv4off, nil);
781 else
782 return v6lookup(fs, ip, nil);
783 }
784
785 static void
printroute(Route * r)786 printroute(Route *r)
787 {
788 int nifc;
789 char t[5], *iname, ifbuf[5];
790 uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen];
791
792 convroute(r, addr, mask, gate, t, &nifc);
793 iname = "-";
794 if(nifc != -1) {
795 iname = ifbuf;
796 snprint(ifbuf, sizeof ifbuf, "%d", nifc);
797 }
798 print(rformat, addr, mask, gate, t, r->tag, iname);
799 }
800
801 long
routewrite(Fs * f,Chan * c,char * p,int n)802 routewrite(Fs *f, Chan *c, char *p, int n)
803 {
804 int h, changed;
805 char *tag;
806 Cmdbuf *cb;
807 uchar addr[IPaddrlen];
808 uchar mask[IPaddrlen];
809 uchar gate[IPaddrlen];
810 IPaux *a, *na;
811 Route *q;
812 uchar type;
813
814 cb = parsecmd(p, n);
815 if(waserror()){
816 free(cb);
817 nexterror();
818 }
819
820 if(strcmp(cb->f[0], "flush") == 0){
821 tag = cb->f[1];
822 for(h = 0; h < nelem(f->v4root); h++)
823 for(changed = 1; changed;){
824 wlock(&routelock);
825 changed = routeflush(f, f->v4root[h], tag);
826 wunlock(&routelock);
827 }
828 for(h = 0; h < nelem(f->v6root); h++)
829 for(changed = 1; changed;){
830 wlock(&routelock);
831 changed = routeflush(f, f->v6root[h], tag);
832 wunlock(&routelock);
833 }
834 } else if(strcmp(cb->f[0], "remove") == 0){
835 if(cb->nf < 3)
836 error(Ebadarg);
837 if (parseip(addr, cb->f[1]) == -1)
838 error(Ebadip);
839 parseipmask(mask, cb->f[2]);
840 if(memcmp(addr, v4prefix, IPv4off) == 0)
841 v4delroute(f, addr+IPv4off, mask+IPv4off, 1);
842 else
843 v6delroute(f, addr, mask, 1);
844 } else if(strcmp(cb->f[0], "add") == 0){
845 if(cb->nf < 4)
846 error(Ebadarg);
847 if(parseip(addr, cb->f[1]) == -1 ||
848 parseip(gate, cb->f[3]) == -1)
849 error(Ebadip);
850 parseipmask(mask, cb->f[2]);
851 tag = "none";
852 if(c != nil){
853 a = c->aux;
854 tag = a->tag;
855 }
856 if(memcmp(addr, v4prefix, IPv4off) == 0){
857 type = 0;
858 if(ipcmp(mask, IPallbits) == 0)
859 type = Rbcast;
860 v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, type);
861 }else
862 v6addroute(f, tag, addr, mask, gate, 0);
863 } else if(strcmp(cb->f[0], "tag") == 0) {
864 if(cb->nf < 2)
865 error(Ebadarg);
866
867 a = c->aux;
868 na = newipaux(a->owner, cb->f[1]);
869 c->aux = na;
870 free(a);
871 } else if(strcmp(cb->f[0], "route") == 0) {
872 if(cb->nf < 2)
873 error(Ebadarg);
874 if (parseip(addr, cb->f[1]) == -1)
875 error(Ebadip);
876
877 q = iproute(f, addr);
878 print("%I: ", addr);
879 if(q == nil)
880 print("no route\n");
881 else
882 printroute(q);
883 }
884
885 poperror();
886 free(cb);
887 return n;
888 }
889