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