17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "../port/error.h"
77dd7cddfSDavid du Colombier
87dd7cddfSDavid du Colombier #include "ip.h"
97dd7cddfSDavid du Colombier
107dd7cddfSDavid du Colombier static void walkadd(Fs*, Route**, Route*);
117dd7cddfSDavid du Colombier static void addnode(Fs*, Route**, Route*);
127dd7cddfSDavid du Colombier static void calcd(Route*);
137dd7cddfSDavid du Colombier
147dd7cddfSDavid du Colombier /* these are used for all instances of IP */
15ea58ad6fSDavid du Colombier static Route* v4freelist;
16ea58ad6fSDavid du Colombier static Route* v6freelist;
17ea58ad6fSDavid du Colombier static RWlock routelock;
18ea58ad6fSDavid du Colombier static ulong v4routegeneration, v6routegeneration;
197dd7cddfSDavid du Colombier
207dd7cddfSDavid du Colombier static void
freeroute(Route * r)217dd7cddfSDavid du Colombier freeroute(Route *r)
227dd7cddfSDavid du Colombier {
237dd7cddfSDavid du Colombier Route **l;
247dd7cddfSDavid du Colombier
257dd7cddfSDavid du Colombier r->left = nil;
267dd7cddfSDavid du Colombier r->right = nil;
277dd7cddfSDavid du Colombier if(r->type & Rv4)
287dd7cddfSDavid du Colombier l = &v4freelist;
297dd7cddfSDavid du Colombier else
307dd7cddfSDavid du Colombier l = &v6freelist;
317dd7cddfSDavid du Colombier r->mid = *l;
327dd7cddfSDavid du Colombier *l = r;
337dd7cddfSDavid du Colombier }
347dd7cddfSDavid du Colombier
357dd7cddfSDavid du Colombier static Route*
allocroute(int type)367dd7cddfSDavid du Colombier allocroute(int type)
377dd7cddfSDavid du Colombier {
387dd7cddfSDavid du Colombier Route *r;
397dd7cddfSDavid du Colombier int n;
407dd7cddfSDavid du Colombier Route **l;
417dd7cddfSDavid du Colombier
427dd7cddfSDavid du Colombier if(type & Rv4){
437dd7cddfSDavid du Colombier n = sizeof(RouteTree) + sizeof(V4route);
447dd7cddfSDavid du Colombier l = &v4freelist;
457dd7cddfSDavid du Colombier } else {
467dd7cddfSDavid du Colombier n = sizeof(RouteTree) + sizeof(V6route);
477dd7cddfSDavid du Colombier l = &v6freelist;
487dd7cddfSDavid du Colombier }
497dd7cddfSDavid du Colombier
507dd7cddfSDavid du Colombier r = *l;
517dd7cddfSDavid du Colombier if(r != nil){
527dd7cddfSDavid du Colombier *l = r->mid;
537dd7cddfSDavid du Colombier } else {
547dd7cddfSDavid du Colombier r = malloc(n);
557dd7cddfSDavid du Colombier if(r == nil)
567dd7cddfSDavid du Colombier panic("out of routing nodes");
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier memset(r, 0, n);
597dd7cddfSDavid du Colombier r->type = type;
607dd7cddfSDavid du Colombier r->ifc = nil;
619a747e4fSDavid du Colombier r->ref = 1;
627dd7cddfSDavid du Colombier
637dd7cddfSDavid du Colombier return r;
647dd7cddfSDavid du Colombier }
657dd7cddfSDavid du Colombier
667dd7cddfSDavid du Colombier static void
addqueue(Route ** q,Route * r)677dd7cddfSDavid du Colombier addqueue(Route **q, Route *r)
687dd7cddfSDavid du Colombier {
697dd7cddfSDavid du Colombier Route *l;
707dd7cddfSDavid du Colombier
717dd7cddfSDavid du Colombier if(r == nil)
727dd7cddfSDavid du Colombier return;
737dd7cddfSDavid du Colombier
747dd7cddfSDavid du Colombier l = allocroute(r->type);
757dd7cddfSDavid du Colombier l->mid = *q;
767dd7cddfSDavid du Colombier *q = l;
777dd7cddfSDavid du Colombier l->left = r;
787dd7cddfSDavid du Colombier }
797dd7cddfSDavid du Colombier
807dd7cddfSDavid du Colombier /*
817dd7cddfSDavid du Colombier * compare 2 v6 addresses
827dd7cddfSDavid du Colombier */
837dd7cddfSDavid du Colombier static int
lcmp(ulong * a,ulong * b)847dd7cddfSDavid du Colombier lcmp(ulong *a, ulong *b)
857dd7cddfSDavid du Colombier {
867dd7cddfSDavid du Colombier int i;
877dd7cddfSDavid du Colombier
887dd7cddfSDavid du Colombier for(i = 0; i < IPllen; i++){
897dd7cddfSDavid du Colombier if(a[i] > b[i])
907dd7cddfSDavid du Colombier return 1;
917dd7cddfSDavid du Colombier if(a[i] < b[i])
927dd7cddfSDavid du Colombier return -1;
937dd7cddfSDavid du Colombier }
947dd7cddfSDavid du Colombier return 0;
957dd7cddfSDavid du Colombier }
967dd7cddfSDavid du Colombier
977dd7cddfSDavid du Colombier /*
987dd7cddfSDavid du Colombier * compare 2 v4 or v6 ranges
997dd7cddfSDavid du Colombier */
1007dd7cddfSDavid du Colombier enum
1017dd7cddfSDavid du Colombier {
1027dd7cddfSDavid du Colombier Rpreceeds,
1037dd7cddfSDavid du Colombier Rfollows,
1047dd7cddfSDavid du Colombier Requals,
1057dd7cddfSDavid du Colombier Rcontains,
1067dd7cddfSDavid du Colombier Rcontained,
1077dd7cddfSDavid du Colombier };
1087dd7cddfSDavid du Colombier
1097dd7cddfSDavid du Colombier static int
rangecompare(Route * a,Route * b)1107dd7cddfSDavid du Colombier rangecompare(Route *a, Route *b)
1117dd7cddfSDavid du Colombier {
1127dd7cddfSDavid du Colombier if(a->type & Rv4){
1137dd7cddfSDavid du Colombier if(a->v4.endaddress < b->v4.address)
1147dd7cddfSDavid du Colombier return Rpreceeds;
1157dd7cddfSDavid du Colombier
1167dd7cddfSDavid du Colombier if(a->v4.address > b->v4.endaddress)
1177dd7cddfSDavid du Colombier return Rfollows;
1187dd7cddfSDavid du Colombier
1197dd7cddfSDavid du Colombier if(a->v4.address <= b->v4.address
1207dd7cddfSDavid du Colombier && a->v4.endaddress >= b->v4.endaddress){
1217dd7cddfSDavid du Colombier if(a->v4.address == b->v4.address
1227dd7cddfSDavid du Colombier && a->v4.endaddress == b->v4.endaddress)
1237dd7cddfSDavid du Colombier return Requals;
1247dd7cddfSDavid du Colombier return Rcontains;
1257dd7cddfSDavid du Colombier }
1267dd7cddfSDavid du Colombier return Rcontained;
1277dd7cddfSDavid du Colombier }
1287dd7cddfSDavid du Colombier
1297dd7cddfSDavid du Colombier if(lcmp(a->v6.endaddress, b->v6.address) < 0)
1307dd7cddfSDavid du Colombier return Rpreceeds;
1317dd7cddfSDavid du Colombier
1327dd7cddfSDavid du Colombier if(lcmp(a->v6.address, b->v6.endaddress) > 0)
1337dd7cddfSDavid du Colombier return Rfollows;
1347dd7cddfSDavid du Colombier
1357dd7cddfSDavid du Colombier if(lcmp(a->v6.address, b->v6.address) <= 0
1367dd7cddfSDavid du Colombier && lcmp(a->v6.endaddress, b->v6.endaddress) >= 0){
1377dd7cddfSDavid du Colombier if(lcmp(a->v6.address, b->v6.address) == 0
1387dd7cddfSDavid du Colombier && lcmp(a->v6.endaddress, b->v6.endaddress) == 0)
1397dd7cddfSDavid du Colombier return Requals;
1407dd7cddfSDavid du Colombier return Rcontains;
1417dd7cddfSDavid du Colombier }
1427dd7cddfSDavid du Colombier
1437dd7cddfSDavid du Colombier return Rcontained;
1447dd7cddfSDavid du Colombier }
1457dd7cddfSDavid du Colombier
1467dd7cddfSDavid du Colombier static void
copygate(Route * old,Route * new)1477dd7cddfSDavid du Colombier copygate(Route *old, Route *new)
1487dd7cddfSDavid du Colombier {
1497dd7cddfSDavid du Colombier if(new->type & Rv4)
1507dd7cddfSDavid du Colombier memmove(old->v4.gate, new->v4.gate, IPv4addrlen);
1517dd7cddfSDavid du Colombier else
1527dd7cddfSDavid du Colombier memmove(old->v6.gate, new->v6.gate, IPaddrlen);
1537dd7cddfSDavid du Colombier }
1547dd7cddfSDavid du Colombier
1557dd7cddfSDavid du Colombier /*
1567dd7cddfSDavid du Colombier * walk down a tree adding nodes back in
1577dd7cddfSDavid du Colombier */
1587dd7cddfSDavid du Colombier static void
walkadd(Fs * f,Route ** root,Route * p)1597dd7cddfSDavid du Colombier walkadd(Fs *f, Route **root, Route *p)
1607dd7cddfSDavid du Colombier {
1617dd7cddfSDavid du Colombier Route *l, *r;
1627dd7cddfSDavid du Colombier
1637dd7cddfSDavid du Colombier l = p->left;
1647dd7cddfSDavid du Colombier r = p->right;
1657dd7cddfSDavid du Colombier p->left = 0;
1667dd7cddfSDavid du Colombier p->right = 0;
1677dd7cddfSDavid du Colombier addnode(f, root, p);
1687dd7cddfSDavid du Colombier if(l)
1697dd7cddfSDavid du Colombier walkadd(f, root, l);
1707dd7cddfSDavid du Colombier if(r)
1717dd7cddfSDavid du Colombier walkadd(f, root, r);
1727dd7cddfSDavid du Colombier }
1737dd7cddfSDavid du Colombier
1747dd7cddfSDavid du Colombier /*
1757dd7cddfSDavid du Colombier * calculate depth
1767dd7cddfSDavid du Colombier */
1777dd7cddfSDavid du Colombier static void
calcd(Route * p)1787dd7cddfSDavid du Colombier calcd(Route *p)
1797dd7cddfSDavid du Colombier {
1807dd7cddfSDavid du Colombier Route *q;
1817dd7cddfSDavid du Colombier int d;
1827dd7cddfSDavid du Colombier
1837dd7cddfSDavid du Colombier if(p) {
1847dd7cddfSDavid du Colombier d = 0;
1857dd7cddfSDavid du Colombier q = p->left;
1867dd7cddfSDavid du Colombier if(q)
1877dd7cddfSDavid du Colombier d = q->depth;
1887dd7cddfSDavid du Colombier q = p->right;
1897dd7cddfSDavid du Colombier if(q && q->depth > d)
1907dd7cddfSDavid du Colombier d = q->depth;
1917dd7cddfSDavid du Colombier q = p->mid;
1927dd7cddfSDavid du Colombier if(q && q->depth > d)
1937dd7cddfSDavid du Colombier d = q->depth;
1947dd7cddfSDavid du Colombier p->depth = d+1;
1957dd7cddfSDavid du Colombier }
1967dd7cddfSDavid du Colombier }
1977dd7cddfSDavid du Colombier
1987dd7cddfSDavid du Colombier /*
1997dd7cddfSDavid du Colombier * balance the tree at the current node
2007dd7cddfSDavid du Colombier */
2017dd7cddfSDavid du Colombier static void
balancetree(Route ** cur)2027dd7cddfSDavid du Colombier balancetree(Route **cur)
2037dd7cddfSDavid du Colombier {
2047dd7cddfSDavid du Colombier Route *p, *l, *r;
2057dd7cddfSDavid du Colombier int dl, dr;
2067dd7cddfSDavid du Colombier
2077dd7cddfSDavid du Colombier /*
2087dd7cddfSDavid du Colombier * if left and right are
2097dd7cddfSDavid du Colombier * too out of balance,
2107dd7cddfSDavid du Colombier * rotate tree node
2117dd7cddfSDavid du Colombier */
2127dd7cddfSDavid du Colombier p = *cur;
2137dd7cddfSDavid du Colombier dl = 0; if(l = p->left) dl = l->depth;
2147dd7cddfSDavid du Colombier dr = 0; if(r = p->right) dr = r->depth;
2157dd7cddfSDavid du Colombier
2167dd7cddfSDavid du Colombier if(dl > dr+1) {
2177dd7cddfSDavid du Colombier p->left = l->right;
2187dd7cddfSDavid du Colombier l->right = p;
2197dd7cddfSDavid du Colombier *cur = l;
2207dd7cddfSDavid du Colombier calcd(p);
2217dd7cddfSDavid du Colombier calcd(l);
2227dd7cddfSDavid du Colombier } else
2237dd7cddfSDavid du Colombier if(dr > dl+1) {
2247dd7cddfSDavid du Colombier p->right = r->left;
2257dd7cddfSDavid du Colombier r->left = p;
2267dd7cddfSDavid du Colombier *cur = r;
2277dd7cddfSDavid du Colombier calcd(p);
2287dd7cddfSDavid du Colombier calcd(r);
2297dd7cddfSDavid du Colombier } else
2307dd7cddfSDavid du Colombier calcd(p);
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier
2337dd7cddfSDavid du Colombier /*
2347dd7cddfSDavid du Colombier * add a new node to the tree
2357dd7cddfSDavid du Colombier */
2367dd7cddfSDavid du Colombier static void
addnode(Fs * f,Route ** cur,Route * new)2377dd7cddfSDavid du Colombier addnode(Fs *f, Route **cur, Route *new)
2387dd7cddfSDavid du Colombier {
2397dd7cddfSDavid du Colombier Route *p;
2407dd7cddfSDavid du Colombier
2417dd7cddfSDavid du Colombier p = *cur;
2427dd7cddfSDavid du Colombier if(p == 0) {
2437dd7cddfSDavid du Colombier *cur = new;
2447dd7cddfSDavid du Colombier new->depth = 1;
2457dd7cddfSDavid du Colombier return;
2467dd7cddfSDavid du Colombier }
2477dd7cddfSDavid du Colombier
2487dd7cddfSDavid du Colombier switch(rangecompare(new, p)){
2497dd7cddfSDavid du Colombier case Rpreceeds:
2507dd7cddfSDavid du Colombier addnode(f, &p->left, new);
2517dd7cddfSDavid du Colombier break;
2527dd7cddfSDavid du Colombier case Rfollows:
2537dd7cddfSDavid du Colombier addnode(f, &p->right, new);
2547dd7cddfSDavid du Colombier break;
2557dd7cddfSDavid du Colombier case Rcontains:
2567dd7cddfSDavid du Colombier /*
2577dd7cddfSDavid du Colombier * if new node is superset
2587dd7cddfSDavid du Colombier * of tree node,
2597dd7cddfSDavid du Colombier * replace tree node and
2607dd7cddfSDavid du Colombier * queue tree node to be
2617dd7cddfSDavid du Colombier * merged into root.
2627dd7cddfSDavid du Colombier */
2637dd7cddfSDavid du Colombier *cur = new;
2647dd7cddfSDavid du Colombier new->depth = 1;
2657dd7cddfSDavid du Colombier addqueue(&f->queue, p);
2667dd7cddfSDavid du Colombier break;
2677dd7cddfSDavid du Colombier case Requals:
2687dd7cddfSDavid du Colombier /*
2697dd7cddfSDavid du Colombier * supercede the old entry if the old one isn't
2707dd7cddfSDavid du Colombier * a local interface.
2717dd7cddfSDavid du Colombier */
2727dd7cddfSDavid du Colombier if((p->type & Rifc) == 0){
2737dd7cddfSDavid du Colombier p->type = new->type;
2747dd7cddfSDavid du Colombier p->ifcid = -1;
2757dd7cddfSDavid du Colombier copygate(p, new);
2769a747e4fSDavid du Colombier } else if(new->type & Rifc)
2779a747e4fSDavid du Colombier p->ref++;
2787dd7cddfSDavid du Colombier freeroute(new);
2797dd7cddfSDavid du Colombier break;
2807dd7cddfSDavid du Colombier case Rcontained:
2817dd7cddfSDavid du Colombier addnode(f, &p->mid, new);
2827dd7cddfSDavid du Colombier break;
2837dd7cddfSDavid du Colombier }
2847dd7cddfSDavid du Colombier
2857dd7cddfSDavid du Colombier balancetree(cur);
2867dd7cddfSDavid du Colombier }
2877dd7cddfSDavid du Colombier
2887dd7cddfSDavid du Colombier #define V4H(a) ((a&0x07ffffff)>>(32-Lroot-5))
2897dd7cddfSDavid du Colombier
2907dd7cddfSDavid du Colombier void
v4addroute(Fs * f,char * tag,uchar * a,uchar * mask,uchar * gate,int type)2917dd7cddfSDavid du Colombier v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
2927dd7cddfSDavid du Colombier {
2937dd7cddfSDavid du Colombier Route *p;
2947dd7cddfSDavid du Colombier ulong sa;
2957dd7cddfSDavid du Colombier ulong m;
2967dd7cddfSDavid du Colombier ulong ea;
2977dd7cddfSDavid du Colombier int h, eh;
2987dd7cddfSDavid du Colombier
2997dd7cddfSDavid du Colombier m = nhgetl(mask);
3007dd7cddfSDavid du Colombier sa = nhgetl(a) & m;
3017dd7cddfSDavid du Colombier ea = sa | ~m;
3027dd7cddfSDavid du Colombier
3037dd7cddfSDavid du Colombier eh = V4H(ea);
3047dd7cddfSDavid du Colombier for(h=V4H(sa); h<=eh; h++) {
3057dd7cddfSDavid du Colombier p = allocroute(Rv4 | type);
3067dd7cddfSDavid du Colombier p->v4.address = sa;
3077dd7cddfSDavid du Colombier p->v4.endaddress = ea;
3087dd7cddfSDavid du Colombier memmove(p->v4.gate, gate, sizeof(p->v4.gate));
3097dd7cddfSDavid du Colombier memmove(p->tag, tag, sizeof(p->tag));
3107dd7cddfSDavid du Colombier
3117dd7cddfSDavid du Colombier wlock(&routelock);
3127dd7cddfSDavid du Colombier addnode(f, &f->v4root[h], p);
3137dd7cddfSDavid du Colombier while(p = f->queue) {
3147dd7cddfSDavid du Colombier f->queue = p->mid;
3157dd7cddfSDavid du Colombier walkadd(f, &f->v4root[h], p->left);
3167dd7cddfSDavid du Colombier freeroute(p);
3177dd7cddfSDavid du Colombier }
3187dd7cddfSDavid du Colombier wunlock(&routelock);
3197dd7cddfSDavid du Colombier }
320a6a9e072SDavid du Colombier v4routegeneration++;
3217dd7cddfSDavid du Colombier
3227dd7cddfSDavid du Colombier ipifcaddroute(f, Rv4, a, mask, gate, type);
3237dd7cddfSDavid du Colombier }
3247dd7cddfSDavid du Colombier
3257dd7cddfSDavid du Colombier #define V6H(a) (((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5))
3263ff48bf5SDavid du Colombier #define ISDFLT(a, mask, tag) ((ipcmp((a),v6Unspecified)==0) && (ipcmp((mask),v6Unspecified)==0) && (strcmp((tag), "ra")!=0))
3277dd7cddfSDavid du Colombier
3287dd7cddfSDavid du Colombier void
v6addroute(Fs * f,char * tag,uchar * a,uchar * mask,uchar * gate,int type)3297dd7cddfSDavid du Colombier v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
3307dd7cddfSDavid du Colombier {
3317dd7cddfSDavid du Colombier Route *p;
3327dd7cddfSDavid du Colombier ulong sa[IPllen], ea[IPllen];
3337dd7cddfSDavid du Colombier ulong x, y;
3347dd7cddfSDavid du Colombier int h, eh;
3357dd7cddfSDavid du Colombier
3363ff48bf5SDavid du Colombier /*
3373ff48bf5SDavid du Colombier if(ISDFLT(a, mask, tag))
3383ff48bf5SDavid du Colombier f->v6p->cdrouter = -1;
3393ff48bf5SDavid du Colombier */
3403ff48bf5SDavid du Colombier
3413ff48bf5SDavid du Colombier
3427dd7cddfSDavid du Colombier for(h = 0; h < IPllen; h++){
3437dd7cddfSDavid du Colombier x = nhgetl(a+4*h);
3447dd7cddfSDavid du Colombier y = nhgetl(mask+4*h);
3457dd7cddfSDavid du Colombier sa[h] = x & y;
3467dd7cddfSDavid du Colombier ea[h] = x | ~y;
3477dd7cddfSDavid du Colombier }
3487dd7cddfSDavid du Colombier
3497dd7cddfSDavid du Colombier eh = V6H(ea);
3507dd7cddfSDavid du Colombier for(h = V6H(sa); h <= eh; h++) {
3517dd7cddfSDavid du Colombier p = allocroute(type);
3527dd7cddfSDavid du Colombier memmove(p->v6.address, sa, IPaddrlen);
3537dd7cddfSDavid du Colombier memmove(p->v6.endaddress, ea, IPaddrlen);
3547dd7cddfSDavid du Colombier memmove(p->v6.gate, gate, IPaddrlen);
3557dd7cddfSDavid du Colombier memmove(p->tag, tag, sizeof(p->tag));
3567dd7cddfSDavid du Colombier
3577dd7cddfSDavid du Colombier wlock(&routelock);
3587dd7cddfSDavid du Colombier addnode(f, &f->v6root[h], p);
3597dd7cddfSDavid du Colombier while(p = f->queue) {
3607dd7cddfSDavid du Colombier f->queue = p->mid;
3617dd7cddfSDavid du Colombier walkadd(f, &f->v6root[h], p->left);
3627dd7cddfSDavid du Colombier freeroute(p);
3637dd7cddfSDavid du Colombier }
3647dd7cddfSDavid du Colombier wunlock(&routelock);
3657dd7cddfSDavid du Colombier }
366a6a9e072SDavid du Colombier v6routegeneration++;
3677dd7cddfSDavid du Colombier
3687dd7cddfSDavid du Colombier ipifcaddroute(f, 0, a, mask, gate, type);
3697dd7cddfSDavid du Colombier }
3707dd7cddfSDavid du Colombier
3717dd7cddfSDavid du Colombier Route**
looknode(Route ** cur,Route * r)3727dd7cddfSDavid du Colombier looknode(Route **cur, Route *r)
3737dd7cddfSDavid du Colombier {
3747dd7cddfSDavid du Colombier Route *p;
3757dd7cddfSDavid du Colombier
3767dd7cddfSDavid du Colombier for(;;){
3777dd7cddfSDavid du Colombier p = *cur;
3787dd7cddfSDavid du Colombier if(p == 0)
3797dd7cddfSDavid du Colombier return 0;
3807dd7cddfSDavid du Colombier
3817dd7cddfSDavid du Colombier switch(rangecompare(r, p)){
3827dd7cddfSDavid du Colombier case Rcontains:
3837dd7cddfSDavid du Colombier return 0;
3847dd7cddfSDavid du Colombier case Rpreceeds:
3857dd7cddfSDavid du Colombier cur = &p->left;
3867dd7cddfSDavid du Colombier break;
3877dd7cddfSDavid du Colombier case Rfollows:
3887dd7cddfSDavid du Colombier cur = &p->right;
3897dd7cddfSDavid du Colombier break;
3907dd7cddfSDavid du Colombier case Rcontained:
3917dd7cddfSDavid du Colombier cur = &p->mid;
3927dd7cddfSDavid du Colombier break;
3937dd7cddfSDavid du Colombier case Requals:
3947dd7cddfSDavid du Colombier return cur;
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier }
3977dd7cddfSDavid du Colombier }
3987dd7cddfSDavid du Colombier
3996c2aa844SDavid du Colombier static void
del1route(Fs * f,Route ** root,Route * rtp,int h,int dolock)4006c2aa844SDavid du Colombier del1route(Fs *f, Route **root, Route *rtp, int h, int dolock)
4017dd7cddfSDavid du Colombier {
4027dd7cddfSDavid du Colombier Route **r, *p;
4037dd7cddfSDavid du Colombier
4047dd7cddfSDavid du Colombier if(dolock)
4057dd7cddfSDavid du Colombier wlock(&routelock);
4066c2aa844SDavid du Colombier r = looknode(&root[h], rtp);
4077dd7cddfSDavid du Colombier if(r) {
4087dd7cddfSDavid du Colombier p = *r;
4099a747e4fSDavid du Colombier if(--(p->ref) == 0){
4107dd7cddfSDavid du Colombier *r = 0;
4117dd7cddfSDavid du Colombier addqueue(&f->queue, p->left);
4127dd7cddfSDavid du Colombier addqueue(&f->queue, p->mid);
4137dd7cddfSDavid du Colombier addqueue(&f->queue, p->right);
4147dd7cddfSDavid du Colombier freeroute(p);
4157dd7cddfSDavid du Colombier while(p = f->queue) {
4167dd7cddfSDavid du Colombier f->queue = p->mid;
4176c2aa844SDavid du Colombier walkadd(f, &root[h], p->left);
4187dd7cddfSDavid du Colombier freeroute(p);
4197dd7cddfSDavid du Colombier }
4207dd7cddfSDavid du Colombier }
4219a747e4fSDavid du Colombier }
4227dd7cddfSDavid du Colombier if(dolock)
4237dd7cddfSDavid du Colombier wunlock(&routelock);
4247dd7cddfSDavid du Colombier }
4256c2aa844SDavid du Colombier
4266c2aa844SDavid du Colombier void
v4delroute(Fs * f,uchar * a,uchar * mask,int dolock)4276c2aa844SDavid du Colombier v4delroute(Fs *f, uchar *a, uchar *mask, int dolock)
4286c2aa844SDavid du Colombier {
4296c2aa844SDavid du Colombier Route rt;
4306c2aa844SDavid du Colombier int h, eh;
4316c2aa844SDavid du Colombier ulong m;
4326c2aa844SDavid du Colombier
4336c2aa844SDavid du Colombier m = nhgetl(mask);
4346c2aa844SDavid du Colombier rt.v4.address = nhgetl(a) & m;
4356c2aa844SDavid du Colombier rt.v4.endaddress = rt.v4.address | ~m;
4366c2aa844SDavid du Colombier rt.type = Rv4;
4376c2aa844SDavid du Colombier
4386c2aa844SDavid du Colombier eh = V4H(rt.v4.endaddress);
4396c2aa844SDavid du Colombier for(h=V4H(rt.v4.address); h<=eh; h++)
4406c2aa844SDavid du Colombier del1route(f, f->v4root, &rt, h, dolock);
441a6a9e072SDavid du Colombier v4routegeneration++;
4427dd7cddfSDavid du Colombier
4437dd7cddfSDavid du Colombier ipifcremroute(f, Rv4, a, mask);
4447dd7cddfSDavid du Colombier }
4457dd7cddfSDavid du Colombier
4467dd7cddfSDavid du Colombier void
v6delroute(Fs * f,uchar * a,uchar * mask,int dolock)4477dd7cddfSDavid du Colombier v6delroute(Fs *f, uchar *a, uchar *mask, int dolock)
4487dd7cddfSDavid du Colombier {
4497dd7cddfSDavid du Colombier Route rt;
4507dd7cddfSDavid du Colombier int h, eh;
4517dd7cddfSDavid du Colombier ulong x, y;
4527dd7cddfSDavid du Colombier
4537dd7cddfSDavid du Colombier for(h = 0; h < IPllen; h++){
4547dd7cddfSDavid du Colombier x = nhgetl(a+4*h);
4557dd7cddfSDavid du Colombier y = nhgetl(mask+4*h);
4567dd7cddfSDavid du Colombier rt.v6.address[h] = x & y;
4577dd7cddfSDavid du Colombier rt.v6.endaddress[h] = x | ~y;
4587dd7cddfSDavid du Colombier }
4597dd7cddfSDavid du Colombier rt.type = 0;
4607dd7cddfSDavid du Colombier
4617dd7cddfSDavid du Colombier eh = V6H(rt.v6.endaddress);
4626c2aa844SDavid du Colombier for(h=V6H(rt.v6.address); h<=eh; h++)
4636c2aa844SDavid du Colombier del1route(f, f->v6root, &rt, h, dolock);
464a6a9e072SDavid du Colombier v6routegeneration++;
4657dd7cddfSDavid du Colombier
4667dd7cddfSDavid du Colombier ipifcremroute(f, 0, a, mask);
4677dd7cddfSDavid du Colombier }
4687dd7cddfSDavid du Colombier
4697dd7cddfSDavid du Colombier Route*
v4lookup(Fs * f,uchar * a,Conv * c)470a6a9e072SDavid du Colombier v4lookup(Fs *f, uchar *a, Conv *c)
4717dd7cddfSDavid du Colombier {
4727dd7cddfSDavid du Colombier Route *p, *q;
4737dd7cddfSDavid du Colombier ulong la;
4747dd7cddfSDavid du Colombier uchar gate[IPaddrlen];
47504b73bddSDavid du Colombier Ipifc *ifc;
4767dd7cddfSDavid du Colombier
47704b73bddSDavid du Colombier if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v4routegeneration)
478a6a9e072SDavid du Colombier return c->r;
479a6a9e072SDavid du Colombier
4807dd7cddfSDavid du Colombier la = nhgetl(a);
4818bbc9479SDavid du Colombier again:
4827dd7cddfSDavid du Colombier q = nil;
4837dd7cddfSDavid du Colombier for(p=f->v4root[V4H(la)]; p;)
4847dd7cddfSDavid du Colombier if(la >= p->v4.address) {
4857dd7cddfSDavid du Colombier if(la <= p->v4.endaddress) {
4867dd7cddfSDavid du Colombier q = p;
4877dd7cddfSDavid du Colombier p = p->mid;
4887dd7cddfSDavid du Colombier } else
4897dd7cddfSDavid du Colombier p = p->right;
4907dd7cddfSDavid du Colombier } else
4917dd7cddfSDavid du Colombier p = p->left;
4927dd7cddfSDavid du Colombier
4937dd7cddfSDavid du Colombier if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
4947dd7cddfSDavid du Colombier if(q->type & Rifc) {
4957dd7cddfSDavid du Colombier hnputl(gate+IPv4off, q->v4.address);
4967dd7cddfSDavid du Colombier memmove(gate, v4prefix, IPv4off);
4977dd7cddfSDavid du Colombier } else
4987dd7cddfSDavid du Colombier v4tov6(gate, q->v4.gate);
49904b73bddSDavid du Colombier ifc = findipifc(f, gate, q->type);
5008bbc9479SDavid du Colombier if(ifc == nil){
5018bbc9479SDavid du Colombier /* find a direct attached route */
5028bbc9479SDavid du Colombier if(q->v4.address == 0 && q->v4.endaddress == ~0){
5038bbc9479SDavid du Colombier la = nhgetl(q->v4.gate);
5048bbc9479SDavid du Colombier goto again;
5058bbc9479SDavid du Colombier }
5067dd7cddfSDavid du Colombier return nil;
5078bbc9479SDavid du Colombier }
50804b73bddSDavid du Colombier q->ifc = ifc;
50904b73bddSDavid du Colombier q->ifcid = ifc->ifcid;
5107dd7cddfSDavid du Colombier }
51104b73bddSDavid du Colombier
512a6a9e072SDavid du Colombier if(c != nil){
513a6a9e072SDavid du Colombier c->r = q;
514a6a9e072SDavid du Colombier c->rgen = v4routegeneration;
515a6a9e072SDavid du Colombier }
5167dd7cddfSDavid du Colombier
5177dd7cddfSDavid du Colombier return q;
5187dd7cddfSDavid du Colombier }
5197dd7cddfSDavid du Colombier
5207dd7cddfSDavid du Colombier Route*
v6lookup(Fs * f,uchar * a,Conv * c)521a6a9e072SDavid du Colombier v6lookup(Fs *f, uchar *a, Conv *c)
5227dd7cddfSDavid du Colombier {
5237dd7cddfSDavid du Colombier Route *p, *q;
5247dd7cddfSDavid du Colombier ulong la[IPllen];
5257dd7cddfSDavid du Colombier int h;
5267dd7cddfSDavid du Colombier ulong x, y;
5277dd7cddfSDavid du Colombier uchar gate[IPaddrlen];
52804b73bddSDavid du Colombier Ipifc *ifc;
5297dd7cddfSDavid du Colombier
5303ff48bf5SDavid du Colombier if(memcmp(a, v4prefix, IPv4off) == 0){
531a6a9e072SDavid du Colombier q = v4lookup(f, a+IPv4off, c);
5327dd7cddfSDavid du Colombier if(q != nil)
5337dd7cddfSDavid du Colombier return q;
5347dd7cddfSDavid du Colombier }
5357dd7cddfSDavid du Colombier
53604b73bddSDavid du Colombier if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v6routegeneration)
537a6a9e072SDavid du Colombier return c->r;
538a6a9e072SDavid du Colombier
5397dd7cddfSDavid du Colombier for(h = 0; h < IPllen; h++)
5407dd7cddfSDavid du Colombier la[h] = nhgetl(a+4*h);
5417dd7cddfSDavid du Colombier
5427dd7cddfSDavid du Colombier q = 0;
5437dd7cddfSDavid du Colombier for(p=f->v6root[V6H(la)]; p;){
5447dd7cddfSDavid du Colombier for(h = 0; h < IPllen; h++){
5457dd7cddfSDavid du Colombier x = la[h];
5467dd7cddfSDavid du Colombier y = p->v6.address[h];
5477dd7cddfSDavid du Colombier if(x == y)
5487dd7cddfSDavid du Colombier continue;
5497dd7cddfSDavid du Colombier if(x < y){
5507dd7cddfSDavid du Colombier p = p->left;
5517dd7cddfSDavid du Colombier goto next;
5527dd7cddfSDavid du Colombier }
5537dd7cddfSDavid du Colombier break;
5547dd7cddfSDavid du Colombier }
5557dd7cddfSDavid du Colombier for(h = 0; h < IPllen; h++){
5567dd7cddfSDavid du Colombier x = la[h];
5577dd7cddfSDavid du Colombier y = p->v6.endaddress[h];
5587dd7cddfSDavid du Colombier if(x == y)
5597dd7cddfSDavid du Colombier continue;
5607dd7cddfSDavid du Colombier if(x > y){
5617dd7cddfSDavid du Colombier p = p->right;
5627dd7cddfSDavid du Colombier goto next;
5637dd7cddfSDavid du Colombier }
5647dd7cddfSDavid du Colombier break;
5657dd7cddfSDavid du Colombier }
5667dd7cddfSDavid du Colombier q = p;
5677dd7cddfSDavid du Colombier p = p->mid;
5687dd7cddfSDavid du Colombier next: ;
5697dd7cddfSDavid du Colombier }
5707dd7cddfSDavid du Colombier
5717dd7cddfSDavid du Colombier if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
5727dd7cddfSDavid du Colombier if(q->type & Rifc) {
5733ff48bf5SDavid du Colombier for(h = 0; h < IPllen; h++)
5743ff48bf5SDavid du Colombier hnputl(gate+4*h, q->v6.address[h]);
57504b73bddSDavid du Colombier ifc = findipifc(f, gate, q->type);
5767dd7cddfSDavid du Colombier } else
57704b73bddSDavid du Colombier ifc = findipifc(f, q->v6.gate, q->type);
57804b73bddSDavid du Colombier if(ifc == nil)
5797dd7cddfSDavid du Colombier return nil;
58004b73bddSDavid du Colombier q->ifc = ifc;
58104b73bddSDavid du Colombier q->ifcid = ifc->ifcid;
5827dd7cddfSDavid du Colombier }
583a6a9e072SDavid du Colombier if(c != nil){
584a6a9e072SDavid du Colombier c->r = q;
585a6a9e072SDavid du Colombier c->rgen = v6routegeneration;
586a6a9e072SDavid du Colombier }
5877dd7cddfSDavid du Colombier
5887dd7cddfSDavid du Colombier return q;
5897dd7cddfSDavid du Colombier }
5907dd7cddfSDavid du Colombier
5917dd7cddfSDavid du Colombier void
routetype(int type,char * p)5927dd7cddfSDavid du Colombier routetype(int type, char *p)
5937dd7cddfSDavid du Colombier {
5947dd7cddfSDavid du Colombier memset(p, ' ', 4);
5957dd7cddfSDavid du Colombier p[4] = 0;
5967dd7cddfSDavid du Colombier if(type & Rv4)
5977dd7cddfSDavid du Colombier *p++ = '4';
5987dd7cddfSDavid du Colombier else
5997dd7cddfSDavid du Colombier *p++ = '6';
6007dd7cddfSDavid du Colombier if(type & Rifc)
6017dd7cddfSDavid du Colombier *p++ = 'i';
6027dd7cddfSDavid du Colombier if(type & Runi)
6037dd7cddfSDavid du Colombier *p++ = 'u';
6047dd7cddfSDavid du Colombier else if(type & Rbcast)
6057dd7cddfSDavid du Colombier *p++ = 'b';
6067dd7cddfSDavid du Colombier else if(type & Rmulti)
6077dd7cddfSDavid du Colombier *p++ = 'm';
6087dd7cddfSDavid du Colombier if(type & Rptpt)
6097dd7cddfSDavid du Colombier *p = 'p';
6107dd7cddfSDavid du Colombier }
6117dd7cddfSDavid du Colombier
612ea58ad6fSDavid du Colombier static char *rformat = "%-15I %-4M %-15I %4.4s %4.4s %3s\n";
6137dd7cddfSDavid du Colombier
6147dd7cddfSDavid du Colombier void
convroute(Route * r,uchar * addr,uchar * mask,uchar * gate,char * t,int * nifc)6157dd7cddfSDavid du Colombier convroute(Route *r, uchar *addr, uchar *mask, uchar *gate, char *t, int *nifc)
6167dd7cddfSDavid du Colombier {
6177dd7cddfSDavid du Colombier int i;
6187dd7cddfSDavid du Colombier
6197dd7cddfSDavid du Colombier if(r->type & Rv4){
6207dd7cddfSDavid du Colombier memmove(addr, v4prefix, IPv4off);
6217dd7cddfSDavid du Colombier hnputl(addr+IPv4off, r->v4.address);
6227dd7cddfSDavid du Colombier memset(mask, 0xff, IPv4off);
6237dd7cddfSDavid du Colombier hnputl(mask+IPv4off, ~(r->v4.endaddress ^ r->v4.address));
6247dd7cddfSDavid du Colombier memmove(gate, v4prefix, IPv4off);
6257dd7cddfSDavid du Colombier memmove(gate+IPv4off, r->v4.gate, IPv4addrlen);
6267dd7cddfSDavid du Colombier } else {
6277dd7cddfSDavid du Colombier for(i = 0; i < IPllen; i++){
6287dd7cddfSDavid du Colombier hnputl(addr + 4*i, r->v6.address[i]);
6297dd7cddfSDavid du Colombier hnputl(mask + 4*i, ~(r->v6.endaddress[i] ^ r->v6.address[i]));
6307dd7cddfSDavid du Colombier }
6317dd7cddfSDavid du Colombier memmove(gate, r->v6.gate, IPaddrlen);
6327dd7cddfSDavid du Colombier }
6337dd7cddfSDavid du Colombier
6347dd7cddfSDavid du Colombier routetype(r->type, t);
6357dd7cddfSDavid du Colombier
6367dd7cddfSDavid du Colombier if(r->ifc)
6377dd7cddfSDavid du Colombier *nifc = r->ifc->conv->x;
6387dd7cddfSDavid du Colombier else
6397dd7cddfSDavid du Colombier *nifc = -1;
6407dd7cddfSDavid du Colombier }
6417dd7cddfSDavid du Colombier
6427dd7cddfSDavid du Colombier /*
6437dd7cddfSDavid du Colombier * this code is not in rr to reduce stack size
6447dd7cddfSDavid du Colombier */
6457dd7cddfSDavid du Colombier static void
sprintroute(Route * r,Routewalk * rw)6467dd7cddfSDavid du Colombier sprintroute(Route *r, Routewalk *rw)
6477dd7cddfSDavid du Colombier {
648679c15e8SDavid du Colombier int nifc, n;
6497dd7cddfSDavid du Colombier char t[5], *iname, ifbuf[5];
6507dd7cddfSDavid du Colombier uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen];
651679c15e8SDavid du Colombier char *p;
6527dd7cddfSDavid du Colombier
6537dd7cddfSDavid du Colombier convroute(r, addr, mask, gate, t, &nifc);
6547dd7cddfSDavid du Colombier iname = "-";
6557dd7cddfSDavid du Colombier if(nifc != -1) {
6567dd7cddfSDavid du Colombier iname = ifbuf;
657208510e1SDavid du Colombier snprint(ifbuf, sizeof ifbuf, "%d", nifc);
6587dd7cddfSDavid du Colombier }
659679c15e8SDavid du Colombier p = seprint(rw->p, rw->e, rformat, addr, mask, gate, t, r->tag, iname);
660679c15e8SDavid du Colombier if(rw->o < 0){
661679c15e8SDavid du Colombier n = p - rw->p;
662679c15e8SDavid du Colombier if(n > -rw->o){
663679c15e8SDavid du Colombier memmove(rw->p, rw->p-rw->o, n+rw->o);
664679c15e8SDavid du Colombier rw->p = p + rw->o;
6657dd7cddfSDavid du Colombier }
666679c15e8SDavid du Colombier rw->o += n;
667679c15e8SDavid du Colombier } else
668679c15e8SDavid du Colombier rw->p = p;
6697dd7cddfSDavid du Colombier }
6707dd7cddfSDavid du Colombier
6717dd7cddfSDavid du Colombier /*
6727dd7cddfSDavid du Colombier * recurse descending tree, applying the function in Routewalk
6737dd7cddfSDavid du Colombier */
6747dd7cddfSDavid du Colombier static int
rr(Route * r,Routewalk * rw)6757dd7cddfSDavid du Colombier rr(Route *r, Routewalk *rw)
6767dd7cddfSDavid du Colombier {
6777dd7cddfSDavid du Colombier int h;
6787dd7cddfSDavid du Colombier
679679c15e8SDavid du Colombier if(rw->e <= rw->p)
6807dd7cddfSDavid du Colombier return 0;
6817dd7cddfSDavid du Colombier if(r == nil)
6827dd7cddfSDavid du Colombier return 1;
6837dd7cddfSDavid du Colombier
6847dd7cddfSDavid du Colombier if(rr(r->left, rw) == 0)
6857dd7cddfSDavid du Colombier return 0;
6867dd7cddfSDavid du Colombier
6877dd7cddfSDavid du Colombier if(r->type & Rv4)
6887dd7cddfSDavid du Colombier h = V4H(r->v4.address);
6897dd7cddfSDavid du Colombier else
6907dd7cddfSDavid du Colombier h = V6H(r->v6.address);
6917dd7cddfSDavid du Colombier
6927dd7cddfSDavid du Colombier if(h == rw->h)
6937dd7cddfSDavid du Colombier rw->walk(r, rw);
6947dd7cddfSDavid du Colombier
6957dd7cddfSDavid du Colombier if(rr(r->mid, rw) == 0)
6967dd7cddfSDavid du Colombier return 0;
6977dd7cddfSDavid du Colombier
6987dd7cddfSDavid du Colombier return rr(r->right, rw);
6997dd7cddfSDavid du Colombier }
7007dd7cddfSDavid du Colombier
7017dd7cddfSDavid du Colombier void
ipwalkroutes(Fs * f,Routewalk * rw)7027dd7cddfSDavid du Colombier ipwalkroutes(Fs *f, Routewalk *rw)
7037dd7cddfSDavid du Colombier {
7047dd7cddfSDavid du Colombier rlock(&routelock);
705679c15e8SDavid du Colombier if(rw->e > rw->p) {
7067dd7cddfSDavid du Colombier for(rw->h = 0; rw->h < nelem(f->v4root); rw->h++)
7077dd7cddfSDavid du Colombier if(rr(f->v4root[rw->h], rw) == 0)
7087dd7cddfSDavid du Colombier break;
7097dd7cddfSDavid du Colombier }
710679c15e8SDavid du Colombier if(rw->e > rw->p) {
7117dd7cddfSDavid du Colombier for(rw->h = 0; rw->h < nelem(f->v6root); rw->h++)
7127dd7cddfSDavid du Colombier if(rr(f->v6root[rw->h], rw) == 0)
7137dd7cddfSDavid du Colombier break;
7147dd7cddfSDavid du Colombier }
7157dd7cddfSDavid du Colombier runlock(&routelock);
7167dd7cddfSDavid du Colombier }
7177dd7cddfSDavid du Colombier
7187dd7cddfSDavid du Colombier long
routeread(Fs * f,char * p,ulong offset,int n)7197dd7cddfSDavid du Colombier routeread(Fs *f, char *p, ulong offset, int n)
7207dd7cddfSDavid du Colombier {
7217dd7cddfSDavid du Colombier Routewalk rw;
7227dd7cddfSDavid du Colombier
7237dd7cddfSDavid du Colombier rw.p = p;
724679c15e8SDavid du Colombier rw.e = p+n;
725679c15e8SDavid du Colombier rw.o = -offset;
7267dd7cddfSDavid du Colombier rw.walk = sprintroute;
7277dd7cddfSDavid du Colombier
7287dd7cddfSDavid du Colombier ipwalkroutes(f, &rw);
7297dd7cddfSDavid du Colombier
730679c15e8SDavid du Colombier return rw.p - p;
7317dd7cddfSDavid du Colombier }
7327dd7cddfSDavid du Colombier
7337dd7cddfSDavid du Colombier /*
7347dd7cddfSDavid du Colombier * this code is not in routeflush to reduce stack size
7357dd7cddfSDavid du Colombier */
7367dd7cddfSDavid du Colombier void
delroute(Fs * f,Route * r,int dolock)7377dd7cddfSDavid du Colombier delroute(Fs *f, Route *r, int dolock)
7387dd7cddfSDavid du Colombier {
7397dd7cddfSDavid du Colombier uchar addr[IPaddrlen];
7407dd7cddfSDavid du Colombier uchar mask[IPaddrlen];
7417dd7cddfSDavid du Colombier uchar gate[IPaddrlen];
7427dd7cddfSDavid du Colombier char t[5];
7437dd7cddfSDavid du Colombier int nifc;
7447dd7cddfSDavid du Colombier
7457dd7cddfSDavid du Colombier convroute(r, addr, mask, gate, t, &nifc);
7467dd7cddfSDavid du Colombier if(r->type & Rv4)
7477dd7cddfSDavid du Colombier v4delroute(f, addr+IPv4off, mask+IPv4off, dolock);
7487dd7cddfSDavid du Colombier else
7497dd7cddfSDavid du Colombier v6delroute(f, addr, mask, dolock);
7507dd7cddfSDavid du Colombier }
7517dd7cddfSDavid du Colombier
7527dd7cddfSDavid du Colombier /*
7537dd7cddfSDavid du Colombier * recurse until one route is deleted
7547dd7cddfSDavid du Colombier * returns 0 if nothing is deleted, 1 otherwise
7557dd7cddfSDavid du Colombier */
7567dd7cddfSDavid du Colombier int
routeflush(Fs * f,Route * r,char * tag)7577dd7cddfSDavid du Colombier routeflush(Fs *f, Route *r, char *tag)
7587dd7cddfSDavid du Colombier {
7597dd7cddfSDavid du Colombier if(r == nil)
7607dd7cddfSDavid du Colombier return 0;
7617dd7cddfSDavid du Colombier if(routeflush(f, r->mid, tag))
7627dd7cddfSDavid du Colombier return 1;
7637dd7cddfSDavid du Colombier if(routeflush(f, r->left, tag))
7647dd7cddfSDavid du Colombier return 1;
7657dd7cddfSDavid du Colombier if(routeflush(f, r->right, tag))
7667dd7cddfSDavid du Colombier return 1;
7677dd7cddfSDavid du Colombier if((r->type & Rifc) == 0){
7687dd7cddfSDavid du Colombier if(tag == nil || strncmp(tag, r->tag, sizeof(r->tag)) == 0){
7697dd7cddfSDavid du Colombier delroute(f, r, 0);
7707dd7cddfSDavid du Colombier return 1;
7717dd7cddfSDavid du Colombier }
7727dd7cddfSDavid du Colombier }
7737dd7cddfSDavid du Colombier return 0;
7747dd7cddfSDavid du Colombier }
7757dd7cddfSDavid du Colombier
776b94bb474SDavid du Colombier Route *
iproute(Fs * fs,uchar * ip)777b94bb474SDavid du Colombier iproute(Fs *fs, uchar *ip)
778b94bb474SDavid du Colombier {
779b94bb474SDavid du Colombier if(isv4(ip))
780b94bb474SDavid du Colombier return v4lookup(fs, ip+IPv4off, nil);
781b94bb474SDavid du Colombier else
782b94bb474SDavid du Colombier return v6lookup(fs, ip, nil);
783b94bb474SDavid du Colombier }
784b94bb474SDavid du Colombier
785b94bb474SDavid du Colombier static void
printroute(Route * r)786b94bb474SDavid du Colombier printroute(Route *r)
787b94bb474SDavid du Colombier {
788b94bb474SDavid du Colombier int nifc;
789b94bb474SDavid du Colombier char t[5], *iname, ifbuf[5];
790b94bb474SDavid du Colombier uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen];
791b94bb474SDavid du Colombier
792b94bb474SDavid du Colombier convroute(r, addr, mask, gate, t, &nifc);
793b94bb474SDavid du Colombier iname = "-";
794b94bb474SDavid du Colombier if(nifc != -1) {
795b94bb474SDavid du Colombier iname = ifbuf;
796b94bb474SDavid du Colombier snprint(ifbuf, sizeof ifbuf, "%d", nifc);
797b94bb474SDavid du Colombier }
798b94bb474SDavid du Colombier print(rformat, addr, mask, gate, t, r->tag, iname);
799b94bb474SDavid du Colombier }
800b94bb474SDavid du Colombier
8017dd7cddfSDavid du Colombier long
routewrite(Fs * f,Chan * c,char * p,int n)8027dd7cddfSDavid du Colombier routewrite(Fs *f, Chan *c, char *p, int n)
8037dd7cddfSDavid du Colombier {
8047dd7cddfSDavid du Colombier int h, changed;
8057dd7cddfSDavid du Colombier char *tag;
8067dd7cddfSDavid du Colombier Cmdbuf *cb;
8077dd7cddfSDavid du Colombier uchar addr[IPaddrlen];
8087dd7cddfSDavid du Colombier uchar mask[IPaddrlen];
8097dd7cddfSDavid du Colombier uchar gate[IPaddrlen];
8109a747e4fSDavid du Colombier IPaux *a, *na;
811b94bb474SDavid du Colombier Route *q;
8128bbc9479SDavid du Colombier uchar type;
8137dd7cddfSDavid du Colombier
8147dd7cddfSDavid du Colombier cb = parsecmd(p, n);
8157dd7cddfSDavid du Colombier if(waserror()){
8167dd7cddfSDavid du Colombier free(cb);
8177dd7cddfSDavid du Colombier nexterror();
8187dd7cddfSDavid du Colombier }
8197dd7cddfSDavid du Colombier
820*4f01f84aSDavid du Colombier if(cb->nf < 1)
821*4f01f84aSDavid du Colombier error("short control request");
822*4f01f84aSDavid du Colombier
8233ff48bf5SDavid du Colombier if(strcmp(cb->f[0], "flush") == 0){
8247dd7cddfSDavid du Colombier tag = cb->f[1];
8257dd7cddfSDavid du Colombier for(h = 0; h < nelem(f->v4root); h++)
8267dd7cddfSDavid du Colombier for(changed = 1; changed;){
8277dd7cddfSDavid du Colombier wlock(&routelock);
8287dd7cddfSDavid du Colombier changed = routeflush(f, f->v4root[h], tag);
8297dd7cddfSDavid du Colombier wunlock(&routelock);
8307dd7cddfSDavid du Colombier }
8317dd7cddfSDavid du Colombier for(h = 0; h < nelem(f->v6root); h++)
8327dd7cddfSDavid du Colombier for(changed = 1; changed;){
8337dd7cddfSDavid du Colombier wlock(&routelock);
8347dd7cddfSDavid du Colombier changed = routeflush(f, f->v6root[h], tag);
8357dd7cddfSDavid du Colombier wunlock(&routelock);
8367dd7cddfSDavid du Colombier }
8373ff48bf5SDavid du Colombier } else if(strcmp(cb->f[0], "remove") == 0){
8383ff48bf5SDavid du Colombier if(cb->nf < 3)
8393ff48bf5SDavid du Colombier error(Ebadarg);
840ea58ad6fSDavid du Colombier if (parseip(addr, cb->f[1]) == -1)
841ea58ad6fSDavid du Colombier error(Ebadip);
8427dd7cddfSDavid du Colombier parseipmask(mask, cb->f[2]);
8437dd7cddfSDavid du Colombier if(memcmp(addr, v4prefix, IPv4off) == 0)
8447dd7cddfSDavid du Colombier v4delroute(f, addr+IPv4off, mask+IPv4off, 1);
8457dd7cddfSDavid du Colombier else
8467dd7cddfSDavid du Colombier v6delroute(f, addr, mask, 1);
8473ff48bf5SDavid du Colombier } else if(strcmp(cb->f[0], "add") == 0){
8483ff48bf5SDavid du Colombier if(cb->nf < 4)
8493ff48bf5SDavid du Colombier error(Ebadarg);
850ea58ad6fSDavid du Colombier if(parseip(addr, cb->f[1]) == -1 ||
851ea58ad6fSDavid du Colombier parseip(gate, cb->f[3]) == -1)
852ea58ad6fSDavid du Colombier error(Ebadip);
8533ff48bf5SDavid du Colombier parseipmask(mask, cb->f[2]);
8543ff48bf5SDavid du Colombier tag = "none";
8553ff48bf5SDavid du Colombier if(c != nil){
8563ff48bf5SDavid du Colombier a = c->aux;
8573ff48bf5SDavid du Colombier tag = a->tag;
8583ff48bf5SDavid du Colombier }
8598bbc9479SDavid du Colombier if(memcmp(addr, v4prefix, IPv4off) == 0){
8608bbc9479SDavid du Colombier type = 0;
8618bbc9479SDavid du Colombier if(ipcmp(mask, IPallbits) == 0)
8628bbc9479SDavid du Colombier type = Rbcast;
8638bbc9479SDavid du Colombier v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, type);
8648bbc9479SDavid du Colombier }else
8653ff48bf5SDavid du Colombier v6addroute(f, tag, addr, mask, gate, 0);
8663ff48bf5SDavid du Colombier } else if(strcmp(cb->f[0], "tag") == 0) {
8673ff48bf5SDavid du Colombier if(cb->nf < 2)
8683ff48bf5SDavid du Colombier error(Ebadarg);
8697dd7cddfSDavid du Colombier
8709a747e4fSDavid du Colombier a = c->aux;
8719a747e4fSDavid du Colombier na = newipaux(a->owner, cb->f[1]);
8729a747e4fSDavid du Colombier c->aux = na;
8739a747e4fSDavid du Colombier free(a);
874b94bb474SDavid du Colombier } else if(strcmp(cb->f[0], "route") == 0) {
875b94bb474SDavid du Colombier if(cb->nf < 2)
876b94bb474SDavid du Colombier error(Ebadarg);
877b94bb474SDavid du Colombier if (parseip(addr, cb->f[1]) == -1)
878b94bb474SDavid du Colombier error(Ebadip);
879b94bb474SDavid du Colombier
880b94bb474SDavid du Colombier q = iproute(f, addr);
881b94bb474SDavid du Colombier print("%I: ", addr);
882b94bb474SDavid du Colombier if(q == nil)
883b94bb474SDavid du Colombier print("no route\n");
884b94bb474SDavid du Colombier else
885b94bb474SDavid du Colombier printroute(q);
886*4f01f84aSDavid du Colombier } else
887*4f01f84aSDavid du Colombier error(Ebadctl);
8887dd7cddfSDavid du Colombier
8897dd7cddfSDavid du Colombier poperror();
8907dd7cddfSDavid du Colombier free(cb);
8917dd7cddfSDavid du Colombier return n;
8927dd7cddfSDavid du Colombier }
893