xref: /plan9-contrib/sys/src/9k/ip/iproute.c (revision 55ba833bbc29e52fa60df7522a0e5f7350ace33d)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier #include	"ip.h"
99ef1f84bSDavid du Colombier 
109ef1f84bSDavid du Colombier static void	walkadd(Fs*, Route**, Route*);
119ef1f84bSDavid du Colombier static void	addnode(Fs*, Route**, Route*);
129ef1f84bSDavid du Colombier static void	calcd(Route*);
139ef1f84bSDavid du Colombier 
149ef1f84bSDavid du Colombier /* these are used for all instances of IP */
159ef1f84bSDavid du Colombier static Route*	v4freelist;
169ef1f84bSDavid du Colombier static Route*	v6freelist;
179ef1f84bSDavid du Colombier static RWlock	routelock;
189ef1f84bSDavid du Colombier static ulong	v4routegeneration, v6routegeneration;
199ef1f84bSDavid du Colombier 
209ef1f84bSDavid du Colombier static void
freeroute(Route * r)219ef1f84bSDavid du Colombier freeroute(Route *r)
229ef1f84bSDavid du Colombier {
239ef1f84bSDavid du Colombier 	Route **l;
249ef1f84bSDavid du Colombier 
259ef1f84bSDavid du Colombier 	r->left = nil;
269ef1f84bSDavid du Colombier 	r->right = nil;
279ef1f84bSDavid du Colombier 	if(r->type & Rv4)
289ef1f84bSDavid du Colombier 		l = &v4freelist;
299ef1f84bSDavid du Colombier 	else
309ef1f84bSDavid du Colombier 		l = &v6freelist;
319ef1f84bSDavid du Colombier 	r->mid = *l;
329ef1f84bSDavid du Colombier 	*l = r;
339ef1f84bSDavid du Colombier }
349ef1f84bSDavid du Colombier 
359ef1f84bSDavid du Colombier static Route*
allocroute(int type)369ef1f84bSDavid du Colombier allocroute(int type)
379ef1f84bSDavid du Colombier {
389ef1f84bSDavid du Colombier 	Route *r;
399ef1f84bSDavid du Colombier 	int n;
409ef1f84bSDavid du Colombier 	Route **l;
419ef1f84bSDavid du Colombier 
429ef1f84bSDavid du Colombier 	if(type & Rv4){
439ef1f84bSDavid du Colombier 		n = sizeof(RouteTree) + sizeof(V4route);
449ef1f84bSDavid du Colombier 		l = &v4freelist;
459ef1f84bSDavid du Colombier 	} else {
469ef1f84bSDavid du Colombier 		n = sizeof(RouteTree) + sizeof(V6route);
479ef1f84bSDavid du Colombier 		l = &v6freelist;
489ef1f84bSDavid du Colombier 	}
499ef1f84bSDavid du Colombier 
509ef1f84bSDavid du Colombier 	r = *l;
519ef1f84bSDavid du Colombier 	if(r != nil){
529ef1f84bSDavid du Colombier 		*l = r->mid;
539ef1f84bSDavid du Colombier 	} else {
549ef1f84bSDavid du Colombier 		r = malloc(n);
559ef1f84bSDavid du Colombier 		if(r == nil)
569ef1f84bSDavid du Colombier 			panic("out of routing nodes");
579ef1f84bSDavid du Colombier 	}
589ef1f84bSDavid du Colombier 	memset(r, 0, n);
599ef1f84bSDavid du Colombier 	r->type = type;
609ef1f84bSDavid du Colombier 	r->ifc = nil;
619ef1f84bSDavid du Colombier 	r->ref = 1;
629ef1f84bSDavid du Colombier 
639ef1f84bSDavid du Colombier 	return r;
649ef1f84bSDavid du Colombier }
659ef1f84bSDavid du Colombier 
669ef1f84bSDavid du Colombier static void
addqueue(Route ** q,Route * r)679ef1f84bSDavid du Colombier addqueue(Route **q, Route *r)
689ef1f84bSDavid du Colombier {
699ef1f84bSDavid du Colombier 	Route *l;
709ef1f84bSDavid du Colombier 
719ef1f84bSDavid du Colombier 	if(r == nil)
729ef1f84bSDavid du Colombier 		return;
739ef1f84bSDavid du Colombier 
749ef1f84bSDavid du Colombier 	l = allocroute(r->type);
759ef1f84bSDavid du Colombier 	l->mid = *q;
769ef1f84bSDavid du Colombier 	*q = l;
779ef1f84bSDavid du Colombier 	l->left = r;
789ef1f84bSDavid du Colombier }
799ef1f84bSDavid du Colombier 
809ef1f84bSDavid du Colombier /*
819ef1f84bSDavid du Colombier  *   compare 2 v6 addresses
829ef1f84bSDavid du Colombier  */
839ef1f84bSDavid du Colombier static int
lcmp(ulong * a,ulong * b)849ef1f84bSDavid du Colombier lcmp(ulong *a, ulong *b)
859ef1f84bSDavid du Colombier {
869ef1f84bSDavid du Colombier 	int i;
879ef1f84bSDavid du Colombier 
889ef1f84bSDavid du Colombier 	for(i = 0; i < IPllen; i++){
899ef1f84bSDavid du Colombier 		if(a[i] > b[i])
909ef1f84bSDavid du Colombier 			return 1;
919ef1f84bSDavid du Colombier 		if(a[i] < b[i])
929ef1f84bSDavid du Colombier 			return -1;
939ef1f84bSDavid du Colombier 	}
949ef1f84bSDavid du Colombier 	return 0;
959ef1f84bSDavid du Colombier }
969ef1f84bSDavid du Colombier 
979ef1f84bSDavid du Colombier /*
989ef1f84bSDavid du Colombier  *  compare 2 v4 or v6 ranges
999ef1f84bSDavid du Colombier  */
1009ef1f84bSDavid du Colombier enum
1019ef1f84bSDavid du Colombier {
1029ef1f84bSDavid du Colombier 	Rpreceeds,
1039ef1f84bSDavid du Colombier 	Rfollows,
1049ef1f84bSDavid du Colombier 	Requals,
1059ef1f84bSDavid du Colombier 	Rcontains,
1069ef1f84bSDavid du Colombier 	Rcontained,
1079ef1f84bSDavid du Colombier };
1089ef1f84bSDavid du Colombier 
1099ef1f84bSDavid du Colombier static int
rangecompare(Route * a,Route * b)1109ef1f84bSDavid du Colombier rangecompare(Route *a, Route *b)
1119ef1f84bSDavid du Colombier {
1129ef1f84bSDavid du Colombier 	if(a->type & Rv4){
1139ef1f84bSDavid du Colombier 		if(a->v4.endaddress < b->v4.address)
1149ef1f84bSDavid du Colombier 			return Rpreceeds;
1159ef1f84bSDavid du Colombier 
1169ef1f84bSDavid du Colombier 		if(a->v4.address > b->v4.endaddress)
1179ef1f84bSDavid du Colombier 			return Rfollows;
1189ef1f84bSDavid du Colombier 
1199ef1f84bSDavid du Colombier 		if(a->v4.address <= b->v4.address
1209ef1f84bSDavid du Colombier 		&& a->v4.endaddress >= b->v4.endaddress){
1219ef1f84bSDavid du Colombier 			if(a->v4.address == b->v4.address
1229ef1f84bSDavid du Colombier 			&& a->v4.endaddress == b->v4.endaddress)
1239ef1f84bSDavid du Colombier 				return Requals;
1249ef1f84bSDavid du Colombier 			return Rcontains;
1259ef1f84bSDavid du Colombier 		}
1269ef1f84bSDavid du Colombier 		return Rcontained;
1279ef1f84bSDavid du Colombier 	}
1289ef1f84bSDavid du Colombier 
1299ef1f84bSDavid du Colombier 	if(lcmp(a->v6.endaddress, b->v6.address) < 0)
1309ef1f84bSDavid du Colombier 		return Rpreceeds;
1319ef1f84bSDavid du Colombier 
1329ef1f84bSDavid du Colombier 	if(lcmp(a->v6.address, b->v6.endaddress) > 0)
1339ef1f84bSDavid du Colombier 		return Rfollows;
1349ef1f84bSDavid du Colombier 
1359ef1f84bSDavid du Colombier 	if(lcmp(a->v6.address, b->v6.address) <= 0
1369ef1f84bSDavid du Colombier 	&& lcmp(a->v6.endaddress, b->v6.endaddress) >= 0){
1379ef1f84bSDavid du Colombier 		if(lcmp(a->v6.address, b->v6.address) == 0
1389ef1f84bSDavid du Colombier 		&& lcmp(a->v6.endaddress, b->v6.endaddress) == 0)
1399ef1f84bSDavid du Colombier 				return Requals;
1409ef1f84bSDavid du Colombier 		return Rcontains;
1419ef1f84bSDavid du Colombier 	}
1429ef1f84bSDavid du Colombier 
1439ef1f84bSDavid du Colombier 	return Rcontained;
1449ef1f84bSDavid du Colombier }
1459ef1f84bSDavid du Colombier 
1469ef1f84bSDavid du Colombier static void
copygate(Route * old,Route * new)1479ef1f84bSDavid du Colombier copygate(Route *old, Route *new)
1489ef1f84bSDavid du Colombier {
1499ef1f84bSDavid du Colombier 	if(new->type & Rv4)
1509ef1f84bSDavid du Colombier 		memmove(old->v4.gate, new->v4.gate, IPv4addrlen);
1519ef1f84bSDavid du Colombier 	else
1529ef1f84bSDavid du Colombier 		memmove(old->v6.gate, new->v6.gate, IPaddrlen);
1539ef1f84bSDavid du Colombier }
1549ef1f84bSDavid du Colombier 
1559ef1f84bSDavid du Colombier /*
1569ef1f84bSDavid du Colombier  *  walk down a tree adding nodes back in
1579ef1f84bSDavid du Colombier  */
1589ef1f84bSDavid du Colombier static void
walkadd(Fs * f,Route ** root,Route * p)1599ef1f84bSDavid du Colombier walkadd(Fs *f, Route **root, Route *p)
1609ef1f84bSDavid du Colombier {
1619ef1f84bSDavid du Colombier 	Route *l, *r;
1629ef1f84bSDavid du Colombier 
1639ef1f84bSDavid du Colombier 	l = p->left;
1649ef1f84bSDavid du Colombier 	r = p->right;
1659ef1f84bSDavid du Colombier 	p->left = 0;
1669ef1f84bSDavid du Colombier 	p->right = 0;
1679ef1f84bSDavid du Colombier 	addnode(f, root, p);
1689ef1f84bSDavid du Colombier 	if(l)
1699ef1f84bSDavid du Colombier 		walkadd(f, root, l);
1709ef1f84bSDavid du Colombier 	if(r)
1719ef1f84bSDavid du Colombier 		walkadd(f, root, r);
1729ef1f84bSDavid du Colombier }
1739ef1f84bSDavid du Colombier 
1749ef1f84bSDavid du Colombier /*
1759ef1f84bSDavid du Colombier  *  calculate depth
1769ef1f84bSDavid du Colombier  */
1779ef1f84bSDavid du Colombier static void
calcd(Route * p)1789ef1f84bSDavid du Colombier calcd(Route *p)
1799ef1f84bSDavid du Colombier {
1809ef1f84bSDavid du Colombier 	Route *q;
1819ef1f84bSDavid du Colombier 	int d;
1829ef1f84bSDavid du Colombier 
1839ef1f84bSDavid du Colombier 	if(p) {
1849ef1f84bSDavid du Colombier 		d = 0;
1859ef1f84bSDavid du Colombier 		q = p->left;
1869ef1f84bSDavid du Colombier 		if(q)
1879ef1f84bSDavid du Colombier 			d = q->depth;
1889ef1f84bSDavid du Colombier 		q = p->right;
1899ef1f84bSDavid du Colombier 		if(q && q->depth > d)
1909ef1f84bSDavid du Colombier 			d = q->depth;
1919ef1f84bSDavid du Colombier 		q = p->mid;
1929ef1f84bSDavid du Colombier 		if(q && q->depth > d)
1939ef1f84bSDavid du Colombier 			d = q->depth;
1949ef1f84bSDavid du Colombier 		p->depth = d+1;
1959ef1f84bSDavid du Colombier 	}
1969ef1f84bSDavid du Colombier }
1979ef1f84bSDavid du Colombier 
1989ef1f84bSDavid du Colombier /*
1999ef1f84bSDavid du Colombier  *  balance the tree at the current node
2009ef1f84bSDavid du Colombier  */
2019ef1f84bSDavid du Colombier static void
balancetree(Route ** cur)2029ef1f84bSDavid du Colombier balancetree(Route **cur)
2039ef1f84bSDavid du Colombier {
2049ef1f84bSDavid du Colombier 	Route *p, *l, *r;
2059ef1f84bSDavid du Colombier 	int dl, dr;
2069ef1f84bSDavid du Colombier 
2079ef1f84bSDavid du Colombier 	/*
2089ef1f84bSDavid du Colombier 	 * if left and right are
2099ef1f84bSDavid du Colombier 	 * too out of balance,
2109ef1f84bSDavid du Colombier 	 * rotate tree node
2119ef1f84bSDavid du Colombier 	 */
2129ef1f84bSDavid du Colombier 	p = *cur;
2139ef1f84bSDavid du Colombier 	dl = 0; if(l = p->left) dl = l->depth;
2149ef1f84bSDavid du Colombier 	dr = 0; if(r = p->right) dr = r->depth;
2159ef1f84bSDavid du Colombier 
2169ef1f84bSDavid du Colombier 	if(dl > dr+1) {
2179ef1f84bSDavid du Colombier 		p->left = l->right;
2189ef1f84bSDavid du Colombier 		l->right = p;
2199ef1f84bSDavid du Colombier 		*cur = l;
2209ef1f84bSDavid du Colombier 		calcd(p);
2219ef1f84bSDavid du Colombier 		calcd(l);
2229ef1f84bSDavid du Colombier 	} else
2239ef1f84bSDavid du Colombier 	if(dr > dl+1) {
2249ef1f84bSDavid du Colombier 		p->right = r->left;
2259ef1f84bSDavid du Colombier 		r->left = p;
2269ef1f84bSDavid du Colombier 		*cur = r;
2279ef1f84bSDavid du Colombier 		calcd(p);
2289ef1f84bSDavid du Colombier 		calcd(r);
2299ef1f84bSDavid du Colombier 	} else
2309ef1f84bSDavid du Colombier 		calcd(p);
2319ef1f84bSDavid du Colombier }
2329ef1f84bSDavid du Colombier 
2339ef1f84bSDavid du Colombier /*
2349ef1f84bSDavid du Colombier  *  add a new node to the tree
2359ef1f84bSDavid du Colombier  */
2369ef1f84bSDavid du Colombier static void
addnode(Fs * f,Route ** cur,Route * new)2379ef1f84bSDavid du Colombier addnode(Fs *f, Route **cur, Route *new)
2389ef1f84bSDavid du Colombier {
2399ef1f84bSDavid du Colombier 	Route *p;
2409ef1f84bSDavid du Colombier 
2419ef1f84bSDavid du Colombier 	p = *cur;
2429ef1f84bSDavid du Colombier 	if(p == 0) {
2439ef1f84bSDavid du Colombier 		*cur = new;
2449ef1f84bSDavid du Colombier 		new->depth = 1;
2459ef1f84bSDavid du Colombier 		return;
2469ef1f84bSDavid du Colombier 	}
2479ef1f84bSDavid du Colombier 
2489ef1f84bSDavid du Colombier 	switch(rangecompare(new, p)){
2499ef1f84bSDavid du Colombier 	case Rpreceeds:
2509ef1f84bSDavid du Colombier 		addnode(f, &p->left, new);
2519ef1f84bSDavid du Colombier 		break;
2529ef1f84bSDavid du Colombier 	case Rfollows:
2539ef1f84bSDavid du Colombier 		addnode(f, &p->right, new);
2549ef1f84bSDavid du Colombier 		break;
2559ef1f84bSDavid du Colombier 	case Rcontains:
2569ef1f84bSDavid du Colombier 		/*
2579ef1f84bSDavid du Colombier 		 *  if new node is superset
2589ef1f84bSDavid du Colombier 		 *  of tree node,
2599ef1f84bSDavid du Colombier 		 *  replace tree node and
2609ef1f84bSDavid du Colombier 		 *  queue tree node to be
2619ef1f84bSDavid du Colombier 		 *  merged into root.
2629ef1f84bSDavid du Colombier 		 */
2639ef1f84bSDavid du Colombier 		*cur = new;
2649ef1f84bSDavid du Colombier 		new->depth = 1;
2659ef1f84bSDavid du Colombier 		addqueue(&f->queue, p);
2669ef1f84bSDavid du Colombier 		break;
2679ef1f84bSDavid du Colombier 	case Requals:
2689ef1f84bSDavid du Colombier 		/*
2699ef1f84bSDavid du Colombier 		 *  supercede the old entry if the old one isn't
2709ef1f84bSDavid du Colombier 		 *  a local interface.
2719ef1f84bSDavid du Colombier 		 */
2729ef1f84bSDavid du Colombier 		if((p->type & Rifc) == 0){
2739ef1f84bSDavid du Colombier 			p->type = new->type;
2749ef1f84bSDavid du Colombier 			p->ifcid = -1;
2759ef1f84bSDavid du Colombier 			copygate(p, new);
2769ef1f84bSDavid du Colombier 		} else if(new->type & Rifc)
2779ef1f84bSDavid du Colombier 			p->ref++;
2789ef1f84bSDavid du Colombier 		freeroute(new);
2799ef1f84bSDavid du Colombier 		break;
2809ef1f84bSDavid du Colombier 	case Rcontained:
2819ef1f84bSDavid du Colombier 		addnode(f, &p->mid, new);
2829ef1f84bSDavid du Colombier 		break;
2839ef1f84bSDavid du Colombier 	}
2849ef1f84bSDavid du Colombier 
2859ef1f84bSDavid du Colombier 	balancetree(cur);
2869ef1f84bSDavid du Colombier }
2879ef1f84bSDavid du Colombier 
2889ef1f84bSDavid du Colombier #define	V4H(a)	((a&0x07ffffff)>>(32-Lroot-5))
2899ef1f84bSDavid du Colombier 
2909ef1f84bSDavid du Colombier void
v4addroute(Fs * f,char * tag,uchar * a,uchar * mask,uchar * gate,int type)2919ef1f84bSDavid du Colombier v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
2929ef1f84bSDavid du Colombier {
2939ef1f84bSDavid du Colombier 	Route *p;
2949ef1f84bSDavid du Colombier 	ulong sa;
2959ef1f84bSDavid du Colombier 	ulong m;
2969ef1f84bSDavid du Colombier 	ulong ea;
2979ef1f84bSDavid du Colombier 	int h, eh;
2989ef1f84bSDavid du Colombier 
2999ef1f84bSDavid du Colombier 	m = nhgetl(mask);
3009ef1f84bSDavid du Colombier 	sa = nhgetl(a) & m;
3019ef1f84bSDavid du Colombier 	ea = sa | ~m;
3029ef1f84bSDavid du Colombier 
3039ef1f84bSDavid du Colombier 	eh = V4H(ea);
3049ef1f84bSDavid du Colombier 	for(h=V4H(sa); h<=eh; h++) {
3059ef1f84bSDavid du Colombier 		p = allocroute(Rv4 | type);
3069ef1f84bSDavid du Colombier 		p->v4.address = sa;
3079ef1f84bSDavid du Colombier 		p->v4.endaddress = ea;
3089ef1f84bSDavid du Colombier 		memmove(p->v4.gate, gate, sizeof(p->v4.gate));
3099ef1f84bSDavid du Colombier 		memmove(p->tag, tag, sizeof(p->tag));
3109ef1f84bSDavid du Colombier 
3119ef1f84bSDavid du Colombier 		wlock(&routelock);
3129ef1f84bSDavid du Colombier 		addnode(f, &f->v4root[h], p);
3139ef1f84bSDavid du Colombier 		while(p = f->queue) {
3149ef1f84bSDavid du Colombier 			f->queue = p->mid;
3159ef1f84bSDavid du Colombier 			walkadd(f, &f->v4root[h], p->left);
3169ef1f84bSDavid du Colombier 			freeroute(p);
3179ef1f84bSDavid du Colombier 		}
3189ef1f84bSDavid du Colombier 		wunlock(&routelock);
3199ef1f84bSDavid du Colombier 	}
3209ef1f84bSDavid du Colombier 	v4routegeneration++;
3219ef1f84bSDavid du Colombier 
3229ef1f84bSDavid du Colombier 	ipifcaddroute(f, Rv4, a, mask, gate, type);
3239ef1f84bSDavid du Colombier }
3249ef1f84bSDavid du Colombier 
3259ef1f84bSDavid du Colombier #define	V6H(a)	(((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5))
3269ef1f84bSDavid du Colombier #define ISDFLT(a, mask, tag) ((ipcmp((a),v6Unspecified)==0) && (ipcmp((mask),v6Unspecified)==0) && (strcmp((tag), "ra")!=0))
3279ef1f84bSDavid du Colombier 
3289ef1f84bSDavid du Colombier void
v6addroute(Fs * f,char * tag,uchar * a,uchar * mask,uchar * gate,int type)3299ef1f84bSDavid du Colombier v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
3309ef1f84bSDavid du Colombier {
3319ef1f84bSDavid du Colombier 	Route *p;
3329ef1f84bSDavid du Colombier 	ulong sa[IPllen], ea[IPllen];
3339ef1f84bSDavid du Colombier 	ulong x, y;
3349ef1f84bSDavid du Colombier 	int h, eh;
3359ef1f84bSDavid du Colombier 
3369ef1f84bSDavid du Colombier 	/*
3379ef1f84bSDavid du Colombier 	if(ISDFLT(a, mask, tag))
3389ef1f84bSDavid du Colombier 		f->v6p->cdrouter = -1;
3399ef1f84bSDavid du Colombier 	*/
3409ef1f84bSDavid du Colombier 
3419ef1f84bSDavid du Colombier 
3429ef1f84bSDavid du Colombier 	for(h = 0; h < IPllen; h++){
3439ef1f84bSDavid du Colombier 		x = nhgetl(a+4*h);
3449ef1f84bSDavid du Colombier 		y = nhgetl(mask+4*h);
3459ef1f84bSDavid du Colombier 		sa[h] = x & y;
3469ef1f84bSDavid du Colombier 		ea[h] = x | ~y;
3479ef1f84bSDavid du Colombier 	}
3489ef1f84bSDavid du Colombier 
3499ef1f84bSDavid du Colombier 	eh = V6H(ea);
3509ef1f84bSDavid du Colombier 	for(h = V6H(sa); h <= eh; h++) {
3519ef1f84bSDavid du Colombier 		p = allocroute(type);
3529ef1f84bSDavid du Colombier 		memmove(p->v6.address, sa, IPaddrlen);
3539ef1f84bSDavid du Colombier 		memmove(p->v6.endaddress, ea, IPaddrlen);
3549ef1f84bSDavid du Colombier 		memmove(p->v6.gate, gate, IPaddrlen);
3559ef1f84bSDavid du Colombier 		memmove(p->tag, tag, sizeof(p->tag));
3569ef1f84bSDavid du Colombier 
3579ef1f84bSDavid du Colombier 		wlock(&routelock);
3589ef1f84bSDavid du Colombier 		addnode(f, &f->v6root[h], p);
3599ef1f84bSDavid du Colombier 		while(p = f->queue) {
3609ef1f84bSDavid du Colombier 			f->queue = p->mid;
3619ef1f84bSDavid du Colombier 			walkadd(f, &f->v6root[h], p->left);
3629ef1f84bSDavid du Colombier 			freeroute(p);
3639ef1f84bSDavid du Colombier 		}
3649ef1f84bSDavid du Colombier 		wunlock(&routelock);
3659ef1f84bSDavid du Colombier 	}
3669ef1f84bSDavid du Colombier 	v6routegeneration++;
3679ef1f84bSDavid du Colombier 
3689ef1f84bSDavid du Colombier 	ipifcaddroute(f, 0, a, mask, gate, type);
3699ef1f84bSDavid du Colombier }
3709ef1f84bSDavid du Colombier 
3719ef1f84bSDavid du Colombier Route**
looknode(Route ** cur,Route * r)3729ef1f84bSDavid du Colombier looknode(Route **cur, Route *r)
3739ef1f84bSDavid du Colombier {
3749ef1f84bSDavid du Colombier 	Route *p;
3759ef1f84bSDavid du Colombier 
3769ef1f84bSDavid du Colombier 	for(;;){
3779ef1f84bSDavid du Colombier 		p = *cur;
3789ef1f84bSDavid du Colombier 		if(p == 0)
3799ef1f84bSDavid du Colombier 			return 0;
3809ef1f84bSDavid du Colombier 
3819ef1f84bSDavid du Colombier 		switch(rangecompare(r, p)){
3829ef1f84bSDavid du Colombier 		case Rcontains:
3839ef1f84bSDavid du Colombier 			return 0;
3849ef1f84bSDavid du Colombier 		case Rpreceeds:
3859ef1f84bSDavid du Colombier 			cur = &p->left;
3869ef1f84bSDavid du Colombier 			break;
3879ef1f84bSDavid du Colombier 		case Rfollows:
3889ef1f84bSDavid du Colombier 			cur = &p->right;
3899ef1f84bSDavid du Colombier 			break;
3909ef1f84bSDavid du Colombier 		case Rcontained:
3919ef1f84bSDavid du Colombier 			cur = &p->mid;
3929ef1f84bSDavid du Colombier 			break;
3939ef1f84bSDavid du Colombier 		case Requals:
3949ef1f84bSDavid du Colombier 			return cur;
3959ef1f84bSDavid du Colombier 		}
3969ef1f84bSDavid du Colombier 	}
3979ef1f84bSDavid du Colombier }
3989ef1f84bSDavid du Colombier 
3997356a45dSDavid du Colombier static void
del1route(Fs * f,Route ** root,Route * rtp,int h,int dolock)4007356a45dSDavid du Colombier del1route(Fs *f, Route **root, Route *rtp, int h, int dolock)
4019ef1f84bSDavid du Colombier {
4029ef1f84bSDavid du Colombier 	Route **r, *p;
4039ef1f84bSDavid du Colombier 
4049ef1f84bSDavid du Colombier 	if(dolock)
4059ef1f84bSDavid du Colombier 		wlock(&routelock);
4067356a45dSDavid du Colombier 	r = looknode(&root[h], rtp);
4079ef1f84bSDavid du Colombier 	if(r) {
4089ef1f84bSDavid du Colombier 		p = *r;
4099ef1f84bSDavid du Colombier 		if(--(p->ref) == 0){
4109ef1f84bSDavid du Colombier 			*r = 0;
4119ef1f84bSDavid du Colombier 			addqueue(&f->queue, p->left);
4129ef1f84bSDavid du Colombier 			addqueue(&f->queue, p->mid);
4139ef1f84bSDavid du Colombier 			addqueue(&f->queue, p->right);
4149ef1f84bSDavid du Colombier 			freeroute(p);
4159ef1f84bSDavid du Colombier 			while(p = f->queue) {
4169ef1f84bSDavid du Colombier 				f->queue = p->mid;
4177356a45dSDavid du Colombier 				walkadd(f, &root[h], p->left);
4189ef1f84bSDavid du Colombier 				freeroute(p);
4199ef1f84bSDavid du Colombier 			}
4209ef1f84bSDavid du Colombier 		}
4219ef1f84bSDavid du Colombier 	}
4229ef1f84bSDavid du Colombier 	if(dolock)
4239ef1f84bSDavid du Colombier 		wunlock(&routelock);
4249ef1f84bSDavid du Colombier }
4257356a45dSDavid du Colombier 
4267356a45dSDavid du Colombier void
v4delroute(Fs * f,uchar * a,uchar * mask,int dolock)4277356a45dSDavid du Colombier v4delroute(Fs *f, uchar *a, uchar *mask, int dolock)
4287356a45dSDavid du Colombier {
4297356a45dSDavid du Colombier 	Route rt;
4307356a45dSDavid du Colombier 	int h, eh;
4317356a45dSDavid du Colombier 	ulong m;
4327356a45dSDavid du Colombier 
4337356a45dSDavid du Colombier 	m = nhgetl(mask);
4347356a45dSDavid du Colombier 	rt.v4.address = nhgetl(a) & m;
4357356a45dSDavid du Colombier 	rt.v4.endaddress = rt.v4.address | ~m;
4367356a45dSDavid du Colombier 	rt.type = Rv4;
4377356a45dSDavid du Colombier 
4387356a45dSDavid du Colombier 	eh = V4H(rt.v4.endaddress);
4397356a45dSDavid du Colombier 	for(h=V4H(rt.v4.address); h<=eh; h++)
4407356a45dSDavid du Colombier 		del1route(f, f->v4root, &rt, h, dolock);
4419ef1f84bSDavid du Colombier 	v4routegeneration++;
4429ef1f84bSDavid du Colombier 
4439ef1f84bSDavid du Colombier 	ipifcremroute(f, Rv4, a, mask);
4449ef1f84bSDavid du Colombier }
4459ef1f84bSDavid du Colombier 
4469ef1f84bSDavid du Colombier void
v6delroute(Fs * f,uchar * a,uchar * mask,int dolock)4479ef1f84bSDavid du Colombier v6delroute(Fs *f, uchar *a, uchar *mask, int dolock)
4489ef1f84bSDavid du Colombier {
4499ef1f84bSDavid du Colombier 	Route rt;
4509ef1f84bSDavid du Colombier 	int h, eh;
4519ef1f84bSDavid du Colombier 	ulong x, y;
4529ef1f84bSDavid du Colombier 
4539ef1f84bSDavid du Colombier 	for(h = 0; h < IPllen; h++){
4549ef1f84bSDavid du Colombier 		x = nhgetl(a+4*h);
4559ef1f84bSDavid du Colombier 		y = nhgetl(mask+4*h);
4569ef1f84bSDavid du Colombier 		rt.v6.address[h] = x & y;
4579ef1f84bSDavid du Colombier 		rt.v6.endaddress[h] = x | ~y;
4589ef1f84bSDavid du Colombier 	}
4599ef1f84bSDavid du Colombier 	rt.type = 0;
4609ef1f84bSDavid du Colombier 
4619ef1f84bSDavid du Colombier 	eh = V6H(rt.v6.endaddress);
4627356a45dSDavid du Colombier 	for(h=V6H(rt.v6.address); h<=eh; h++)
4637356a45dSDavid du Colombier 		del1route(f, f->v6root, &rt, h, dolock);
4649ef1f84bSDavid du Colombier 	v6routegeneration++;
4659ef1f84bSDavid du Colombier 
4669ef1f84bSDavid du Colombier 	ipifcremroute(f, 0, a, mask);
4679ef1f84bSDavid du Colombier }
4689ef1f84bSDavid du Colombier 
4699ef1f84bSDavid du Colombier Route*
v4lookup(Fs * f,uchar * a,Conv * c)4709ef1f84bSDavid du Colombier v4lookup(Fs *f, uchar *a, Conv *c)
4719ef1f84bSDavid du Colombier {
4729ef1f84bSDavid du Colombier 	Route *p, *q;
4739ef1f84bSDavid du Colombier 	ulong la;
4749ef1f84bSDavid du Colombier 	uchar gate[IPaddrlen];
4759ef1f84bSDavid du Colombier 	Ipifc *ifc;
4769ef1f84bSDavid du Colombier 
4779ef1f84bSDavid du Colombier 	if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v4routegeneration)
4789ef1f84bSDavid du Colombier 		return c->r;
4799ef1f84bSDavid du Colombier 
4809ef1f84bSDavid du Colombier 	la = nhgetl(a);
481*55ba833bSDavid du Colombier again:
4829ef1f84bSDavid du Colombier 	q = nil;
4839ef1f84bSDavid du Colombier 	for(p=f->v4root[V4H(la)]; p;)
4849ef1f84bSDavid du Colombier 		if(la >= p->v4.address) {
4859ef1f84bSDavid du Colombier 			if(la <= p->v4.endaddress) {
4869ef1f84bSDavid du Colombier 				q = p;
4879ef1f84bSDavid du Colombier 				p = p->mid;
4889ef1f84bSDavid du Colombier 			} else
4899ef1f84bSDavid du Colombier 				p = p->right;
4909ef1f84bSDavid du Colombier 		} else
4919ef1f84bSDavid du Colombier 			p = p->left;
4929ef1f84bSDavid du Colombier 
4939ef1f84bSDavid du Colombier 	if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
4949ef1f84bSDavid du Colombier 		if(q->type & Rifc) {
4959ef1f84bSDavid du Colombier 			hnputl(gate+IPv4off, q->v4.address);
4969ef1f84bSDavid du Colombier 			memmove(gate, v4prefix, IPv4off);
4979ef1f84bSDavid du Colombier 		} else
4989ef1f84bSDavid du Colombier 			v4tov6(gate, q->v4.gate);
4999ef1f84bSDavid du Colombier 		ifc = findipifc(f, gate, q->type);
500*55ba833bSDavid du Colombier 		if(ifc == nil){
501*55ba833bSDavid du Colombier 			/* find a direct attached route */
502*55ba833bSDavid du Colombier 			if(q->v4.address == 0 && q->v4.endaddress == ~0){
503*55ba833bSDavid du Colombier 				la = nhgetl(q->v4.gate);
504*55ba833bSDavid du Colombier 				goto again;
505*55ba833bSDavid du Colombier 			}
5069ef1f84bSDavid du Colombier 			return nil;
507*55ba833bSDavid du Colombier 		}
5089ef1f84bSDavid du Colombier 		q->ifc = ifc;
5099ef1f84bSDavid du Colombier 		q->ifcid = ifc->ifcid;
5109ef1f84bSDavid du Colombier 	}
5119ef1f84bSDavid du Colombier 
5129ef1f84bSDavid du Colombier 	if(c != nil){
5139ef1f84bSDavid du Colombier 		c->r = q;
5149ef1f84bSDavid du Colombier 		c->rgen = v4routegeneration;
5159ef1f84bSDavid du Colombier 	}
5169ef1f84bSDavid du Colombier 
5179ef1f84bSDavid du Colombier 	return q;
5189ef1f84bSDavid du Colombier }
5199ef1f84bSDavid du Colombier 
5209ef1f84bSDavid du Colombier Route*
v6lookup(Fs * f,uchar * a,Conv * c)5219ef1f84bSDavid du Colombier v6lookup(Fs *f, uchar *a, Conv *c)
5229ef1f84bSDavid du Colombier {
5239ef1f84bSDavid du Colombier 	Route *p, *q;
5249ef1f84bSDavid du Colombier 	ulong la[IPllen];
5259ef1f84bSDavid du Colombier 	int h;
5269ef1f84bSDavid du Colombier 	ulong x, y;
5279ef1f84bSDavid du Colombier 	uchar gate[IPaddrlen];
5289ef1f84bSDavid du Colombier 	Ipifc *ifc;
5299ef1f84bSDavid du Colombier 
5309ef1f84bSDavid du Colombier 	if(memcmp(a, v4prefix, IPv4off) == 0){
5319ef1f84bSDavid du Colombier 		q = v4lookup(f, a+IPv4off, c);
5329ef1f84bSDavid du Colombier 		if(q != nil)
5339ef1f84bSDavid du Colombier 			return q;
5349ef1f84bSDavid du Colombier 	}
5359ef1f84bSDavid du Colombier 
5369ef1f84bSDavid du Colombier 	if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v6routegeneration)
5379ef1f84bSDavid du Colombier 		return c->r;
5389ef1f84bSDavid du Colombier 
5399ef1f84bSDavid du Colombier 	for(h = 0; h < IPllen; h++)
5409ef1f84bSDavid du Colombier 		la[h] = nhgetl(a+4*h);
5419ef1f84bSDavid du Colombier 
5429ef1f84bSDavid du Colombier 	q = 0;
5439ef1f84bSDavid du Colombier 	for(p=f->v6root[V6H(la)]; p;){
5449ef1f84bSDavid du Colombier 		for(h = 0; h < IPllen; h++){
5459ef1f84bSDavid du Colombier 			x = la[h];
5469ef1f84bSDavid du Colombier 			y = p->v6.address[h];
5479ef1f84bSDavid du Colombier 			if(x == y)
5489ef1f84bSDavid du Colombier 				continue;
5499ef1f84bSDavid du Colombier 			if(x < y){
5509ef1f84bSDavid du Colombier 				p = p->left;
5519ef1f84bSDavid du Colombier 				goto next;
5529ef1f84bSDavid du Colombier 			}
5539ef1f84bSDavid du Colombier 			break;
5549ef1f84bSDavid du Colombier 		}
5559ef1f84bSDavid du Colombier 		for(h = 0; h < IPllen; h++){
5569ef1f84bSDavid du Colombier 			x = la[h];
5579ef1f84bSDavid du Colombier 			y = p->v6.endaddress[h];
5589ef1f84bSDavid du Colombier 			if(x == y)
5599ef1f84bSDavid du Colombier 				continue;
5609ef1f84bSDavid du Colombier 			if(x > y){
5619ef1f84bSDavid du Colombier 				p = p->right;
5629ef1f84bSDavid du Colombier 				goto next;
5639ef1f84bSDavid du Colombier 			}
5649ef1f84bSDavid du Colombier 			break;
5659ef1f84bSDavid du Colombier 		}
5669ef1f84bSDavid du Colombier 		q = p;
5679ef1f84bSDavid du Colombier 		p = p->mid;
5689ef1f84bSDavid du Colombier next:		;
5699ef1f84bSDavid du Colombier 	}
5709ef1f84bSDavid du Colombier 
5719ef1f84bSDavid du Colombier 	if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
5729ef1f84bSDavid du Colombier 		if(q->type & Rifc) {
5739ef1f84bSDavid du Colombier 			for(h = 0; h < IPllen; h++)
5749ef1f84bSDavid du Colombier 				hnputl(gate+4*h, q->v6.address[h]);
5759ef1f84bSDavid du Colombier 			ifc = findipifc(f, gate, q->type);
5769ef1f84bSDavid du Colombier 		} else
5779ef1f84bSDavid du Colombier 			ifc = findipifc(f, q->v6.gate, q->type);
5789ef1f84bSDavid du Colombier 		if(ifc == nil)
5799ef1f84bSDavid du Colombier 			return nil;
5809ef1f84bSDavid du Colombier 		q->ifc = ifc;
5819ef1f84bSDavid du Colombier 		q->ifcid = ifc->ifcid;
5829ef1f84bSDavid du Colombier 	}
5839ef1f84bSDavid du Colombier 	if(c != nil){
5849ef1f84bSDavid du Colombier 		c->r = q;
5859ef1f84bSDavid du Colombier 		c->rgen = v6routegeneration;
5869ef1f84bSDavid du Colombier 	}
5879ef1f84bSDavid du Colombier 
5889ef1f84bSDavid du Colombier 	return q;
5899ef1f84bSDavid du Colombier }
5909ef1f84bSDavid du Colombier 
5919ef1f84bSDavid du Colombier void
routetype(int type,char * p)5929ef1f84bSDavid du Colombier routetype(int type, char *p)
5939ef1f84bSDavid du Colombier {
5949ef1f84bSDavid du Colombier 	memset(p, ' ', 4);
5959ef1f84bSDavid du Colombier 	p[4] = 0;
5969ef1f84bSDavid du Colombier 	if(type & Rv4)
5979ef1f84bSDavid du Colombier 		*p++ = '4';
5989ef1f84bSDavid du Colombier 	else
5999ef1f84bSDavid du Colombier 		*p++ = '6';
6009ef1f84bSDavid du Colombier 	if(type & Rifc)
6019ef1f84bSDavid du Colombier 		*p++ = 'i';
6029ef1f84bSDavid du Colombier 	if(type & Runi)
6039ef1f84bSDavid du Colombier 		*p++ = 'u';
6049ef1f84bSDavid du Colombier 	else if(type & Rbcast)
6059ef1f84bSDavid du Colombier 		*p++ = 'b';
6069ef1f84bSDavid du Colombier 	else if(type & Rmulti)
6079ef1f84bSDavid du Colombier 		*p++ = 'm';
6089ef1f84bSDavid du Colombier 	if(type & Rptpt)
6099ef1f84bSDavid du Colombier 		*p = 'p';
6109ef1f84bSDavid du Colombier }
6119ef1f84bSDavid du Colombier 
6129ef1f84bSDavid du Colombier static char *rformat = "%-15I %-4M %-15I %4.4s %4.4s %3s\n";
6139ef1f84bSDavid du Colombier 
6149ef1f84bSDavid du Colombier void
convroute(Route * r,uchar * addr,uchar * mask,uchar * gate,char * t,int * nifc)6159ef1f84bSDavid du Colombier convroute(Route *r, uchar *addr, uchar *mask, uchar *gate, char *t, int *nifc)
6169ef1f84bSDavid du Colombier {
6179ef1f84bSDavid du Colombier 	int i;
6189ef1f84bSDavid du Colombier 
6199ef1f84bSDavid du Colombier 	if(r->type & Rv4){
6209ef1f84bSDavid du Colombier 		memmove(addr, v4prefix, IPv4off);
6219ef1f84bSDavid du Colombier 		hnputl(addr+IPv4off, r->v4.address);
6229ef1f84bSDavid du Colombier 		memset(mask, 0xff, IPv4off);
6239ef1f84bSDavid du Colombier 		hnputl(mask+IPv4off, ~(r->v4.endaddress ^ r->v4.address));
6249ef1f84bSDavid du Colombier 		memmove(gate, v4prefix, IPv4off);
6259ef1f84bSDavid du Colombier 		memmove(gate+IPv4off, r->v4.gate, IPv4addrlen);
6269ef1f84bSDavid du Colombier 	} else {
6279ef1f84bSDavid du Colombier 		for(i = 0; i < IPllen; i++){
6289ef1f84bSDavid du Colombier 			hnputl(addr + 4*i, r->v6.address[i]);
6299ef1f84bSDavid du Colombier 			hnputl(mask + 4*i, ~(r->v6.endaddress[i] ^ r->v6.address[i]));
6309ef1f84bSDavid du Colombier 		}
6319ef1f84bSDavid du Colombier 		memmove(gate, r->v6.gate, IPaddrlen);
6329ef1f84bSDavid du Colombier 	}
6339ef1f84bSDavid du Colombier 
6349ef1f84bSDavid du Colombier 	routetype(r->type, t);
6359ef1f84bSDavid du Colombier 
6369ef1f84bSDavid du Colombier 	if(r->ifc)
6379ef1f84bSDavid du Colombier 		*nifc = r->ifc->conv->x;
6389ef1f84bSDavid du Colombier 	else
6399ef1f84bSDavid du Colombier 		*nifc = -1;
6409ef1f84bSDavid du Colombier }
6419ef1f84bSDavid du Colombier 
6429ef1f84bSDavid du Colombier /*
6439ef1f84bSDavid du Colombier  *  this code is not in rr to reduce stack size
6449ef1f84bSDavid du Colombier  */
6459ef1f84bSDavid du Colombier static void
sprintroute(Route * r,Routewalk * rw)6469ef1f84bSDavid du Colombier sprintroute(Route *r, Routewalk *rw)
6479ef1f84bSDavid du Colombier {
6489ef1f84bSDavid du Colombier 	int nifc, n;
6499ef1f84bSDavid du Colombier 	char t[5], *iname, ifbuf[5];
6509ef1f84bSDavid du Colombier 	uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen];
6519ef1f84bSDavid du Colombier 	char *p;
6529ef1f84bSDavid du Colombier 
6539ef1f84bSDavid du Colombier 	convroute(r, addr, mask, gate, t, &nifc);
6549ef1f84bSDavid du Colombier 	iname = "-";
6559ef1f84bSDavid du Colombier 	if(nifc != -1) {
6569ef1f84bSDavid du Colombier 		iname = ifbuf;
6579ef1f84bSDavid du Colombier 		snprint(ifbuf, sizeof ifbuf, "%d", nifc);
6589ef1f84bSDavid du Colombier 	}
6599ef1f84bSDavid du Colombier 	p = seprint(rw->p, rw->e, rformat, addr, mask, gate, t, r->tag, iname);
6609ef1f84bSDavid du Colombier 	if(rw->o < 0){
6619ef1f84bSDavid du Colombier 		n = p - rw->p;
6629ef1f84bSDavid du Colombier 		if(n > -rw->o){
6639ef1f84bSDavid du Colombier 			memmove(rw->p, rw->p-rw->o, n+rw->o);
6649ef1f84bSDavid du Colombier 			rw->p = p + rw->o;
6659ef1f84bSDavid du Colombier 		}
6669ef1f84bSDavid du Colombier 		rw->o += n;
6679ef1f84bSDavid du Colombier 	} else
6689ef1f84bSDavid du Colombier 		rw->p = p;
6699ef1f84bSDavid du Colombier }
6709ef1f84bSDavid du Colombier 
6719ef1f84bSDavid du Colombier /*
6729ef1f84bSDavid du Colombier  *  recurse descending tree, applying the function in Routewalk
6739ef1f84bSDavid du Colombier  */
6749ef1f84bSDavid du Colombier static int
rr(Route * r,Routewalk * rw)6759ef1f84bSDavid du Colombier rr(Route *r, Routewalk *rw)
6769ef1f84bSDavid du Colombier {
6779ef1f84bSDavid du Colombier 	int h;
6789ef1f84bSDavid du Colombier 
6799ef1f84bSDavid du Colombier 	if(rw->e <= rw->p)
6809ef1f84bSDavid du Colombier 		return 0;
6819ef1f84bSDavid du Colombier 	if(r == nil)
6829ef1f84bSDavid du Colombier 		return 1;
6839ef1f84bSDavid du Colombier 
6849ef1f84bSDavid du Colombier 	if(rr(r->left, rw) == 0)
6859ef1f84bSDavid du Colombier 		return 0;
6869ef1f84bSDavid du Colombier 
6879ef1f84bSDavid du Colombier 	if(r->type & Rv4)
6889ef1f84bSDavid du Colombier 		h = V4H(r->v4.address);
6899ef1f84bSDavid du Colombier 	else
6909ef1f84bSDavid du Colombier 		h = V6H(r->v6.address);
6919ef1f84bSDavid du Colombier 
6929ef1f84bSDavid du Colombier 	if(h == rw->h)
6939ef1f84bSDavid du Colombier 		rw->walk(r, rw);
6949ef1f84bSDavid du Colombier 
6959ef1f84bSDavid du Colombier 	if(rr(r->mid, rw) == 0)
6969ef1f84bSDavid du Colombier 		return 0;
6979ef1f84bSDavid du Colombier 
6989ef1f84bSDavid du Colombier 	return rr(r->right, rw);
6999ef1f84bSDavid du Colombier }
7009ef1f84bSDavid du Colombier 
7019ef1f84bSDavid du Colombier void
ipwalkroutes(Fs * f,Routewalk * rw)7029ef1f84bSDavid du Colombier ipwalkroutes(Fs *f, Routewalk *rw)
7039ef1f84bSDavid du Colombier {
7049ef1f84bSDavid du Colombier 	rlock(&routelock);
7059ef1f84bSDavid du Colombier 	if(rw->e > rw->p) {
7069ef1f84bSDavid du Colombier 		for(rw->h = 0; rw->h < nelem(f->v4root); rw->h++)
7079ef1f84bSDavid du Colombier 			if(rr(f->v4root[rw->h], rw) == 0)
7089ef1f84bSDavid du Colombier 				break;
7099ef1f84bSDavid du Colombier 	}
7109ef1f84bSDavid du Colombier 	if(rw->e > rw->p) {
7119ef1f84bSDavid du Colombier 		for(rw->h = 0; rw->h < nelem(f->v6root); rw->h++)
7129ef1f84bSDavid du Colombier 			if(rr(f->v6root[rw->h], rw) == 0)
7139ef1f84bSDavid du Colombier 				break;
7149ef1f84bSDavid du Colombier 	}
7159ef1f84bSDavid du Colombier 	runlock(&routelock);
7169ef1f84bSDavid du Colombier }
7179ef1f84bSDavid du Colombier 
7189ef1f84bSDavid du Colombier long
routeread(Fs * f,char * p,ulong offset,int n)7199ef1f84bSDavid du Colombier routeread(Fs *f, char *p, ulong offset, int n)
7209ef1f84bSDavid du Colombier {
7219ef1f84bSDavid du Colombier 	Routewalk rw;
7229ef1f84bSDavid du Colombier 
7239ef1f84bSDavid du Colombier 	rw.p = p;
7249ef1f84bSDavid du Colombier 	rw.e = p+n;
7259ef1f84bSDavid du Colombier 	rw.o = -offset;
7269ef1f84bSDavid du Colombier 	rw.walk = sprintroute;
7279ef1f84bSDavid du Colombier 
7289ef1f84bSDavid du Colombier 	ipwalkroutes(f, &rw);
7299ef1f84bSDavid du Colombier 
7309ef1f84bSDavid du Colombier 	return rw.p - p;
7319ef1f84bSDavid du Colombier }
7329ef1f84bSDavid du Colombier 
7339ef1f84bSDavid du Colombier /*
7349ef1f84bSDavid du Colombier  *  this code is not in routeflush to reduce stack size
7359ef1f84bSDavid du Colombier  */
7369ef1f84bSDavid du Colombier void
delroute(Fs * f,Route * r,int dolock)7379ef1f84bSDavid du Colombier delroute(Fs *f, Route *r, int dolock)
7389ef1f84bSDavid du Colombier {
7399ef1f84bSDavid du Colombier 	uchar addr[IPaddrlen];
7409ef1f84bSDavid du Colombier 	uchar mask[IPaddrlen];
7419ef1f84bSDavid du Colombier 	uchar gate[IPaddrlen];
7429ef1f84bSDavid du Colombier 	char t[5];
7439ef1f84bSDavid du Colombier 	int nifc;
7449ef1f84bSDavid du Colombier 
7459ef1f84bSDavid du Colombier 	convroute(r, addr, mask, gate, t, &nifc);
7469ef1f84bSDavid du Colombier 	if(r->type & Rv4)
7479ef1f84bSDavid du Colombier 		v4delroute(f, addr+IPv4off, mask+IPv4off, dolock);
7489ef1f84bSDavid du Colombier 	else
7499ef1f84bSDavid du Colombier 		v6delroute(f, addr, mask, dolock);
7509ef1f84bSDavid du Colombier }
7519ef1f84bSDavid du Colombier 
7529ef1f84bSDavid du Colombier /*
7539ef1f84bSDavid du Colombier  *  recurse until one route is deleted
7549ef1f84bSDavid du Colombier  *    returns 0 if nothing is deleted, 1 otherwise
7559ef1f84bSDavid du Colombier  */
7569ef1f84bSDavid du Colombier int
routeflush(Fs * f,Route * r,char * tag)7579ef1f84bSDavid du Colombier routeflush(Fs *f, Route *r, char *tag)
7589ef1f84bSDavid du Colombier {
7599ef1f84bSDavid du Colombier 	if(r == nil)
7609ef1f84bSDavid du Colombier 		return 0;
7619ef1f84bSDavid du Colombier 	if(routeflush(f, r->mid, tag))
7629ef1f84bSDavid du Colombier 		return 1;
7639ef1f84bSDavid du Colombier 	if(routeflush(f, r->left, tag))
7649ef1f84bSDavid du Colombier 		return 1;
7659ef1f84bSDavid du Colombier 	if(routeflush(f, r->right, tag))
7669ef1f84bSDavid du Colombier 		return 1;
7679ef1f84bSDavid du Colombier 	if((r->type & Rifc) == 0){
7689ef1f84bSDavid du Colombier 		if(tag == nil || strncmp(tag, r->tag, sizeof(r->tag)) == 0){
7699ef1f84bSDavid du Colombier 			delroute(f, r, 0);
7709ef1f84bSDavid du Colombier 			return 1;
7719ef1f84bSDavid du Colombier 		}
7729ef1f84bSDavid du Colombier 	}
7739ef1f84bSDavid du Colombier 	return 0;
7749ef1f84bSDavid du Colombier }
7759ef1f84bSDavid du Colombier 
7769ef1f84bSDavid du Colombier Route *
iproute(Fs * fs,uchar * ip)7779ef1f84bSDavid du Colombier iproute(Fs *fs, uchar *ip)
7789ef1f84bSDavid du Colombier {
7799ef1f84bSDavid du Colombier 	if(isv4(ip))
7809ef1f84bSDavid du Colombier 		return v4lookup(fs, ip+IPv4off, nil);
7819ef1f84bSDavid du Colombier 	else
7829ef1f84bSDavid du Colombier 		return v6lookup(fs, ip, nil);
7839ef1f84bSDavid du Colombier }
7849ef1f84bSDavid du Colombier 
7859ef1f84bSDavid du Colombier static void
printroute(Route * r)7869ef1f84bSDavid du Colombier printroute(Route *r)
7879ef1f84bSDavid du Colombier {
7889ef1f84bSDavid du Colombier 	int nifc;
7899ef1f84bSDavid du Colombier 	char t[5], *iname, ifbuf[5];
7909ef1f84bSDavid du Colombier 	uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen];
7919ef1f84bSDavid du Colombier 
7929ef1f84bSDavid du Colombier 	convroute(r, addr, mask, gate, t, &nifc);
7939ef1f84bSDavid du Colombier 	iname = "-";
7949ef1f84bSDavid du Colombier 	if(nifc != -1) {
7959ef1f84bSDavid du Colombier 		iname = ifbuf;
7969ef1f84bSDavid du Colombier 		snprint(ifbuf, sizeof ifbuf, "%d", nifc);
7979ef1f84bSDavid du Colombier 	}
7989ef1f84bSDavid du Colombier 	print(rformat, addr, mask, gate, t, r->tag, iname);
7999ef1f84bSDavid du Colombier }
8009ef1f84bSDavid du Colombier 
8019ef1f84bSDavid du Colombier long
routewrite(Fs * f,Chan * c,char * p,int n)8029ef1f84bSDavid du Colombier routewrite(Fs *f, Chan *c, char *p, int n)
8039ef1f84bSDavid du Colombier {
8049ef1f84bSDavid du Colombier 	int h, changed;
8059ef1f84bSDavid du Colombier 	char *tag;
8069ef1f84bSDavid du Colombier 	Cmdbuf *cb;
8079ef1f84bSDavid du Colombier 	uchar addr[IPaddrlen];
8089ef1f84bSDavid du Colombier 	uchar mask[IPaddrlen];
8099ef1f84bSDavid du Colombier 	uchar gate[IPaddrlen];
8109ef1f84bSDavid du Colombier 	IPaux *a, *na;
8119ef1f84bSDavid du Colombier 	Route *q;
812*55ba833bSDavid du Colombier 	uchar type;
8139ef1f84bSDavid du Colombier 
8149ef1f84bSDavid du Colombier 	cb = parsecmd(p, n);
8159ef1f84bSDavid du Colombier 	if(waserror()){
8169ef1f84bSDavid du Colombier 		free(cb);
8179ef1f84bSDavid du Colombier 		nexterror();
8189ef1f84bSDavid du Colombier 	}
8199ef1f84bSDavid du Colombier 
8209ef1f84bSDavid du Colombier 	if(strcmp(cb->f[0], "flush") == 0){
8219ef1f84bSDavid du Colombier 		tag = cb->f[1];
8229ef1f84bSDavid du Colombier 		for(h = 0; h < nelem(f->v4root); h++)
8239ef1f84bSDavid du Colombier 			for(changed = 1; changed;){
8249ef1f84bSDavid du Colombier 				wlock(&routelock);
8259ef1f84bSDavid du Colombier 				changed = routeflush(f, f->v4root[h], tag);
8269ef1f84bSDavid du Colombier 				wunlock(&routelock);
8279ef1f84bSDavid du Colombier 			}
8289ef1f84bSDavid du Colombier 		for(h = 0; h < nelem(f->v6root); h++)
8299ef1f84bSDavid du Colombier 			for(changed = 1; changed;){
8309ef1f84bSDavid du Colombier 				wlock(&routelock);
8319ef1f84bSDavid du Colombier 				changed = routeflush(f, f->v6root[h], tag);
8329ef1f84bSDavid du Colombier 				wunlock(&routelock);
8339ef1f84bSDavid du Colombier 			}
8349ef1f84bSDavid du Colombier 	} else if(strcmp(cb->f[0], "remove") == 0){
8359ef1f84bSDavid du Colombier 		if(cb->nf < 3)
8369ef1f84bSDavid du Colombier 			error(Ebadarg);
8379ef1f84bSDavid du Colombier 		if (parseip(addr, cb->f[1]) == -1)
8389ef1f84bSDavid du Colombier 			error(Ebadip);
8399ef1f84bSDavid du Colombier 		parseipmask(mask, cb->f[2]);
8409ef1f84bSDavid du Colombier 		if(memcmp(addr, v4prefix, IPv4off) == 0)
8419ef1f84bSDavid du Colombier 			v4delroute(f, addr+IPv4off, mask+IPv4off, 1);
8429ef1f84bSDavid du Colombier 		else
8439ef1f84bSDavid du Colombier 			v6delroute(f, addr, mask, 1);
8449ef1f84bSDavid du Colombier 	} else if(strcmp(cb->f[0], "add") == 0){
8459ef1f84bSDavid du Colombier 		if(cb->nf < 4)
8469ef1f84bSDavid du Colombier 			error(Ebadarg);
8479ef1f84bSDavid du Colombier 		if(parseip(addr, cb->f[1]) == -1 ||
8489ef1f84bSDavid du Colombier 		    parseip(gate, cb->f[3]) == -1)
8499ef1f84bSDavid du Colombier 			error(Ebadip);
8509ef1f84bSDavid du Colombier 		parseipmask(mask, cb->f[2]);
8519ef1f84bSDavid du Colombier 		tag = "none";
8529ef1f84bSDavid du Colombier 		if(c != nil){
8539ef1f84bSDavid du Colombier 			a = c->aux;
8549ef1f84bSDavid du Colombier 			tag = a->tag;
8559ef1f84bSDavid du Colombier 		}
856*55ba833bSDavid du Colombier 		if(memcmp(addr, v4prefix, IPv4off) == 0){
857*55ba833bSDavid du Colombier 			type = 0;
858*55ba833bSDavid du Colombier 			if(ipcmp(mask, IPallbits) == 0)
859*55ba833bSDavid du Colombier 				type = Rbcast;
860*55ba833bSDavid du Colombier 			v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, type);
861*55ba833bSDavid du Colombier 		}else
8629ef1f84bSDavid du Colombier 			v6addroute(f, tag, addr, mask, gate, 0);
8639ef1f84bSDavid du Colombier 	} else if(strcmp(cb->f[0], "tag") == 0) {
8649ef1f84bSDavid du Colombier 		if(cb->nf < 2)
8659ef1f84bSDavid du Colombier 			error(Ebadarg);
8669ef1f84bSDavid du Colombier 
8679ef1f84bSDavid du Colombier 		a = c->aux;
8689ef1f84bSDavid du Colombier 		na = newipaux(a->owner, cb->f[1]);
8699ef1f84bSDavid du Colombier 		c->aux = na;
8709ef1f84bSDavid du Colombier 		free(a);
8719ef1f84bSDavid du Colombier 	} else if(strcmp(cb->f[0], "route") == 0) {
8729ef1f84bSDavid du Colombier 		if(cb->nf < 2)
8739ef1f84bSDavid du Colombier 			error(Ebadarg);
8749ef1f84bSDavid du Colombier 		if (parseip(addr, cb->f[1]) == -1)
8759ef1f84bSDavid du Colombier 			error(Ebadip);
8769ef1f84bSDavid du Colombier 
8779ef1f84bSDavid du Colombier 		q = iproute(f, addr);
8789ef1f84bSDavid du Colombier 		print("%I: ", addr);
8799ef1f84bSDavid du Colombier 		if(q == nil)
8809ef1f84bSDavid du Colombier 			print("no route\n");
8819ef1f84bSDavid du Colombier 		else
8829ef1f84bSDavid du Colombier 			printroute(q);
8839ef1f84bSDavid du Colombier 	}
8849ef1f84bSDavid du Colombier 
8859ef1f84bSDavid du Colombier 	poperror();
8869ef1f84bSDavid du Colombier 	free(cb);
8879ef1f84bSDavid du Colombier 	return n;
8889ef1f84bSDavid du Colombier }
889