xref: /plan9-contrib/sys/src/9k/ip/ipifc.c (revision a3323688dee1e9a0fcc1d7d933e3ce101170952d)
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 #include "ipv6.h"
109ef1f84bSDavid du Colombier 
119ef1f84bSDavid du Colombier #define DPRINT if(0)print
129ef1f84bSDavid du Colombier 
139ef1f84bSDavid du Colombier enum {
149ef1f84bSDavid du Colombier 	Maxmedia	= 32,
159ef1f84bSDavid du Colombier 	Nself		= Maxmedia*5,
169ef1f84bSDavid du Colombier 	NHASH		= 1<<6,
179ef1f84bSDavid du Colombier 	NCACHE		= 256,
189ef1f84bSDavid du Colombier 	QMAX		= 192*1024-1,
19*a3323688SDavid du Colombier 	Maxv6repr	= (128/(4*4))*(4+1), /* limit of xxxx:xxxx:⋯ notation */
209ef1f84bSDavid du Colombier };
219ef1f84bSDavid du Colombier 
229ef1f84bSDavid du Colombier Medium *media[Maxmedia] = { 0 };
239ef1f84bSDavid du Colombier 
249ef1f84bSDavid du Colombier /*
259ef1f84bSDavid du Colombier  *  cache of local addresses (addresses we answer to)
269ef1f84bSDavid du Colombier  */
279ef1f84bSDavid du Colombier struct Ipself
289ef1f84bSDavid du Colombier {
299ef1f84bSDavid du Colombier 	uchar	a[IPaddrlen];
309ef1f84bSDavid du Colombier 	Ipself	*hnext;		/* next address in the hash table */
319ef1f84bSDavid du Colombier 	Iplink	*link;		/* binding twixt Ipself and Ipifc */
329ef1f84bSDavid du Colombier 	ulong	expire;
339ef1f84bSDavid du Colombier 	uchar	type;		/* type of address */
349ef1f84bSDavid du Colombier 	int	ref;
359ef1f84bSDavid du Colombier 	Ipself	*next;		/* free list */
369ef1f84bSDavid du Colombier };
379ef1f84bSDavid du Colombier 
389ef1f84bSDavid du Colombier struct Ipselftab
399ef1f84bSDavid du Colombier {
409ef1f84bSDavid du Colombier 	QLock;
419ef1f84bSDavid du Colombier 	int	inited;
429ef1f84bSDavid du Colombier 	int	acceptall;	/* true if an interface has the null address */
439ef1f84bSDavid du Colombier 	Ipself	*hash[NHASH];	/* hash chains */
449ef1f84bSDavid du Colombier };
459ef1f84bSDavid du Colombier 
469ef1f84bSDavid du Colombier /*
479ef1f84bSDavid du Colombier  *  Multicast addresses are chained onto a Chan so that
489ef1f84bSDavid du Colombier  *  we can remove them when the Chan is closed.
499ef1f84bSDavid du Colombier  */
509ef1f84bSDavid du Colombier typedef struct Ipmcast Ipmcast;
519ef1f84bSDavid du Colombier struct Ipmcast
529ef1f84bSDavid du Colombier {
539ef1f84bSDavid du Colombier 	Ipmcast	*next;
549ef1f84bSDavid du Colombier 	uchar	ma[IPaddrlen];	/* multicast address */
559ef1f84bSDavid du Colombier 	uchar	ia[IPaddrlen];	/* interface address */
569ef1f84bSDavid du Colombier };
579ef1f84bSDavid du Colombier 
589ef1f84bSDavid du Colombier /* quick hash for ip addresses */
599ef1f84bSDavid du Colombier #define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )
609ef1f84bSDavid du Colombier 
619ef1f84bSDavid du Colombier static char tifc[] = "ifc ";
629ef1f84bSDavid du Colombier 
639ef1f84bSDavid du Colombier static void	addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
649ef1f84bSDavid du Colombier static void	remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
659ef1f84bSDavid du Colombier static char*	ipifcjoinmulti(Ipifc *ifc, char **argv, int argc);
669ef1f84bSDavid du Colombier static char*	ipifcleavemulti(Ipifc *ifc, char **argv, int argc);
679ef1f84bSDavid du Colombier static void	ipifcregisterproxy(Fs*, Ipifc*, uchar*);
689ef1f84bSDavid du Colombier static char*	ipifcremlifc(Ipifc*, Iplifc*);
699ef1f84bSDavid du Colombier 
709ef1f84bSDavid du Colombier /*
719ef1f84bSDavid du Colombier  *  link in a new medium
729ef1f84bSDavid du Colombier  */
739ef1f84bSDavid du Colombier void
addipmedium(Medium * med)749ef1f84bSDavid du Colombier addipmedium(Medium *med)
759ef1f84bSDavid du Colombier {
769ef1f84bSDavid du Colombier 	int i;
779ef1f84bSDavid du Colombier 
789ef1f84bSDavid du Colombier 	for(i = 0; i < nelem(media)-1; i++)
799ef1f84bSDavid du Colombier 		if(media[i] == nil){
809ef1f84bSDavid du Colombier 			media[i] = med;
819ef1f84bSDavid du Colombier 			break;
829ef1f84bSDavid du Colombier 		}
839ef1f84bSDavid du Colombier }
849ef1f84bSDavid du Colombier 
859ef1f84bSDavid du Colombier /*
869ef1f84bSDavid du Colombier  *  find the medium with this name
879ef1f84bSDavid du Colombier  */
889ef1f84bSDavid du Colombier Medium*
ipfindmedium(char * name)899ef1f84bSDavid du Colombier ipfindmedium(char *name)
909ef1f84bSDavid du Colombier {
919ef1f84bSDavid du Colombier 	Medium **mp;
929ef1f84bSDavid du Colombier 
939ef1f84bSDavid du Colombier 	for(mp = media; *mp != nil; mp++)
949ef1f84bSDavid du Colombier 		if(strcmp((*mp)->name, name) == 0)
959ef1f84bSDavid du Colombier 			break;
969ef1f84bSDavid du Colombier 	return *mp;
979ef1f84bSDavid du Colombier }
989ef1f84bSDavid du Colombier 
999ef1f84bSDavid du Colombier /*
1009ef1f84bSDavid du Colombier  *  attach a device (or pkt driver) to the interface.
1019ef1f84bSDavid du Colombier  *  called with c locked
1029ef1f84bSDavid du Colombier  */
1039ef1f84bSDavid du Colombier static char*
ipifcbind(Conv * c,char ** argv,int argc)1049ef1f84bSDavid du Colombier ipifcbind(Conv *c, char **argv, int argc)
1059ef1f84bSDavid du Colombier {
1069ef1f84bSDavid du Colombier 	Ipifc *ifc;
1079ef1f84bSDavid du Colombier 	Medium *medium;
1089ef1f84bSDavid du Colombier 
1099ef1f84bSDavid du Colombier 	if(argc < 2)
1109ef1f84bSDavid du Colombier 		return Ebadarg;
1119ef1f84bSDavid du Colombier 
1129ef1f84bSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
1139ef1f84bSDavid du Colombier 
1149ef1f84bSDavid du Colombier 	/* bind the device to the interface */
1159ef1f84bSDavid du Colombier 	medium = ipfindmedium(argv[1]);
1169ef1f84bSDavid du Colombier 	if(medium == nil)
1179ef1f84bSDavid du Colombier 		return "unknown interface type";
1189ef1f84bSDavid du Colombier 
1199ef1f84bSDavid du Colombier 	wlock(ifc);
1209ef1f84bSDavid du Colombier 	if(ifc->medium != nil){
1219ef1f84bSDavid du Colombier 		wunlock(ifc);
1229ef1f84bSDavid du Colombier 		return "interface already bound";
1239ef1f84bSDavid du Colombier 	}
1249ef1f84bSDavid du Colombier 	if(waserror()){
1259ef1f84bSDavid du Colombier 		wunlock(ifc);
1269ef1f84bSDavid du Colombier 		nexterror();
1279ef1f84bSDavid du Colombier 	}
1289ef1f84bSDavid du Colombier 
1299ef1f84bSDavid du Colombier 	/* do medium specific binding */
1309ef1f84bSDavid du Colombier 	(*medium->bind)(ifc, argc, argv);
1319ef1f84bSDavid du Colombier 
1329ef1f84bSDavid du Colombier 	/* set the bound device name */
1339ef1f84bSDavid du Colombier 	if(argc > 2)
1349ef1f84bSDavid du Colombier 		strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
1359ef1f84bSDavid du Colombier 	else
1369ef1f84bSDavid du Colombier 		snprint(ifc->dev, sizeof ifc->dev, "%s%d", medium->name, c->x);
1379ef1f84bSDavid du Colombier 	ifc->dev[sizeof(ifc->dev)-1] = 0;
1389ef1f84bSDavid du Colombier 
1399ef1f84bSDavid du Colombier 	/* set up parameters */
1409ef1f84bSDavid du Colombier 	ifc->medium = medium;
1419ef1f84bSDavid du Colombier 	ifc->mintu = ifc->medium->mintu;
1429ef1f84bSDavid du Colombier 	ifc->maxtu = ifc->medium->maxtu;
1439ef1f84bSDavid du Colombier 	if(ifc->medium->unbindonclose == 0)
1449ef1f84bSDavid du Colombier 		ifc->conv->inuse++;
1459ef1f84bSDavid du Colombier 	ifc->rp.mflag = 0;		/* default not managed */
1469ef1f84bSDavid du Colombier 	ifc->rp.oflag = 0;
1479ef1f84bSDavid du Colombier 	ifc->rp.maxraint = 600000;	/* millisecs */
1489ef1f84bSDavid du Colombier 	ifc->rp.minraint = 200000;
1499ef1f84bSDavid du Colombier 	ifc->rp.linkmtu = 0;		/* no mtu sent */
1509ef1f84bSDavid du Colombier 	ifc->rp.reachtime = 0;
1519ef1f84bSDavid du Colombier 	ifc->rp.rxmitra = 0;
1529ef1f84bSDavid du Colombier 	ifc->rp.ttl = MAXTTL;
1539ef1f84bSDavid du Colombier 	ifc->rp.routerlt = 3 * ifc->rp.maxraint;
1549ef1f84bSDavid du Colombier 
1559ef1f84bSDavid du Colombier 	/* any ancillary structures (like routes) no longer pertain */
1569ef1f84bSDavid du Colombier 	ifc->ifcid++;
1579ef1f84bSDavid du Colombier 
1589ef1f84bSDavid du Colombier 	/* reopen all the queues closed by a previous unbind */
1599ef1f84bSDavid du Colombier 	qreopen(c->rq);
1609ef1f84bSDavid du Colombier 	qreopen(c->eq);
1619ef1f84bSDavid du Colombier 	qreopen(c->sq);
1629ef1f84bSDavid du Colombier 
1639ef1f84bSDavid du Colombier 	wunlock(ifc);
1649ef1f84bSDavid du Colombier 	poperror();
1659ef1f84bSDavid du Colombier 
1669ef1f84bSDavid du Colombier 	return nil;
1679ef1f84bSDavid du Colombier }
1689ef1f84bSDavid du Colombier 
1699ef1f84bSDavid du Colombier /*
1709ef1f84bSDavid du Colombier  *  detach a device from an interface, close the interface
1719ef1f84bSDavid du Colombier  *  called with ifc->conv closed
1729ef1f84bSDavid du Colombier  */
1739ef1f84bSDavid du Colombier static char*
ipifcunbind(Ipifc * ifc)1749ef1f84bSDavid du Colombier ipifcunbind(Ipifc *ifc)
1759ef1f84bSDavid du Colombier {
1769ef1f84bSDavid du Colombier 	char *err;
1779ef1f84bSDavid du Colombier 
1789ef1f84bSDavid du Colombier 	if(waserror()){
1799ef1f84bSDavid du Colombier 		wunlock(ifc);
1809ef1f84bSDavid du Colombier 		nexterror();
1819ef1f84bSDavid du Colombier 	}
1829ef1f84bSDavid du Colombier 	wlock(ifc);
1839ef1f84bSDavid du Colombier 
1849ef1f84bSDavid du Colombier 	/* dissociate routes */
1859ef1f84bSDavid du Colombier 	if(ifc->medium != nil && ifc->medium->unbindonclose == 0)
1869ef1f84bSDavid du Colombier 		ifc->conv->inuse--;
1879ef1f84bSDavid du Colombier 	ifc->ifcid++;
1889ef1f84bSDavid du Colombier 
1899ef1f84bSDavid du Colombier 	/* disassociate logical interfaces (before zeroing ifc->arg) */
1909ef1f84bSDavid du Colombier 	while(ifc->lifc){
1919ef1f84bSDavid du Colombier 		err = ipifcremlifc(ifc, ifc->lifc);
1929ef1f84bSDavid du Colombier 		/*
1939ef1f84bSDavid du Colombier 		 * note: err non-zero means lifc not found,
1949ef1f84bSDavid du Colombier 		 * which can't happen in this case.
1959ef1f84bSDavid du Colombier 		 */
1969ef1f84bSDavid du Colombier 		if(err)
1979ef1f84bSDavid du Colombier 			error(err);
1989ef1f84bSDavid du Colombier 	}
1999ef1f84bSDavid du Colombier 
2009ef1f84bSDavid du Colombier 	/* disassociate device */
2019ef1f84bSDavid du Colombier 	if(ifc->medium && ifc->medium->unbind)
2029ef1f84bSDavid du Colombier 		(*ifc->medium->unbind)(ifc);
2039ef1f84bSDavid du Colombier 	memset(ifc->dev, 0, sizeof(ifc->dev));
2049ef1f84bSDavid du Colombier 	ifc->arg = nil;
2059ef1f84bSDavid du Colombier 	ifc->reassemble = 0;
2069ef1f84bSDavid du Colombier 
2079ef1f84bSDavid du Colombier 	/* close queues to stop queuing of packets */
2089ef1f84bSDavid du Colombier 	qclose(ifc->conv->rq);
2099ef1f84bSDavid du Colombier 	qclose(ifc->conv->wq);
2109ef1f84bSDavid du Colombier 	qclose(ifc->conv->sq);
2119ef1f84bSDavid du Colombier 
2129ef1f84bSDavid du Colombier 	ifc->medium = nil;
2139ef1f84bSDavid du Colombier 	wunlock(ifc);
2149ef1f84bSDavid du Colombier 	poperror();
2159ef1f84bSDavid du Colombier 	return nil;
2169ef1f84bSDavid du Colombier }
2179ef1f84bSDavid du Colombier 
2189ef1f84bSDavid du Colombier char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag"
2199ef1f84bSDavid du Colombier " %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt"
2209ef1f84bSDavid du Colombier " %d pktin %lud pktout %lud errin %lud errout %lud\n";
2219ef1f84bSDavid du Colombier 
2229ef1f84bSDavid du Colombier char slineformat[] = "	%-40I %-10M %-40I %-12lud %-12lud\n";
2239ef1f84bSDavid du Colombier 
2249ef1f84bSDavid du Colombier static int
ipifcstate(Conv * c,char * state,int n)2259ef1f84bSDavid du Colombier ipifcstate(Conv *c, char *state, int n)
2269ef1f84bSDavid du Colombier {
2279ef1f84bSDavid du Colombier 	Ipifc *ifc;
2289ef1f84bSDavid du Colombier 	Iplifc *lifc;
2299ef1f84bSDavid du Colombier 	char *e, *s;
2309ef1f84bSDavid du Colombier 
2319ef1f84bSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
2329ef1f84bSDavid du Colombier 	s = state;
2339ef1f84bSDavid du Colombier 	e = s+n;
2349ef1f84bSDavid du Colombier 	s = seprint(s, e, sfixedformat,
2359ef1f84bSDavid du Colombier 		ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
2369ef1f84bSDavid du Colombier 		ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
2379ef1f84bSDavid du Colombier 		ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
2389ef1f84bSDavid du Colombier 		ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
2399ef1f84bSDavid du Colombier 		ifc->in, ifc->out, ifc->inerr, ifc->outerr);
2409ef1f84bSDavid du Colombier 
2419ef1f84bSDavid du Colombier 	rlock(ifc);
2429ef1f84bSDavid du Colombier 	for(lifc = ifc->lifc; lifc && s < e; lifc = lifc->next)
2439ef1f84bSDavid du Colombier 		s = seprint(s, e, slineformat, lifc->local,
2449ef1f84bSDavid du Colombier 			lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
2459ef1f84bSDavid du Colombier 	if(ifc->lifc == nil)
2469ef1f84bSDavid du Colombier 		s = seprint(s, e, "\n");
2479ef1f84bSDavid du Colombier 	runlock(ifc);
2489ef1f84bSDavid du Colombier 	return s - state;
2499ef1f84bSDavid du Colombier }
2509ef1f84bSDavid du Colombier 
2519ef1f84bSDavid du Colombier static int
ipifclocal(Conv * c,char * state,int n)2529ef1f84bSDavid du Colombier ipifclocal(Conv *c, char *state, int n)
2539ef1f84bSDavid du Colombier {
2549ef1f84bSDavid du Colombier 	Ipifc *ifc;
2559ef1f84bSDavid du Colombier 	Iplifc *lifc;
2569ef1f84bSDavid du Colombier 	Iplink *link;
2579ef1f84bSDavid du Colombier 	char *e, *s;
2589ef1f84bSDavid du Colombier 
2599ef1f84bSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
2609ef1f84bSDavid du Colombier 	s = state;
2619ef1f84bSDavid du Colombier 	e = s+n;
2629ef1f84bSDavid du Colombier 
2639ef1f84bSDavid du Colombier 	rlock(ifc);
2649ef1f84bSDavid du Colombier 	for(lifc = ifc->lifc; lifc && s < e; lifc = lifc->next){
2659ef1f84bSDavid du Colombier 		s = seprint(s, e, "%-40.40I ->", lifc->local);
2669ef1f84bSDavid du Colombier 		for(link = lifc->link; link; link = link->lifclink)
2679ef1f84bSDavid du Colombier 			s = seprint(s, e, " %-40.40I", link->self->a);
2689ef1f84bSDavid du Colombier 		s = seprint(s, e, "\n");
2699ef1f84bSDavid du Colombier 	}
2709ef1f84bSDavid du Colombier 	runlock(ifc);
2719ef1f84bSDavid du Colombier 	return s - state;
2729ef1f84bSDavid du Colombier }
2739ef1f84bSDavid du Colombier 
2749ef1f84bSDavid du Colombier static int
ipifcinuse(Conv * c)2759ef1f84bSDavid du Colombier ipifcinuse(Conv *c)
2769ef1f84bSDavid du Colombier {
2779ef1f84bSDavid du Colombier 	Ipifc *ifc;
2789ef1f84bSDavid du Colombier 
2799ef1f84bSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
2809ef1f84bSDavid du Colombier 	return ifc->medium != nil;
2819ef1f84bSDavid du Colombier }
2829ef1f84bSDavid du Colombier 
2839ef1f84bSDavid du Colombier /*
2849ef1f84bSDavid du Colombier  *  called when a process writes to an interface's 'data'
2859ef1f84bSDavid du Colombier  */
2869ef1f84bSDavid du Colombier static void
ipifckick(void * x)2879ef1f84bSDavid du Colombier ipifckick(void *x)
2889ef1f84bSDavid du Colombier {
2899ef1f84bSDavid du Colombier 	Conv *c = x;
2909ef1f84bSDavid du Colombier 	Block *bp;
2919ef1f84bSDavid du Colombier 	Ipifc *ifc;
2929ef1f84bSDavid du Colombier 
2939ef1f84bSDavid du Colombier 	bp = qget(c->wq);
2949ef1f84bSDavid du Colombier 	if(bp == nil)
2959ef1f84bSDavid du Colombier 		return;
2969ef1f84bSDavid du Colombier 
2979ef1f84bSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
2989ef1f84bSDavid du Colombier 	if(!canrlock(ifc)){
2999ef1f84bSDavid du Colombier 		freeb(bp);
3009ef1f84bSDavid du Colombier 		return;
3019ef1f84bSDavid du Colombier 	}
3029ef1f84bSDavid du Colombier 	if(waserror()){
3039ef1f84bSDavid du Colombier 		runlock(ifc);
3049ef1f84bSDavid du Colombier 		nexterror();
3059ef1f84bSDavid du Colombier 	}
3069ef1f84bSDavid du Colombier 	if(ifc->medium == nil || ifc->medium->pktin == nil)
3079ef1f84bSDavid du Colombier 		freeb(bp);
3089ef1f84bSDavid du Colombier 	else
3099ef1f84bSDavid du Colombier 		(*ifc->medium->pktin)(c->p->f, ifc, bp);
3109ef1f84bSDavid du Colombier 	runlock(ifc);
3119ef1f84bSDavid du Colombier 	poperror();
3129ef1f84bSDavid du Colombier }
3139ef1f84bSDavid du Colombier 
3149ef1f84bSDavid du Colombier /*
3159ef1f84bSDavid du Colombier  *  called when a new ipifc structure is created
3169ef1f84bSDavid du Colombier  */
3179ef1f84bSDavid du Colombier static void
ipifccreate(Conv * c)3189ef1f84bSDavid du Colombier ipifccreate(Conv *c)
3199ef1f84bSDavid du Colombier {
3209ef1f84bSDavid du Colombier 	Ipifc *ifc;
3219ef1f84bSDavid du Colombier 
3229ef1f84bSDavid du Colombier 	c->rq = qopen(QMAX, 0, 0, 0);
3239ef1f84bSDavid du Colombier 	c->sq = qopen(QMAX, 0, 0, 0);
3249ef1f84bSDavid du Colombier 	c->wq = qopen(QMAX, Qkick, ipifckick, c);
3259ef1f84bSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
3269ef1f84bSDavid du Colombier 	ifc->conv = c;
3279ef1f84bSDavid du Colombier 	ifc->unbinding = 0;
3289ef1f84bSDavid du Colombier 	ifc->medium = nil;
3299ef1f84bSDavid du Colombier 	ifc->reassemble = 0;
3309ef1f84bSDavid du Colombier }
3319ef1f84bSDavid du Colombier 
3329ef1f84bSDavid du Colombier /*
3339ef1f84bSDavid du Colombier  *  called after last close of ipifc data or ctl
3349ef1f84bSDavid du Colombier  *  called with c locked, we must unlock
3359ef1f84bSDavid du Colombier  */
3369ef1f84bSDavid du Colombier static void
ipifcclose(Conv * c)3379ef1f84bSDavid du Colombier ipifcclose(Conv *c)
3389ef1f84bSDavid du Colombier {
3399ef1f84bSDavid du Colombier 	Ipifc *ifc;
3409ef1f84bSDavid du Colombier 	Medium *medium;
3419ef1f84bSDavid du Colombier 
3429ef1f84bSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
3439ef1f84bSDavid du Colombier 	medium = ifc->medium;
3449ef1f84bSDavid du Colombier 	if(medium != nil && medium->unbindonclose)
3459ef1f84bSDavid du Colombier 		ipifcunbind(ifc);
3469ef1f84bSDavid du Colombier }
3479ef1f84bSDavid du Colombier 
3489ef1f84bSDavid du Colombier /*
3499ef1f84bSDavid du Colombier  *  change an interface's mtu
3509ef1f84bSDavid du Colombier  */
3519ef1f84bSDavid du Colombier char*
ipifcsetmtu(Ipifc * ifc,char ** argv,int argc)3529ef1f84bSDavid du Colombier ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
3539ef1f84bSDavid du Colombier {
3549ef1f84bSDavid du Colombier 	int mtu;
3559ef1f84bSDavid du Colombier 
3569ef1f84bSDavid du Colombier 	if(argc < 2 || ifc->medium == nil)
3579ef1f84bSDavid du Colombier 		return Ebadarg;
3589ef1f84bSDavid du Colombier 	mtu = strtoul(argv[1], 0, 0);
3599ef1f84bSDavid du Colombier 	if(mtu < ifc->medium->mintu || mtu > ifc->medium->maxtu)
3609ef1f84bSDavid du Colombier 		return Ebadarg;
3619ef1f84bSDavid du Colombier 	ifc->maxtu = mtu;
3629ef1f84bSDavid du Colombier 	return nil;
3639ef1f84bSDavid du Colombier }
3649ef1f84bSDavid du Colombier 
3659ef1f84bSDavid du Colombier /*
3669ef1f84bSDavid du Colombier  *  add an address to an interface.
3679ef1f84bSDavid du Colombier  */
3689ef1f84bSDavid du Colombier char*
ipifcadd(Ipifc * ifc,char ** argv,int argc,int tentative,Iplifc * lifcp)3699ef1f84bSDavid du Colombier ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
3709ef1f84bSDavid du Colombier {
3719ef1f84bSDavid du Colombier 	int i, type, mtu, sendnbrdisc = 0;
3729ef1f84bSDavid du Colombier 	uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
3739ef1f84bSDavid du Colombier 	uchar bcast[IPaddrlen], net[IPaddrlen];
3749ef1f84bSDavid du Colombier 	Iplifc *lifc, **l;
3759ef1f84bSDavid du Colombier 	Fs *f;
3769ef1f84bSDavid du Colombier 
3779ef1f84bSDavid du Colombier 	if(ifc->medium == nil)
3789ef1f84bSDavid du Colombier 		return "ipifc not yet bound to device";
3799ef1f84bSDavid du Colombier 
3809ef1f84bSDavid du Colombier 	f = ifc->conv->p->f;
3819ef1f84bSDavid du Colombier 
3829ef1f84bSDavid du Colombier 	type = Rifc;
3839ef1f84bSDavid du Colombier 	memset(ip, 0, IPaddrlen);
3849ef1f84bSDavid du Colombier 	memset(mask, 0, IPaddrlen);
3859ef1f84bSDavid du Colombier 	memset(rem, 0, IPaddrlen);
3869ef1f84bSDavid du Colombier 	switch(argc){
3879ef1f84bSDavid du Colombier 	case 6:
3889ef1f84bSDavid du Colombier 		if(strcmp(argv[5], "proxy") == 0)
3899ef1f84bSDavid du Colombier 			type |= Rproxy;
3909ef1f84bSDavid du Colombier 		/* fall through */
3919ef1f84bSDavid du Colombier 	case 5:
3929ef1f84bSDavid du Colombier 		mtu = strtoul(argv[4], 0, 0);
3939ef1f84bSDavid du Colombier 		if(mtu >= ifc->medium->mintu && mtu <= ifc->medium->maxtu)
3949ef1f84bSDavid du Colombier 			ifc->maxtu = mtu;
3959ef1f84bSDavid du Colombier 		/* fall through */
3969ef1f84bSDavid du Colombier 	case 4:
3979ef1f84bSDavid du Colombier 		if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
3989ef1f84bSDavid du Colombier 			return Ebadip;
3999ef1f84bSDavid du Colombier 		parseipmask(mask, argv[2]);
4009ef1f84bSDavid du Colombier 		maskip(rem, mask, net);
4019ef1f84bSDavid du Colombier 		break;
4029ef1f84bSDavid du Colombier 	case 3:
4039ef1f84bSDavid du Colombier 		if (parseip(ip, argv[1]) == -1)
4049ef1f84bSDavid du Colombier 			return Ebadip;
4059ef1f84bSDavid du Colombier 		parseipmask(mask, argv[2]);
4069ef1f84bSDavid du Colombier 		maskip(ip, mask, rem);
4079ef1f84bSDavid du Colombier 		maskip(rem, mask, net);
4089ef1f84bSDavid du Colombier 		break;
4099ef1f84bSDavid du Colombier 	case 2:
4109ef1f84bSDavid du Colombier 		if (parseip(ip, argv[1]) == -1)
4119ef1f84bSDavid du Colombier 			return Ebadip;
4129ef1f84bSDavid du Colombier 		memmove(mask, defmask(ip), IPaddrlen);
4139ef1f84bSDavid du Colombier 		maskip(ip, mask, rem);
4149ef1f84bSDavid du Colombier 		maskip(rem, mask, net);
4159ef1f84bSDavid du Colombier 		break;
4169ef1f84bSDavid du Colombier 	default:
4179ef1f84bSDavid du Colombier 		return Ebadarg;
4189ef1f84bSDavid du Colombier 	}
4199ef1f84bSDavid du Colombier 	if(isv4(ip))
4209ef1f84bSDavid du Colombier 		tentative = 0;
4219ef1f84bSDavid du Colombier 	wlock(ifc);
4229ef1f84bSDavid du Colombier 
4239ef1f84bSDavid du Colombier 	/* ignore if this is already a local address for this ifc */
4249ef1f84bSDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
4259ef1f84bSDavid du Colombier 		if(ipcmp(lifc->local, ip) == 0) {
4269ef1f84bSDavid du Colombier 			if(lifc->tentative != tentative)
4279ef1f84bSDavid du Colombier 				lifc->tentative = tentative;
4289ef1f84bSDavid du Colombier 			if(lifcp) {
4299ef1f84bSDavid du Colombier 				lifc->onlink = lifcp->onlink;
4309ef1f84bSDavid du Colombier 				lifc->autoflag = lifcp->autoflag;
4319ef1f84bSDavid du Colombier 				lifc->validlt = lifcp->validlt;
4329ef1f84bSDavid du Colombier 				lifc->preflt = lifcp->preflt;
4339ef1f84bSDavid du Colombier 				lifc->origint = lifcp->origint;
4349ef1f84bSDavid du Colombier 			}
4359ef1f84bSDavid du Colombier 			goto out;
4369ef1f84bSDavid du Colombier 		}
4379ef1f84bSDavid du Colombier 	}
4389ef1f84bSDavid du Colombier 
4399ef1f84bSDavid du Colombier 	/* add the address to the list of logical ifc's for this ifc */
4409ef1f84bSDavid du Colombier 	lifc = smalloc(sizeof(Iplifc));
4419ef1f84bSDavid du Colombier 	ipmove(lifc->local, ip);
4429ef1f84bSDavid du Colombier 	ipmove(lifc->mask, mask);
4439ef1f84bSDavid du Colombier 	ipmove(lifc->remote, rem);
4449ef1f84bSDavid du Colombier 	ipmove(lifc->net, net);
4459ef1f84bSDavid du Colombier 	lifc->tentative = tentative;
4469ef1f84bSDavid du Colombier 	if(lifcp) {
4479ef1f84bSDavid du Colombier 		lifc->onlink = lifcp->onlink;
4489ef1f84bSDavid du Colombier 		lifc->autoflag = lifcp->autoflag;
4499ef1f84bSDavid du Colombier 		lifc->validlt = lifcp->validlt;
4509ef1f84bSDavid du Colombier 		lifc->preflt = lifcp->preflt;
4519ef1f84bSDavid du Colombier 		lifc->origint = lifcp->origint;
4529ef1f84bSDavid du Colombier 	} else {		/* default values */
4539ef1f84bSDavid du Colombier 		lifc->onlink = lifc->autoflag = 1;
4549ef1f84bSDavid du Colombier 		lifc->validlt = lifc->preflt = ~0L;
4559ef1f84bSDavid du Colombier 		lifc->origint = NOW / 1000;
4569ef1f84bSDavid du Colombier 	}
4579ef1f84bSDavid du Colombier 	lifc->next = nil;
4589ef1f84bSDavid du Colombier 
4599ef1f84bSDavid du Colombier 	for(l = &ifc->lifc; *l; l = &(*l)->next)
4609ef1f84bSDavid du Colombier 		;
4619ef1f84bSDavid du Colombier 	*l = lifc;
4629ef1f84bSDavid du Colombier 
4639ef1f84bSDavid du Colombier 	/* check for point-to-point interface */
4649ef1f84bSDavid du Colombier 	if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
4659ef1f84bSDavid du Colombier 	if(ipcmp(mask, IPallbits) == 0)
4669ef1f84bSDavid du Colombier 		type |= Rptpt;
4679ef1f84bSDavid du Colombier 
4689ef1f84bSDavid du Colombier 	/* add local routes */
4699ef1f84bSDavid du Colombier 	if(isv4(ip))
4709ef1f84bSDavid du Colombier 		v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
4719ef1f84bSDavid du Colombier 	else
4729ef1f84bSDavid du Colombier 		v6addroute(f, tifc, rem, mask, rem, type);
4739ef1f84bSDavid du Colombier 
4749ef1f84bSDavid du Colombier 	addselfcache(f, ifc, lifc, ip, Runi);
4759ef1f84bSDavid du Colombier 
4769ef1f84bSDavid du Colombier 	if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){
4779ef1f84bSDavid du Colombier 		ipifcregisterproxy(f, ifc, rem);
4789ef1f84bSDavid du Colombier 		goto out;
4799ef1f84bSDavid du Colombier 	}
4809ef1f84bSDavid du Colombier 
4819ef1f84bSDavid du Colombier 	if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
4829ef1f84bSDavid du Colombier 		/* add subnet directed broadcast address to the self cache */
4839ef1f84bSDavid du Colombier 		for(i = 0; i < IPaddrlen; i++)
4849ef1f84bSDavid du Colombier 			bcast[i] = (ip[i] & mask[i]) | ~mask[i];
4859ef1f84bSDavid du Colombier 		addselfcache(f, ifc, lifc, bcast, Rbcast);
4869ef1f84bSDavid du Colombier 
4879ef1f84bSDavid du Colombier 		/* add subnet directed network address to the self cache */
4889ef1f84bSDavid du Colombier 		for(i = 0; i < IPaddrlen; i++)
4899ef1f84bSDavid du Colombier 			bcast[i] = (ip[i] & mask[i]) & mask[i];
4909ef1f84bSDavid du Colombier 		addselfcache(f, ifc, lifc, bcast, Rbcast);
4919ef1f84bSDavid du Colombier 
4929ef1f84bSDavid du Colombier 		/* add network directed broadcast address to the self cache */
4939ef1f84bSDavid du Colombier 		memmove(mask, defmask(ip), IPaddrlen);
4949ef1f84bSDavid du Colombier 		for(i = 0; i < IPaddrlen; i++)
4959ef1f84bSDavid du Colombier 			bcast[i] = (ip[i] & mask[i]) | ~mask[i];
4969ef1f84bSDavid du Colombier 		addselfcache(f, ifc, lifc, bcast, Rbcast);
4979ef1f84bSDavid du Colombier 
4989ef1f84bSDavid du Colombier 		/* add network directed network address to the self cache */
4999ef1f84bSDavid du Colombier 		memmove(mask, defmask(ip), IPaddrlen);
5009ef1f84bSDavid du Colombier 		for(i = 0; i < IPaddrlen; i++)
5019ef1f84bSDavid du Colombier 			bcast[i] = (ip[i] & mask[i]) & mask[i];
5029ef1f84bSDavid du Colombier 		addselfcache(f, ifc, lifc, bcast, Rbcast);
5039ef1f84bSDavid du Colombier 
5049ef1f84bSDavid du Colombier 		addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
5059ef1f84bSDavid du Colombier 	}
5069ef1f84bSDavid du Colombier 	else {
5079ef1f84bSDavid du Colombier 		if(ipcmp(ip, v6loopback) == 0) {
5089ef1f84bSDavid du Colombier 			/* add node-local mcast address */
5099ef1f84bSDavid du Colombier 			addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
5109ef1f84bSDavid du Colombier 
5119ef1f84bSDavid du Colombier 			/* add route for all node multicast */
5129ef1f84bSDavid du Colombier 			v6addroute(f, tifc, v6allnodesN, v6allnodesNmask,
5139ef1f84bSDavid du Colombier 				v6allnodesN, Rmulti);
5149ef1f84bSDavid du Colombier 		}
5159ef1f84bSDavid du Colombier 
5169ef1f84bSDavid du Colombier 		/* add all nodes multicast address */
5179ef1f84bSDavid du Colombier 		addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
5189ef1f84bSDavid du Colombier 
5199ef1f84bSDavid du Colombier 		/* add route for all nodes multicast */
5209ef1f84bSDavid du Colombier 		v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL,
5219ef1f84bSDavid du Colombier 			Rmulti);
5229ef1f84bSDavid du Colombier 
5239ef1f84bSDavid du Colombier 		/* add solicited-node multicast address */
5249ef1f84bSDavid du Colombier 		ipv62smcast(bcast, ip);
5259ef1f84bSDavid du Colombier 		addselfcache(f, ifc, lifc, bcast, Rmulti);
5269ef1f84bSDavid du Colombier 
5279ef1f84bSDavid du Colombier 		sendnbrdisc = 1;
5289ef1f84bSDavid du Colombier 	}
5299ef1f84bSDavid du Colombier 
5309ef1f84bSDavid du Colombier 	/* register the address on this network for address resolution */
5319ef1f84bSDavid du Colombier 	if(isv4(ip) && ifc->medium->areg != nil)
5329ef1f84bSDavid du Colombier 		(*ifc->medium->areg)(ifc, ip);
5339ef1f84bSDavid du Colombier 
5349ef1f84bSDavid du Colombier out:
5359ef1f84bSDavid du Colombier 	wunlock(ifc);
5369ef1f84bSDavid du Colombier 	if(tentative && sendnbrdisc)
5379ef1f84bSDavid du Colombier 		icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
5389ef1f84bSDavid du Colombier 	return nil;
5399ef1f84bSDavid du Colombier }
5409ef1f84bSDavid du Colombier 
5419ef1f84bSDavid du Colombier /*
5429ef1f84bSDavid du Colombier  *  remove a logical interface from an ifc
5439ef1f84bSDavid du Colombier  *  always called with ifc wlock'd
5449ef1f84bSDavid du Colombier  */
5459ef1f84bSDavid du Colombier static char*
ipifcremlifc(Ipifc * ifc,Iplifc * lifc)5469ef1f84bSDavid du Colombier ipifcremlifc(Ipifc *ifc, Iplifc *lifc)
5479ef1f84bSDavid du Colombier {
5489ef1f84bSDavid du Colombier 	Iplifc **l;
5499ef1f84bSDavid du Colombier 	Fs *f;
5509ef1f84bSDavid du Colombier 
5519ef1f84bSDavid du Colombier 	f = ifc->conv->p->f;
5529ef1f84bSDavid du Colombier 
5539ef1f84bSDavid du Colombier 	/*
5549ef1f84bSDavid du Colombier 	 *  find address on this interface and remove from chain.
5559ef1f84bSDavid du Colombier 	 *  for pt to pt we actually specify the remote address as the
5569ef1f84bSDavid du Colombier 	 *  addresss to remove.
5579ef1f84bSDavid du Colombier 	 */
5589ef1f84bSDavid du Colombier 	for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next)
5599ef1f84bSDavid du Colombier 		;
5609ef1f84bSDavid du Colombier 	if(*l == nil)
5619ef1f84bSDavid du Colombier 		return "address not on this interface";
5629ef1f84bSDavid du Colombier 	*l = lifc->next;
5639ef1f84bSDavid du Colombier 
5649ef1f84bSDavid du Colombier 	/* disassociate any addresses */
5659ef1f84bSDavid du Colombier 	while(lifc->link)
5669ef1f84bSDavid du Colombier 		remselfcache(f, ifc, lifc, lifc->link->self->a);
5679ef1f84bSDavid du Colombier 
5689ef1f84bSDavid du Colombier 	/* remove the route for this logical interface */
5699ef1f84bSDavid du Colombier 	if(isv4(lifc->local))
5709ef1f84bSDavid du Colombier 		v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
5719ef1f84bSDavid du Colombier 	else {
5729ef1f84bSDavid du Colombier 		v6delroute(f, lifc->remote, lifc->mask, 1);
5739ef1f84bSDavid du Colombier 		if(ipcmp(lifc->local, v6loopback) == 0)
5749ef1f84bSDavid du Colombier 			/* remove route for all node multicast */
5759ef1f84bSDavid du Colombier 			v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
5769ef1f84bSDavid du Colombier 		else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
5779ef1f84bSDavid du Colombier 			/* remove route for all link multicast */
5789ef1f84bSDavid du Colombier 			v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
5799ef1f84bSDavid du Colombier 	}
5809ef1f84bSDavid du Colombier 
5819ef1f84bSDavid du Colombier 	free(lifc);
5829ef1f84bSDavid du Colombier 	return nil;
5839ef1f84bSDavid du Colombier }
5849ef1f84bSDavid du Colombier 
5859ef1f84bSDavid du Colombier /*
5869ef1f84bSDavid du Colombier  *  remove an address from an interface.
5879ef1f84bSDavid du Colombier  *  called with c->car locked
5889ef1f84bSDavid du Colombier  */
5899ef1f84bSDavid du Colombier char*
ipifcrem(Ipifc * ifc,char ** argv,int argc)5909ef1f84bSDavid du Colombier ipifcrem(Ipifc *ifc, char **argv, int argc)
5919ef1f84bSDavid du Colombier {
5929ef1f84bSDavid du Colombier 	char *rv;
5939ef1f84bSDavid du Colombier 	uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
5949ef1f84bSDavid du Colombier 	Iplifc *lifc;
5959ef1f84bSDavid du Colombier 
5969ef1f84bSDavid du Colombier 	if(argc < 3)
5979ef1f84bSDavid du Colombier 		return Ebadarg;
5989ef1f84bSDavid du Colombier 
5999ef1f84bSDavid du Colombier 	if (parseip(ip, argv[1]) == -1)
6009ef1f84bSDavid du Colombier 		return Ebadip;
6019ef1f84bSDavid du Colombier 	parseipmask(mask, argv[2]);
6029ef1f84bSDavid du Colombier 	if(argc < 4)
6039ef1f84bSDavid du Colombier 		maskip(ip, mask, rem);
6049ef1f84bSDavid du Colombier 	else
6059ef1f84bSDavid du Colombier 		if (parseip(rem, argv[3]) == -1)
6069ef1f84bSDavid du Colombier 			return Ebadip;
6079ef1f84bSDavid du Colombier 
6089ef1f84bSDavid du Colombier 	wlock(ifc);
6099ef1f84bSDavid du Colombier 
6109ef1f84bSDavid du Colombier 	/*
6119ef1f84bSDavid du Colombier 	 *  find address on this interface and remove from chain.
6129ef1f84bSDavid du Colombier 	 *  for pt to pt we actually specify the remote address as the
6139ef1f84bSDavid du Colombier 	 *  addresss to remove.
6149ef1f84bSDavid du Colombier 	 */
6159ef1f84bSDavid du Colombier 	for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
6169ef1f84bSDavid du Colombier 		if (memcmp(ip, lifc->local, IPaddrlen) == 0
6179ef1f84bSDavid du Colombier 		&& memcmp(mask, lifc->mask, IPaddrlen) == 0
6189ef1f84bSDavid du Colombier 		&& memcmp(rem, lifc->remote, IPaddrlen) == 0)
6199ef1f84bSDavid du Colombier 			break;
6209ef1f84bSDavid du Colombier 	}
6219ef1f84bSDavid du Colombier 
6229ef1f84bSDavid du Colombier 	rv = ipifcremlifc(ifc, lifc);
6239ef1f84bSDavid du Colombier 	wunlock(ifc);
6249ef1f84bSDavid du Colombier 	return rv;
6259ef1f84bSDavid du Colombier }
6269ef1f84bSDavid du Colombier 
6279ef1f84bSDavid du Colombier /*
6289ef1f84bSDavid du Colombier  * distribute routes to active interfaces like the
6299ef1f84bSDavid du Colombier  * TRIP linecards
6309ef1f84bSDavid du Colombier  */
6319ef1f84bSDavid du Colombier void
ipifcaddroute(Fs * f,int vers,uchar * addr,uchar * mask,uchar * gate,int type)6329ef1f84bSDavid du Colombier ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
6339ef1f84bSDavid du Colombier {
6349ef1f84bSDavid du Colombier 	Medium *medium;
6359ef1f84bSDavid du Colombier 	Conv **cp, **e;
6369ef1f84bSDavid du Colombier 	Ipifc *ifc;
6379ef1f84bSDavid du Colombier 
6389ef1f84bSDavid du Colombier 	e = &f->ipifc->conv[f->ipifc->nc];
6399ef1f84bSDavid du Colombier 	for(cp = f->ipifc->conv; cp < e; cp++){
6409ef1f84bSDavid du Colombier 		if(*cp != nil) {
6419ef1f84bSDavid du Colombier 			ifc = (Ipifc*)(*cp)->ptcl;
6429ef1f84bSDavid du Colombier 			medium = ifc->medium;
6439ef1f84bSDavid du Colombier 			if(medium != nil && medium->addroute != nil)
6449ef1f84bSDavid du Colombier 				medium->addroute(ifc, vers, addr, mask, gate, type);
6459ef1f84bSDavid du Colombier 		}
6469ef1f84bSDavid du Colombier 	}
6479ef1f84bSDavid du Colombier }
6489ef1f84bSDavid du Colombier 
6499ef1f84bSDavid du Colombier void
ipifcremroute(Fs * f,int vers,uchar * addr,uchar * mask)6509ef1f84bSDavid du Colombier ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
6519ef1f84bSDavid du Colombier {
6529ef1f84bSDavid du Colombier 	Medium *medium;
6539ef1f84bSDavid du Colombier 	Conv **cp, **e;
6549ef1f84bSDavid du Colombier 	Ipifc *ifc;
6559ef1f84bSDavid du Colombier 
6569ef1f84bSDavid du Colombier 	e = &f->ipifc->conv[f->ipifc->nc];
6579ef1f84bSDavid du Colombier 	for(cp = f->ipifc->conv; cp < e; cp++){
6589ef1f84bSDavid du Colombier 		if(*cp != nil) {
6599ef1f84bSDavid du Colombier 			ifc = (Ipifc*)(*cp)->ptcl;
6609ef1f84bSDavid du Colombier 			medium = ifc->medium;
6619ef1f84bSDavid du Colombier 			if(medium != nil && medium->remroute != nil)
6629ef1f84bSDavid du Colombier 				medium->remroute(ifc, vers, addr, mask);
6639ef1f84bSDavid du Colombier 		}
6649ef1f84bSDavid du Colombier 	}
6659ef1f84bSDavid du Colombier }
6669ef1f84bSDavid du Colombier 
6679ef1f84bSDavid du Colombier /*
6689ef1f84bSDavid du Colombier  *  associate an address with the interface.  This wipes out any previous
6699ef1f84bSDavid du Colombier  *  addresses.  This is a macro that means, remove all the old interfaces
6709ef1f84bSDavid du Colombier  *  and add a new one.
6719ef1f84bSDavid du Colombier  */
6729ef1f84bSDavid du Colombier static char*
ipifcconnect(Conv * c,char ** argv,int argc)6739ef1f84bSDavid du Colombier ipifcconnect(Conv* c, char **argv, int argc)
6749ef1f84bSDavid du Colombier {
6759ef1f84bSDavid du Colombier 	char *err;
6769ef1f84bSDavid du Colombier 	Ipifc *ifc;
6779ef1f84bSDavid du Colombier 
6789ef1f84bSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
6799ef1f84bSDavid du Colombier 
6809ef1f84bSDavid du Colombier 	if(ifc->medium == nil)
6819ef1f84bSDavid du Colombier 		 return "ipifc not yet bound to device";
6829ef1f84bSDavid du Colombier 
6839ef1f84bSDavid du Colombier 	if(waserror()){
6849ef1f84bSDavid du Colombier 		wunlock(ifc);
6859ef1f84bSDavid du Colombier 		nexterror();
6869ef1f84bSDavid du Colombier 	}
6879ef1f84bSDavid du Colombier 	wlock(ifc);
6889ef1f84bSDavid du Colombier 	while(ifc->lifc){
6899ef1f84bSDavid du Colombier 		err = ipifcremlifc(ifc, ifc->lifc);
6909ef1f84bSDavid du Colombier 		if(err)
6919ef1f84bSDavid du Colombier 			error(err);
6929ef1f84bSDavid du Colombier 	}
6939ef1f84bSDavid du Colombier 	wunlock(ifc);
6949ef1f84bSDavid du Colombier 	poperror();
6959ef1f84bSDavid du Colombier 
6969ef1f84bSDavid du Colombier 	err = ipifcadd(ifc, argv, argc, 0, nil);
6979ef1f84bSDavid du Colombier 	if(err)
6989ef1f84bSDavid du Colombier 		return err;
6999ef1f84bSDavid du Colombier 
7009ef1f84bSDavid du Colombier 	Fsconnected(c, nil);
7019ef1f84bSDavid du Colombier 	return nil;
7029ef1f84bSDavid du Colombier }
7039ef1f84bSDavid du Colombier 
7049ef1f84bSDavid du Colombier char*
ipifcra6(Ipifc * ifc,char ** argv,int argc)7059ef1f84bSDavid du Colombier ipifcra6(Ipifc *ifc, char **argv, int argc)
7069ef1f84bSDavid du Colombier {
7079ef1f84bSDavid du Colombier 	int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
7089ef1f84bSDavid du Colombier 
7099ef1f84bSDavid du Colombier 	argsleft = argc - 1;
7109ef1f84bSDavid du Colombier 	i = 1;
7119ef1f84bSDavid du Colombier 
7129ef1f84bSDavid du Colombier 	if(argsleft % 2 != 0)
7139ef1f84bSDavid du Colombier 		return Ebadarg;
7149ef1f84bSDavid du Colombier 
7159ef1f84bSDavid du Colombier 	while (argsleft > 1) {
7169ef1f84bSDavid du Colombier 		if(strcmp(argv[i], "recvra") == 0)
7179ef1f84bSDavid du Colombier 			ifc->recvra6 = (atoi(argv[i+1]) != 0);
7189ef1f84bSDavid du Colombier 		else if(strcmp(argv[i], "sendra") == 0)
7199ef1f84bSDavid du Colombier 			ifc->sendra6 = (atoi(argv[i+1]) != 0);
7209ef1f84bSDavid du Colombier 		else if(strcmp(argv[i], "mflag") == 0)
7219ef1f84bSDavid du Colombier 			ifc->rp.mflag = (atoi(argv[i+1]) != 0);
7229ef1f84bSDavid du Colombier 		else if(strcmp(argv[i], "oflag") == 0)
7239ef1f84bSDavid du Colombier 			ifc->rp.oflag = (atoi(argv[i+1]) != 0);
7249ef1f84bSDavid du Colombier 		else if(strcmp(argv[i], "maxraint") == 0)
7259ef1f84bSDavid du Colombier 			ifc->rp.maxraint = atoi(argv[i+1]);
7269ef1f84bSDavid du Colombier 		else if(strcmp(argv[i], "minraint") == 0)
7279ef1f84bSDavid du Colombier 			ifc->rp.minraint = atoi(argv[i+1]);
7289ef1f84bSDavid du Colombier 		else if(strcmp(argv[i], "linkmtu") == 0)
7299ef1f84bSDavid du Colombier 			ifc->rp.linkmtu = atoi(argv[i+1]);
7309ef1f84bSDavid du Colombier 		else if(strcmp(argv[i], "reachtime") == 0)
7319ef1f84bSDavid du Colombier 			ifc->rp.reachtime = atoi(argv[i+1]);
7329ef1f84bSDavid du Colombier 		else if(strcmp(argv[i], "rxmitra") == 0)
7339ef1f84bSDavid du Colombier 			ifc->rp.rxmitra = atoi(argv[i+1]);
7349ef1f84bSDavid du Colombier 		else if(strcmp(argv[i], "ttl") == 0)
7359ef1f84bSDavid du Colombier 			ifc->rp.ttl = atoi(argv[i+1]);
7369ef1f84bSDavid du Colombier 		else if(strcmp(argv[i], "routerlt") == 0)
7379ef1f84bSDavid du Colombier 			ifc->rp.routerlt = atoi(argv[i+1]);
7389ef1f84bSDavid du Colombier 		else
7399ef1f84bSDavid du Colombier 			return Ebadarg;
7409ef1f84bSDavid du Colombier 
7419ef1f84bSDavid du Colombier 		argsleft -= 2;
7429ef1f84bSDavid du Colombier 		i += 2;
7439ef1f84bSDavid du Colombier 	}
7449ef1f84bSDavid du Colombier 
7459ef1f84bSDavid du Colombier 	/* consistency check */
7469ef1f84bSDavid du Colombier 	if(ifc->rp.maxraint < ifc->rp.minraint) {
7479ef1f84bSDavid du Colombier 		ifc->rp.maxraint = vmax;
7489ef1f84bSDavid du Colombier 		ifc->rp.minraint = vmin;
7499ef1f84bSDavid du Colombier 		return Ebadarg;
7509ef1f84bSDavid du Colombier 	}
7519ef1f84bSDavid du Colombier 	return nil;
7529ef1f84bSDavid du Colombier }
7539ef1f84bSDavid du Colombier 
7549ef1f84bSDavid du Colombier /*
7559ef1f84bSDavid du Colombier  *  non-standard control messages.
7569ef1f84bSDavid du Colombier  *  called with c->car locked.
7579ef1f84bSDavid du Colombier  */
7589ef1f84bSDavid du Colombier static char*
ipifcctl(Conv * c,char ** argv,int argc)7599ef1f84bSDavid du Colombier ipifcctl(Conv* c, char**argv, int argc)
7609ef1f84bSDavid du Colombier {
7619ef1f84bSDavid du Colombier 	Ipifc *ifc;
7629ef1f84bSDavid du Colombier 	int i;
7639ef1f84bSDavid du Colombier 
7649ef1f84bSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
7659ef1f84bSDavid du Colombier 	if(strcmp(argv[0], "add") == 0)
7669ef1f84bSDavid du Colombier 		return ipifcadd(ifc, argv, argc, 0, nil);
7679ef1f84bSDavid du Colombier 	else if(strcmp(argv[0], "try") == 0)
7689ef1f84bSDavid du Colombier 		return ipifcadd(ifc, argv, argc, 1, nil);
7699ef1f84bSDavid du Colombier 	else if(strcmp(argv[0], "remove") == 0)
7709ef1f84bSDavid du Colombier 		return ipifcrem(ifc, argv, argc);
7719ef1f84bSDavid du Colombier 	else if(strcmp(argv[0], "unbind") == 0)
7729ef1f84bSDavid du Colombier 		return ipifcunbind(ifc);
7739ef1f84bSDavid du Colombier 	else if(strcmp(argv[0], "joinmulti") == 0)
7749ef1f84bSDavid du Colombier 		return ipifcjoinmulti(ifc, argv, argc);
7759ef1f84bSDavid du Colombier 	else if(strcmp(argv[0], "leavemulti") == 0)
7769ef1f84bSDavid du Colombier 		return ipifcleavemulti(ifc, argv, argc);
7779ef1f84bSDavid du Colombier 	else if(strcmp(argv[0], "mtu") == 0)
7789ef1f84bSDavid du Colombier 		return ipifcsetmtu(ifc, argv, argc);
7799ef1f84bSDavid du Colombier 	else if(strcmp(argv[0], "reassemble") == 0){
7809ef1f84bSDavid du Colombier 		ifc->reassemble = 1;
7819ef1f84bSDavid du Colombier 		return nil;
7829ef1f84bSDavid du Colombier 	}
7839ef1f84bSDavid du Colombier 	else if(strcmp(argv[0], "iprouting") == 0){
7849ef1f84bSDavid du Colombier 		i = 1;
7859ef1f84bSDavid du Colombier 		if(argc > 1)
7869ef1f84bSDavid du Colombier 			i = atoi(argv[1]);
7879ef1f84bSDavid du Colombier 		iprouting(c->p->f, i);
7889ef1f84bSDavid du Colombier 		return nil;
7899ef1f84bSDavid du Colombier 	}
7909ef1f84bSDavid du Colombier 	else if(strcmp(argv[0], "add6") == 0)
7919ef1f84bSDavid du Colombier 		return ipifcadd6(ifc, argv, argc);
7929ef1f84bSDavid du Colombier 	else if(strcmp(argv[0], "ra6") == 0)
7939ef1f84bSDavid du Colombier 		return ipifcra6(ifc, argv, argc);
7949ef1f84bSDavid du Colombier 	return "unsupported ctl";
7959ef1f84bSDavid du Colombier }
7969ef1f84bSDavid du Colombier 
7979ef1f84bSDavid du Colombier int
ipifcstats(Proto * ipifc,char * buf,int len)7989ef1f84bSDavid du Colombier ipifcstats(Proto *ipifc, char *buf, int len)
7999ef1f84bSDavid du Colombier {
8009ef1f84bSDavid du Colombier 	return ipstats(ipifc->f, buf, len);
8019ef1f84bSDavid du Colombier }
8029ef1f84bSDavid du Colombier 
8039ef1f84bSDavid du Colombier void
ipifcinit(Fs * f)8049ef1f84bSDavid du Colombier ipifcinit(Fs *f)
8059ef1f84bSDavid du Colombier {
8069ef1f84bSDavid du Colombier 	Proto *ipifc;
8079ef1f84bSDavid du Colombier 
8089ef1f84bSDavid du Colombier 	ipifc = smalloc(sizeof(Proto));
8099ef1f84bSDavid du Colombier 	ipifc->name = "ipifc";
8109ef1f84bSDavid du Colombier 	ipifc->connect = ipifcconnect;
8119ef1f84bSDavid du Colombier 	ipifc->announce = nil;
8129ef1f84bSDavid du Colombier 	ipifc->bind = ipifcbind;
8139ef1f84bSDavid du Colombier 	ipifc->state = ipifcstate;
8149ef1f84bSDavid du Colombier 	ipifc->create = ipifccreate;
8159ef1f84bSDavid du Colombier 	ipifc->close = ipifcclose;
8169ef1f84bSDavid du Colombier 	ipifc->rcv = nil;
8179ef1f84bSDavid du Colombier 	ipifc->ctl = ipifcctl;
8189ef1f84bSDavid du Colombier 	ipifc->advise = nil;
8199ef1f84bSDavid du Colombier 	ipifc->stats = ipifcstats;
8209ef1f84bSDavid du Colombier 	ipifc->inuse = ipifcinuse;
8219ef1f84bSDavid du Colombier 	ipifc->local = ipifclocal;
8229ef1f84bSDavid du Colombier 	ipifc->ipproto = -1;
8239ef1f84bSDavid du Colombier 	ipifc->nc = Maxmedia;
8249ef1f84bSDavid du Colombier 	ipifc->ptclsize = sizeof(Ipifc);
8259ef1f84bSDavid du Colombier 
8269ef1f84bSDavid du Colombier 	f->ipifc = ipifc;	/* hack for ipifcremroute, findipifc, ... */
8279ef1f84bSDavid du Colombier 	f->self = smalloc(sizeof(Ipselftab));	/* hack for ipforme */
8289ef1f84bSDavid du Colombier 
8299ef1f84bSDavid du Colombier 	Fsproto(f, ipifc);
8309ef1f84bSDavid du Colombier }
8319ef1f84bSDavid du Colombier 
8329ef1f84bSDavid du Colombier /*
8339ef1f84bSDavid du Colombier  *  add to self routing cache
8349ef1f84bSDavid du Colombier  *	called with c->car locked
8359ef1f84bSDavid du Colombier  */
8369ef1f84bSDavid du Colombier static void
addselfcache(Fs * f,Ipifc * ifc,Iplifc * lifc,uchar * a,int type)8379ef1f84bSDavid du Colombier addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
8389ef1f84bSDavid du Colombier {
8399ef1f84bSDavid du Colombier 	Ipself *p;
8409ef1f84bSDavid du Colombier 	Iplink *lp;
8419ef1f84bSDavid du Colombier 	int h;
8429ef1f84bSDavid du Colombier 
8439ef1f84bSDavid du Colombier 	qlock(f->self);
8449ef1f84bSDavid du Colombier 
8459ef1f84bSDavid du Colombier 	/* see if the address already exists */
8469ef1f84bSDavid du Colombier 	h = hashipa(a);
8479ef1f84bSDavid du Colombier 	for(p = f->self->hash[h]; p; p = p->next)
8489ef1f84bSDavid du Colombier 		if(memcmp(a, p->a, IPaddrlen) == 0)
8499ef1f84bSDavid du Colombier 			break;
8509ef1f84bSDavid du Colombier 
8519ef1f84bSDavid du Colombier 	/* allocate a local address and add to hash chain */
8529ef1f84bSDavid du Colombier 	if(p == nil){
8539ef1f84bSDavid du Colombier 		p = smalloc(sizeof(*p));
8549ef1f84bSDavid du Colombier 		ipmove(p->a, a);
8559ef1f84bSDavid du Colombier 		p->type = type;
8569ef1f84bSDavid du Colombier 		p->next = f->self->hash[h];
8579ef1f84bSDavid du Colombier 		f->self->hash[h] = p;
8589ef1f84bSDavid du Colombier 
8599ef1f84bSDavid du Colombier 		/* if the null address, accept all packets */
8609ef1f84bSDavid du Colombier 		if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
8619ef1f84bSDavid du Colombier 			f->self->acceptall = 1;
8629ef1f84bSDavid du Colombier 	}
8639ef1f84bSDavid du Colombier 
8649ef1f84bSDavid du Colombier 	/* look for a link for this lifc */
8659ef1f84bSDavid du Colombier 	for(lp = p->link; lp; lp = lp->selflink)
8669ef1f84bSDavid du Colombier 		if(lp->lifc == lifc)
8679ef1f84bSDavid du Colombier 			break;
8689ef1f84bSDavid du Colombier 
8699ef1f84bSDavid du Colombier 	/* allocate a lifc-to-local link and link to both */
8709ef1f84bSDavid du Colombier 	if(lp == nil){
8719ef1f84bSDavid du Colombier 		lp = smalloc(sizeof(*lp));
8729ef1f84bSDavid du Colombier 		lp->ref = 1;
8739ef1f84bSDavid du Colombier 		lp->lifc = lifc;
8749ef1f84bSDavid du Colombier 		lp->self = p;
8759ef1f84bSDavid du Colombier 		lp->selflink = p->link;
8769ef1f84bSDavid du Colombier 		p->link = lp;
8779ef1f84bSDavid du Colombier 		lp->lifclink = lifc->link;
8789ef1f84bSDavid du Colombier 		lifc->link = lp;
8799ef1f84bSDavid du Colombier 
8809ef1f84bSDavid du Colombier 		/* add to routing table */
8819ef1f84bSDavid du Colombier 		if(isv4(a))
8829ef1f84bSDavid du Colombier 			v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off,
8839ef1f84bSDavid du Colombier 				a+IPv4off, type);
8849ef1f84bSDavid du Colombier 		else
8859ef1f84bSDavid du Colombier 			v6addroute(f, tifc, a, IPallbits, a, type);
8869ef1f84bSDavid du Colombier 
8879ef1f84bSDavid du Colombier 		if((type & Rmulti) && ifc->medium->addmulti != nil)
8889ef1f84bSDavid du Colombier 			(*ifc->medium->addmulti)(ifc, a, lifc->local);
8899ef1f84bSDavid du Colombier 	} else
8909ef1f84bSDavid du Colombier 		lp->ref++;
8919ef1f84bSDavid du Colombier 
8929ef1f84bSDavid du Colombier 	qunlock(f->self);
8939ef1f84bSDavid du Colombier }
8949ef1f84bSDavid du Colombier 
8959ef1f84bSDavid du Colombier /*
8969ef1f84bSDavid du Colombier  *  These structures are unlinked from their chains while
8979ef1f84bSDavid du Colombier  *  other threads may be using them.  To avoid excessive locking,
8989ef1f84bSDavid du Colombier  *  just put them aside for a while before freeing them.
8999ef1f84bSDavid du Colombier  *	called with f->self locked
9009ef1f84bSDavid du Colombier  */
9019ef1f84bSDavid du Colombier static Iplink *freeiplink;
9029ef1f84bSDavid du Colombier static Ipself *freeipself;
9039ef1f84bSDavid du Colombier 
9049ef1f84bSDavid du Colombier static void
iplinkfree(Iplink * p)9059ef1f84bSDavid du Colombier iplinkfree(Iplink *p)
9069ef1f84bSDavid du Colombier {
9079ef1f84bSDavid du Colombier 	Iplink **l, *np;
9089ef1f84bSDavid du Colombier 	ulong now = NOW;
9099ef1f84bSDavid du Colombier 
9109ef1f84bSDavid du Colombier 	l = &freeiplink;
9119ef1f84bSDavid du Colombier 	for(np = *l; np; np = *l){
9129ef1f84bSDavid du Colombier 		if(np->expire > now){
9139ef1f84bSDavid du Colombier 			*l = np->next;
9149ef1f84bSDavid du Colombier 			free(np);
9159ef1f84bSDavid du Colombier 			continue;
9169ef1f84bSDavid du Colombier 		}
9179ef1f84bSDavid du Colombier 		l = &np->next;
9189ef1f84bSDavid du Colombier 	}
9199ef1f84bSDavid du Colombier 	p->expire = now + 5000;	/* give other threads 5 secs to get out */
9209ef1f84bSDavid du Colombier 	p->next = nil;
9219ef1f84bSDavid du Colombier 	*l = p;
9229ef1f84bSDavid du Colombier }
9239ef1f84bSDavid du Colombier 
9249ef1f84bSDavid du Colombier static void
ipselffree(Ipself * p)9259ef1f84bSDavid du Colombier ipselffree(Ipself *p)
9269ef1f84bSDavid du Colombier {
9279ef1f84bSDavid du Colombier 	Ipself **l, *np;
9289ef1f84bSDavid du Colombier 	ulong now = NOW;
9299ef1f84bSDavid du Colombier 
9309ef1f84bSDavid du Colombier 	l = &freeipself;
9319ef1f84bSDavid du Colombier 	for(np = *l; np; np = *l){
9329ef1f84bSDavid du Colombier 		if(np->expire > now){
9339ef1f84bSDavid du Colombier 			*l = np->next;
9349ef1f84bSDavid du Colombier 			free(np);
9359ef1f84bSDavid du Colombier 			continue;
9369ef1f84bSDavid du Colombier 		}
9379ef1f84bSDavid du Colombier 		l = &np->next;
9389ef1f84bSDavid du Colombier 	}
9399ef1f84bSDavid du Colombier 	p->expire = now + 5000;	/* give other threads 5 secs to get out */
9409ef1f84bSDavid du Colombier 	p->next = nil;
9419ef1f84bSDavid du Colombier 	*l = p;
9429ef1f84bSDavid du Colombier }
9439ef1f84bSDavid du Colombier 
9449ef1f84bSDavid du Colombier /*
9459ef1f84bSDavid du Colombier  *  Decrement reference for this address on this link.
9469ef1f84bSDavid du Colombier  *  Unlink from selftab if this is the last ref.
9479ef1f84bSDavid du Colombier  *	called with c->car locked
9489ef1f84bSDavid du Colombier  */
9499ef1f84bSDavid du Colombier static void
remselfcache(Fs * f,Ipifc * ifc,Iplifc * lifc,uchar * a)9509ef1f84bSDavid du Colombier remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
9519ef1f84bSDavid du Colombier {
9529ef1f84bSDavid du Colombier 	Ipself *p, **l;
9539ef1f84bSDavid du Colombier 	Iplink *link, **l_self, **l_lifc;
9549ef1f84bSDavid du Colombier 
9559ef1f84bSDavid du Colombier 	qlock(f->self);
9569ef1f84bSDavid du Colombier 
9579ef1f84bSDavid du Colombier 	/* find the unique selftab entry */
9589ef1f84bSDavid du Colombier 	l = &f->self->hash[hashipa(a)];
9599ef1f84bSDavid du Colombier 	for(p = *l; p; p = *l){
9609ef1f84bSDavid du Colombier 		if(ipcmp(p->a, a) == 0)
9619ef1f84bSDavid du Colombier 			break;
9629ef1f84bSDavid du Colombier 		l = &p->next;
9639ef1f84bSDavid du Colombier 	}
9649ef1f84bSDavid du Colombier 
9659ef1f84bSDavid du Colombier 	if(p == nil)
9669ef1f84bSDavid du Colombier 		goto out;
9679ef1f84bSDavid du Colombier 
9689ef1f84bSDavid du Colombier 	/*
9699ef1f84bSDavid du Colombier 	 *  walk down links from an ifc looking for one
9709ef1f84bSDavid du Colombier 	 *  that matches the selftab entry
9719ef1f84bSDavid du Colombier 	 */
9729ef1f84bSDavid du Colombier 	l_lifc = &lifc->link;
9739ef1f84bSDavid du Colombier 	for(link = *l_lifc; link; link = *l_lifc){
9749ef1f84bSDavid du Colombier 		if(link->self == p)
9759ef1f84bSDavid du Colombier 			break;
9769ef1f84bSDavid du Colombier 		l_lifc = &link->lifclink;
9779ef1f84bSDavid du Colombier 	}
9789ef1f84bSDavid du Colombier 
9799ef1f84bSDavid du Colombier 	if(link == nil)
9809ef1f84bSDavid du Colombier 		goto out;
9819ef1f84bSDavid du Colombier 
9829ef1f84bSDavid du Colombier 	/*
9839ef1f84bSDavid du Colombier 	 *  walk down the links from the selftab looking for
9849ef1f84bSDavid du Colombier 	 *  the one we just found
9859ef1f84bSDavid du Colombier 	 */
9869ef1f84bSDavid du Colombier 	l_self = &p->link;
9879ef1f84bSDavid du Colombier 	for(link = *l_self; link; link = *l_self){
9889ef1f84bSDavid du Colombier 		if(link == *l_lifc)
9899ef1f84bSDavid du Colombier 			break;
9909ef1f84bSDavid du Colombier 		l_self = &link->selflink;
9919ef1f84bSDavid du Colombier 	}
9929ef1f84bSDavid du Colombier 
9939ef1f84bSDavid du Colombier 	if(link == nil)
9949ef1f84bSDavid du Colombier 		panic("remselfcache");
9959ef1f84bSDavid du Colombier 
9969ef1f84bSDavid du Colombier 	if(--(link->ref) != 0)
9979ef1f84bSDavid du Colombier 		goto out;
9989ef1f84bSDavid du Colombier 
9999ef1f84bSDavid du Colombier 	if((p->type & Rmulti) && ifc->medium->remmulti != nil)
10009ef1f84bSDavid du Colombier 		(*ifc->medium->remmulti)(ifc, a, lifc->local);
10019ef1f84bSDavid du Colombier 
10029ef1f84bSDavid du Colombier 	/* ref == 0, remove from both chains and free the link */
10039ef1f84bSDavid du Colombier 	*l_lifc = link->lifclink;
10049ef1f84bSDavid du Colombier 	*l_self = link->selflink;
10059ef1f84bSDavid du Colombier 	iplinkfree(link);
10069ef1f84bSDavid du Colombier 
10079ef1f84bSDavid du Colombier 	if(p->link != nil)
10089ef1f84bSDavid du Colombier 		goto out;
10099ef1f84bSDavid du Colombier 
10109ef1f84bSDavid du Colombier 	/* remove from routing table */
10119ef1f84bSDavid du Colombier 	if(isv4(a))
10129ef1f84bSDavid du Colombier 		v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
10139ef1f84bSDavid du Colombier 	else
10149ef1f84bSDavid du Colombier 		v6delroute(f, a, IPallbits, 1);
10159ef1f84bSDavid du Colombier 
10169ef1f84bSDavid du Colombier 	/* no more links, remove from hash and free */
10179ef1f84bSDavid du Colombier 	*l = p->next;
10189ef1f84bSDavid du Colombier 	ipselffree(p);
10199ef1f84bSDavid du Colombier 
10209ef1f84bSDavid du Colombier 	/* if IPnoaddr, forget */
10219ef1f84bSDavid du Colombier 	if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
10229ef1f84bSDavid du Colombier 		f->self->acceptall = 0;
10239ef1f84bSDavid du Colombier 
10249ef1f84bSDavid du Colombier out:
10259ef1f84bSDavid du Colombier 	qunlock(f->self);
10269ef1f84bSDavid du Colombier }
10279ef1f84bSDavid du Colombier 
10289ef1f84bSDavid du Colombier static char *stformat = "%-44.44I %2.2d %4.4s\n";
10299ef1f84bSDavid du Colombier enum
10309ef1f84bSDavid du Colombier {
10319ef1f84bSDavid du Colombier 	Nstformat= 41,
10329ef1f84bSDavid du Colombier };
10339ef1f84bSDavid du Colombier 
10349ef1f84bSDavid du Colombier long
ipselftabread(Fs * f,char * cp,ulong offset,int n)10359ef1f84bSDavid du Colombier ipselftabread(Fs *f, char *cp, ulong offset, int n)
10369ef1f84bSDavid du Colombier {
10379ef1f84bSDavid du Colombier 	int i, nifc, off;
10389ef1f84bSDavid du Colombier 	Ipself *p;
10399ef1f84bSDavid du Colombier 	Iplink *link;
10409ef1f84bSDavid du Colombier 	char *e, *s, state[8];
10419ef1f84bSDavid du Colombier 
10429ef1f84bSDavid du Colombier 	s = cp;
10439ef1f84bSDavid du Colombier 	e = s+n;
10449ef1f84bSDavid du Colombier 	off = offset;
10459ef1f84bSDavid du Colombier 	qlock(f->self);
10469ef1f84bSDavid du Colombier 	for(i = 0; i < NHASH && s < e; i++){
10479ef1f84bSDavid du Colombier 		for(p = f->self->hash[i]; p != nil && s < e; p = p->next){
10489ef1f84bSDavid du Colombier 			nifc = 0;
10499ef1f84bSDavid du Colombier 			for(link = p->link; link; link = link->selflink)
10509ef1f84bSDavid du Colombier 				nifc++;
10519ef1f84bSDavid du Colombier 			routetype(p->type, state);
10529ef1f84bSDavid du Colombier 			s = seprint(s, e, stformat, p->a, nifc, state);
10539ef1f84bSDavid du Colombier 			if(off > 0){
10549ef1f84bSDavid du Colombier 				off -= s - cp;
10559ef1f84bSDavid du Colombier 				s = cp;
10569ef1f84bSDavid du Colombier 			}
10579ef1f84bSDavid du Colombier 		}
10589ef1f84bSDavid du Colombier 	}
10599ef1f84bSDavid du Colombier 	qunlock(f->self);
10609ef1f84bSDavid du Colombier 	return s - cp;
10619ef1f84bSDavid du Colombier }
10629ef1f84bSDavid du Colombier 
10639ef1f84bSDavid du Colombier int
iptentative(Fs * f,uchar * addr)10649ef1f84bSDavid du Colombier iptentative(Fs *f, uchar *addr)
10659ef1f84bSDavid du Colombier {
10669ef1f84bSDavid du Colombier 	Ipself *p;
10679ef1f84bSDavid du Colombier 
10689ef1f84bSDavid du Colombier 	p = f->self->hash[hashipa(addr)];
10699ef1f84bSDavid du Colombier 	for(; p; p = p->next){
10709ef1f84bSDavid du Colombier 		if(ipcmp(addr, p->a) == 0)
10719ef1f84bSDavid du Colombier 			return p->link->lifc->tentative;
10729ef1f84bSDavid du Colombier 	}
10739ef1f84bSDavid du Colombier 	return 0;
10749ef1f84bSDavid du Colombier }
10759ef1f84bSDavid du Colombier 
10769ef1f84bSDavid du Colombier /*
10779ef1f84bSDavid du Colombier  *  returns
10789ef1f84bSDavid du Colombier  *	0		- no match
10799ef1f84bSDavid du Colombier  *	Runi
10809ef1f84bSDavid du Colombier  *	Rbcast
10819ef1f84bSDavid du Colombier  *	Rmcast
10829ef1f84bSDavid du Colombier  */
10839ef1f84bSDavid du Colombier int
ipforme(Fs * f,uchar * addr)10849ef1f84bSDavid du Colombier ipforme(Fs *f, uchar *addr)
10859ef1f84bSDavid du Colombier {
10869ef1f84bSDavid du Colombier 	Ipself *p;
10879ef1f84bSDavid du Colombier 
10889ef1f84bSDavid du Colombier 	p = f->self->hash[hashipa(addr)];
10899ef1f84bSDavid du Colombier 	for(; p; p = p->next){
10909ef1f84bSDavid du Colombier 		if(ipcmp(addr, p->a) == 0)
10919ef1f84bSDavid du Colombier 			return p->type;
10929ef1f84bSDavid du Colombier 	}
10939ef1f84bSDavid du Colombier 
10949ef1f84bSDavid du Colombier 	/* hack to say accept anything */
10959ef1f84bSDavid du Colombier 	if(f->self->acceptall)
10969ef1f84bSDavid du Colombier 		return Runi;
10979ef1f84bSDavid du Colombier 	return 0;
10989ef1f84bSDavid du Colombier }
10999ef1f84bSDavid du Colombier 
11009ef1f84bSDavid du Colombier /*
11019ef1f84bSDavid du Colombier  *  find the ifc on same net as the remote system.  If none,
11029ef1f84bSDavid du Colombier  *  return nil.
11039ef1f84bSDavid du Colombier  */
11049ef1f84bSDavid du Colombier Ipifc*
findipifc(Fs * f,uchar * remote,int type)11059ef1f84bSDavid du Colombier findipifc(Fs *f, uchar *remote, int type)
11069ef1f84bSDavid du Colombier {
11079ef1f84bSDavid du Colombier 	Ipifc *ifc, *x;
11089ef1f84bSDavid du Colombier 	Iplifc *lifc;
11099ef1f84bSDavid du Colombier 	Conv **cp, **e;
11109ef1f84bSDavid du Colombier 	uchar gnet[IPaddrlen], xmask[IPaddrlen];
11119ef1f84bSDavid du Colombier 
11129ef1f84bSDavid du Colombier 	x = nil;
11139ef1f84bSDavid du Colombier 	memset(xmask, 0, IPaddrlen);
11149ef1f84bSDavid du Colombier 
11159ef1f84bSDavid du Colombier 	/* find most specific match */
11169ef1f84bSDavid du Colombier 	e = &f->ipifc->conv[f->ipifc->nc];
11179ef1f84bSDavid du Colombier 	for(cp = f->ipifc->conv; cp < e; cp++){
11189ef1f84bSDavid du Colombier 		if(*cp == 0)
11199ef1f84bSDavid du Colombier 			continue;
11209ef1f84bSDavid du Colombier 		ifc = (Ipifc*)(*cp)->ptcl;
11219ef1f84bSDavid du Colombier 		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
11229ef1f84bSDavid du Colombier 			maskip(remote, lifc->mask, gnet);
11239ef1f84bSDavid du Colombier 			if(ipcmp(gnet, lifc->net) == 0){
11249ef1f84bSDavid du Colombier 				if(x == nil || ipcmp(lifc->mask, xmask) > 0){
11259ef1f84bSDavid du Colombier 					x = ifc;
11269ef1f84bSDavid du Colombier 					ipmove(xmask, lifc->mask);
11279ef1f84bSDavid du Colombier 				}
11289ef1f84bSDavid du Colombier 			}
11299ef1f84bSDavid du Colombier 		}
11309ef1f84bSDavid du Colombier 	}
11319ef1f84bSDavid du Colombier 	if(x != nil)
11329ef1f84bSDavid du Colombier 		return x;
11339ef1f84bSDavid du Colombier 
11349ef1f84bSDavid du Colombier 	/* for now for broadcast and multicast, just use first interface */
11359ef1f84bSDavid du Colombier 	if(type & (Rbcast|Rmulti)){
11369ef1f84bSDavid du Colombier 		for(cp = f->ipifc->conv; cp < e; cp++){
11379ef1f84bSDavid du Colombier 			if(*cp == 0)
11389ef1f84bSDavid du Colombier 				continue;
11399ef1f84bSDavid du Colombier 			ifc = (Ipifc*)(*cp)->ptcl;
11409ef1f84bSDavid du Colombier 			if(ifc->lifc != nil)
11419ef1f84bSDavid du Colombier 				return ifc;
11429ef1f84bSDavid du Colombier 		}
11439ef1f84bSDavid du Colombier 	}
11449ef1f84bSDavid du Colombier 	return nil;
11459ef1f84bSDavid du Colombier }
11469ef1f84bSDavid du Colombier 
11479ef1f84bSDavid du Colombier enum {
11489ef1f84bSDavid du Colombier 	unknownv6,		/* UGH */
11499ef1f84bSDavid du Colombier //	multicastv6,
11509ef1f84bSDavid du Colombier 	unspecifiedv6,
11519ef1f84bSDavid du Colombier 	linklocalv6,
11529ef1f84bSDavid du Colombier 	globalv6,
11539ef1f84bSDavid du Colombier };
11549ef1f84bSDavid du Colombier 
11559ef1f84bSDavid du Colombier int
v6addrtype(uchar * addr)11569ef1f84bSDavid du Colombier v6addrtype(uchar *addr)
11579ef1f84bSDavid du Colombier {
11589ef1f84bSDavid du Colombier 	if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
11599ef1f84bSDavid du Colombier 		return unknownv6;
11609ef1f84bSDavid du Colombier 	else if(islinklocal(addr) ||
11619ef1f84bSDavid du Colombier 	    isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
11629ef1f84bSDavid du Colombier 		return linklocalv6;
11639ef1f84bSDavid du Colombier 	else
11649ef1f84bSDavid du Colombier 		return globalv6;
11659ef1f84bSDavid du Colombier }
11669ef1f84bSDavid du Colombier 
11679ef1f84bSDavid du Colombier #define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
11689ef1f84bSDavid du Colombier 			(lifc)->origint + (lifc)->preflt >= NOW/1000)
11699ef1f84bSDavid du Colombier 
11709ef1f84bSDavid du Colombier static void
findprimaryipv6(Fs * f,uchar * local)11719ef1f84bSDavid du Colombier findprimaryipv6(Fs *f, uchar *local)
11729ef1f84bSDavid du Colombier {
11739ef1f84bSDavid du Colombier 	int atype, atypel;
11749ef1f84bSDavid du Colombier 	Conv **cp, **e;
11759ef1f84bSDavid du Colombier 	Ipifc *ifc;
11769ef1f84bSDavid du Colombier 	Iplifc *lifc;
11779ef1f84bSDavid du Colombier 
11789ef1f84bSDavid du Colombier 	ipmove(local, v6Unspecified);
11799ef1f84bSDavid du Colombier 	atype = unspecifiedv6;
11809ef1f84bSDavid du Colombier 
11819ef1f84bSDavid du Colombier 	/*
11829ef1f84bSDavid du Colombier 	 * find "best" (global > link local > unspecified)
11839ef1f84bSDavid du Colombier 	 * local address; address must be current.
11849ef1f84bSDavid du Colombier 	 */
11859ef1f84bSDavid du Colombier 	e = &f->ipifc->conv[f->ipifc->nc];
11869ef1f84bSDavid du Colombier 	for(cp = f->ipifc->conv; cp < e; cp++){
11879ef1f84bSDavid du Colombier 		if(*cp == 0)
11889ef1f84bSDavid du Colombier 			continue;
11899ef1f84bSDavid du Colombier 		ifc = (Ipifc*)(*cp)->ptcl;
11909ef1f84bSDavid du Colombier 		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
11919ef1f84bSDavid du Colombier 			atypel = v6addrtype(lifc->local);
11929ef1f84bSDavid du Colombier 			if(atypel > atype && v6addrcurr(lifc)) {
11939ef1f84bSDavid du Colombier 				ipmove(local, lifc->local);
11949ef1f84bSDavid du Colombier 				atype = atypel;
11959ef1f84bSDavid du Colombier 				if(atype == globalv6)
11969ef1f84bSDavid du Colombier 					return;
11979ef1f84bSDavid du Colombier 			}
11989ef1f84bSDavid du Colombier 		}
11999ef1f84bSDavid du Colombier 	}
12009ef1f84bSDavid du Colombier }
12019ef1f84bSDavid du Colombier 
12029ef1f84bSDavid du Colombier /*
12039ef1f84bSDavid du Colombier  *  returns first ip address configured
12049ef1f84bSDavid du Colombier  */
12059ef1f84bSDavid du Colombier static void
findprimaryipv4(Fs * f,uchar * local)12069ef1f84bSDavid du Colombier findprimaryipv4(Fs *f, uchar *local)
12079ef1f84bSDavid du Colombier {
12089ef1f84bSDavid du Colombier 	Conv **cp, **e;
12099ef1f84bSDavid du Colombier 	Ipifc *ifc;
12109ef1f84bSDavid du Colombier 	Iplifc *lifc;
12119ef1f84bSDavid du Colombier 
12129ef1f84bSDavid du Colombier 	/* find first ifc local address */
12139ef1f84bSDavid du Colombier 	e = &f->ipifc->conv[f->ipifc->nc];
12149ef1f84bSDavid du Colombier 	for(cp = f->ipifc->conv; cp < e; cp++){
12159ef1f84bSDavid du Colombier 		if(*cp == 0)
12169ef1f84bSDavid du Colombier 			continue;
12179ef1f84bSDavid du Colombier 		ifc = (Ipifc*)(*cp)->ptcl;
12189ef1f84bSDavid du Colombier 		if((lifc = ifc->lifc) != nil){
12199ef1f84bSDavid du Colombier 			ipmove(local, lifc->local);
12209ef1f84bSDavid du Colombier 			return;
12219ef1f84bSDavid du Colombier 		}
12229ef1f84bSDavid du Colombier 	}
12239ef1f84bSDavid du Colombier }
12249ef1f84bSDavid du Colombier 
12259ef1f84bSDavid du Colombier /*
12269ef1f84bSDavid du Colombier  *  find the local address 'closest' to the remote system, copy it to
12279ef1f84bSDavid du Colombier  *  local and return the ifc for that address
12289ef1f84bSDavid du Colombier  */
12299ef1f84bSDavid du Colombier void
findlocalip(Fs * f,uchar * local,uchar * remote)12309ef1f84bSDavid du Colombier findlocalip(Fs *f, uchar *local, uchar *remote)
12319ef1f84bSDavid du Colombier {
12329ef1f84bSDavid du Colombier 	int version, atype = unspecifiedv6, atypel = unknownv6;
12339ef1f84bSDavid du Colombier 	int atyper, deprecated;
12349ef1f84bSDavid du Colombier 	uchar gate[IPaddrlen], gnet[IPaddrlen];
12359ef1f84bSDavid du Colombier 	Ipifc *ifc;
12369ef1f84bSDavid du Colombier 	Iplifc *lifc;
12379ef1f84bSDavid du Colombier 	Route *r;
12389ef1f84bSDavid du Colombier 
12399ef1f84bSDavid du Colombier 	USED(atype);
12409ef1f84bSDavid du Colombier 	USED(atypel);
12419ef1f84bSDavid du Colombier 	qlock(f->ipifc);
12429ef1f84bSDavid du Colombier 	r = v6lookup(f, remote, nil);
12439ef1f84bSDavid du Colombier 	version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;
12449ef1f84bSDavid du Colombier 
12459ef1f84bSDavid du Colombier 	if(r != nil){
12469ef1f84bSDavid du Colombier 		ifc = r->ifc;
12479ef1f84bSDavid du Colombier 		if(r->type & Rv4)
12489ef1f84bSDavid du Colombier 			v4tov6(gate, r->v4.gate);
12499ef1f84bSDavid du Colombier 		else {
12509ef1f84bSDavid du Colombier 			ipmove(gate, r->v6.gate);
12519ef1f84bSDavid du Colombier 			ipmove(local, v6Unspecified);
12529ef1f84bSDavid du Colombier 		}
12539ef1f84bSDavid du Colombier 
12549ef1f84bSDavid du Colombier 		switch(version) {
12559ef1f84bSDavid du Colombier 		case V4:
12569ef1f84bSDavid du Colombier 			/* find ifc address closest to the gateway to use */
12579ef1f84bSDavid du Colombier 			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
12589ef1f84bSDavid du Colombier 				maskip(gate, lifc->mask, gnet);
12599ef1f84bSDavid du Colombier 				if(ipcmp(gnet, lifc->net) == 0){
12609ef1f84bSDavid du Colombier 					ipmove(local, lifc->local);
12619ef1f84bSDavid du Colombier 					goto out;
12629ef1f84bSDavid du Colombier 				}
12639ef1f84bSDavid du Colombier 			}
12649ef1f84bSDavid du Colombier 			break;
12659ef1f84bSDavid du Colombier 		case V6:
12669ef1f84bSDavid du Colombier 			/* find ifc address with scope matching the destination */
12679ef1f84bSDavid du Colombier 			atyper = v6addrtype(remote);
12689ef1f84bSDavid du Colombier 			deprecated = 0;
12699ef1f84bSDavid du Colombier 			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
12709ef1f84bSDavid du Colombier 				atypel = v6addrtype(lifc->local);
12719ef1f84bSDavid du Colombier 				/* prefer appropriate scope */
12729ef1f84bSDavid du Colombier 				if(atypel > atype && atype < atyper ||
12739ef1f84bSDavid du Colombier 				   atypel < atype && atype > atyper){
12749ef1f84bSDavid du Colombier 					ipmove(local, lifc->local);
12759ef1f84bSDavid du Colombier 					deprecated = !v6addrcurr(lifc);
12769ef1f84bSDavid du Colombier 					atype = atypel;
12779ef1f84bSDavid du Colombier 				} else if(atypel == atype){
12789ef1f84bSDavid du Colombier 					/* avoid deprecated addresses */
12799ef1f84bSDavid du Colombier 					if(deprecated && v6addrcurr(lifc)){
12809ef1f84bSDavid du Colombier 						ipmove(local, lifc->local);
12819ef1f84bSDavid du Colombier 						atype = atypel;
12829ef1f84bSDavid du Colombier 						deprecated = 0;
12839ef1f84bSDavid du Colombier 					}
12849ef1f84bSDavid du Colombier 				}
12859ef1f84bSDavid du Colombier 				if(atype == atyper && !deprecated)
12869ef1f84bSDavid du Colombier 					goto out;
12879ef1f84bSDavid du Colombier 			}
12889ef1f84bSDavid du Colombier 			if(atype >= atyper)
12899ef1f84bSDavid du Colombier 				goto out;
12909ef1f84bSDavid du Colombier 			break;
12919ef1f84bSDavid du Colombier 		default:
12929ef1f84bSDavid du Colombier 			panic("findlocalip: version %d", version);
12939ef1f84bSDavid du Colombier 		}
12949ef1f84bSDavid du Colombier 	}
12959ef1f84bSDavid du Colombier 
12969ef1f84bSDavid du Colombier 	switch(version){
12979ef1f84bSDavid du Colombier 	case V4:
12989ef1f84bSDavid du Colombier 		findprimaryipv4(f, local);
12999ef1f84bSDavid du Colombier 		break;
13009ef1f84bSDavid du Colombier 	case V6:
13019ef1f84bSDavid du Colombier 		findprimaryipv6(f, local);
13029ef1f84bSDavid du Colombier 		break;
13039ef1f84bSDavid du Colombier 	default:
13049ef1f84bSDavid du Colombier 		panic("findlocalip2: version %d", version);
13059ef1f84bSDavid du Colombier 	}
13069ef1f84bSDavid du Colombier 
13079ef1f84bSDavid du Colombier out:
13089ef1f84bSDavid du Colombier 	qunlock(f->ipifc);
13099ef1f84bSDavid du Colombier }
13109ef1f84bSDavid du Colombier 
13119ef1f84bSDavid du Colombier /*
13129ef1f84bSDavid du Colombier  *  return first v4 address associated with an interface
13139ef1f84bSDavid du Colombier  */
13149ef1f84bSDavid du Colombier int
ipv4local(Ipifc * ifc,uchar * addr)13159ef1f84bSDavid du Colombier ipv4local(Ipifc *ifc, uchar *addr)
13169ef1f84bSDavid du Colombier {
13179ef1f84bSDavid du Colombier 	Iplifc *lifc;
13189ef1f84bSDavid du Colombier 
13199ef1f84bSDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
13209ef1f84bSDavid du Colombier 		if(isv4(lifc->local)){
13219ef1f84bSDavid du Colombier 			memmove(addr, lifc->local+IPv4off, IPv4addrlen);
13229ef1f84bSDavid du Colombier 			return 1;
13239ef1f84bSDavid du Colombier 		}
13249ef1f84bSDavid du Colombier 	}
13259ef1f84bSDavid du Colombier 	return 0;
13269ef1f84bSDavid du Colombier }
13279ef1f84bSDavid du Colombier 
13289ef1f84bSDavid du Colombier /*
13299ef1f84bSDavid du Colombier  *  return first v6 address associated with an interface
13309ef1f84bSDavid du Colombier  */
13319ef1f84bSDavid du Colombier int
ipv6local(Ipifc * ifc,uchar * addr)13329ef1f84bSDavid du Colombier ipv6local(Ipifc *ifc, uchar *addr)
13339ef1f84bSDavid du Colombier {
13349ef1f84bSDavid du Colombier 	Iplifc *lifc;
13359ef1f84bSDavid du Colombier 
13369ef1f84bSDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
13379ef1f84bSDavid du Colombier 		if(!isv4(lifc->local) && !(lifc->tentative)){
13389ef1f84bSDavid du Colombier 			ipmove(addr, lifc->local);
13399ef1f84bSDavid du Colombier 			return 1;
13409ef1f84bSDavid du Colombier 		}
13419ef1f84bSDavid du Colombier 	}
13429ef1f84bSDavid du Colombier 	return 0;
13439ef1f84bSDavid du Colombier }
13449ef1f84bSDavid du Colombier 
13459ef1f84bSDavid du Colombier int
ipv6anylocal(Ipifc * ifc,uchar * addr)13469ef1f84bSDavid du Colombier ipv6anylocal(Ipifc *ifc, uchar *addr)
13479ef1f84bSDavid du Colombier {
13489ef1f84bSDavid du Colombier 	Iplifc *lifc;
13499ef1f84bSDavid du Colombier 
13509ef1f84bSDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
13519ef1f84bSDavid du Colombier 		if(!isv4(lifc->local)){
13529ef1f84bSDavid du Colombier 			ipmove(addr, lifc->local);
13539ef1f84bSDavid du Colombier 			return SRC_UNI;
13549ef1f84bSDavid du Colombier 		}
13559ef1f84bSDavid du Colombier 	}
13569ef1f84bSDavid du Colombier 	return SRC_UNSPEC;
13579ef1f84bSDavid du Colombier }
13589ef1f84bSDavid du Colombier 
13599ef1f84bSDavid du Colombier /*
13609ef1f84bSDavid du Colombier  *  see if this address is bound to the interface
13619ef1f84bSDavid du Colombier  */
13629ef1f84bSDavid du Colombier Iplifc*
iplocalonifc(Ipifc * ifc,uchar * ip)13639ef1f84bSDavid du Colombier iplocalonifc(Ipifc *ifc, uchar *ip)
13649ef1f84bSDavid du Colombier {
13659ef1f84bSDavid du Colombier 	Iplifc *lifc;
13669ef1f84bSDavid du Colombier 
13679ef1f84bSDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next)
13689ef1f84bSDavid du Colombier 		if(ipcmp(ip, lifc->local) == 0)
13699ef1f84bSDavid du Colombier 			return lifc;
13709ef1f84bSDavid du Colombier 	return nil;
13719ef1f84bSDavid du Colombier }
13729ef1f84bSDavid du Colombier 
13739ef1f84bSDavid du Colombier 
13749ef1f84bSDavid du Colombier /*
13759ef1f84bSDavid du Colombier  *  See if we're proxying for this address on this interface
13769ef1f84bSDavid du Colombier  */
13779ef1f84bSDavid du Colombier int
ipproxyifc(Fs * f,Ipifc * ifc,uchar * ip)13789ef1f84bSDavid du Colombier ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
13799ef1f84bSDavid du Colombier {
13809ef1f84bSDavid du Colombier 	Route *r;
13819ef1f84bSDavid du Colombier 	uchar net[IPaddrlen];
13829ef1f84bSDavid du Colombier 	Iplifc *lifc;
13839ef1f84bSDavid du Colombier 
13849ef1f84bSDavid du Colombier 	/* see if this is a direct connected pt to pt address */
13859ef1f84bSDavid du Colombier 	r = v6lookup(f, ip, nil);
13869ef1f84bSDavid du Colombier 	if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
13879ef1f84bSDavid du Colombier 		return 0;
13889ef1f84bSDavid du Colombier 
13899ef1f84bSDavid du Colombier 	/* see if this is on the right interface */
13909ef1f84bSDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
13919ef1f84bSDavid du Colombier 		maskip(ip, lifc->mask, net);
13929ef1f84bSDavid du Colombier 		if(ipcmp(net, lifc->remote) == 0)
13939ef1f84bSDavid du Colombier 			return 1;
13949ef1f84bSDavid du Colombier 	}
13959ef1f84bSDavid du Colombier 	return 0;
13969ef1f84bSDavid du Colombier }
13979ef1f84bSDavid du Colombier 
13989ef1f84bSDavid du Colombier /*
13999ef1f84bSDavid du Colombier  *  return multicast version if any
14009ef1f84bSDavid du Colombier  */
14019ef1f84bSDavid du Colombier int
ipismulticast(uchar * ip)14029ef1f84bSDavid du Colombier ipismulticast(uchar *ip)
14039ef1f84bSDavid du Colombier {
14049ef1f84bSDavid du Colombier 	if(isv4(ip)){
14059ef1f84bSDavid du Colombier 		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
14069ef1f84bSDavid du Colombier 			return V4;
14079ef1f84bSDavid du Colombier 	}
14089ef1f84bSDavid du Colombier 	else if(ip[0] == 0xff)
14099ef1f84bSDavid du Colombier 		return V6;
14109ef1f84bSDavid du Colombier 	return 0;
14119ef1f84bSDavid du Colombier }
14129ef1f84bSDavid du Colombier int
ipisbm(uchar * ip)14139ef1f84bSDavid du Colombier ipisbm(uchar *ip)
14149ef1f84bSDavid du Colombier {
14159ef1f84bSDavid du Colombier 	if(isv4(ip)){
14169ef1f84bSDavid du Colombier 		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
14179ef1f84bSDavid du Colombier 			return V4;
14189ef1f84bSDavid du Colombier 		else if(ipcmp(ip, IPv4bcast) == 0)
14199ef1f84bSDavid du Colombier 			return V4;
14209ef1f84bSDavid du Colombier 	}
14219ef1f84bSDavid du Colombier 	else if(ip[0] == 0xff)
14229ef1f84bSDavid du Colombier 		return V6;
14239ef1f84bSDavid du Colombier 	return 0;
14249ef1f84bSDavid du Colombier }
14259ef1f84bSDavid du Colombier 
14269ef1f84bSDavid du Colombier 
14279ef1f84bSDavid du Colombier /*
14289ef1f84bSDavid du Colombier  *  add a multicast address to an interface, called with c->car locked
14299ef1f84bSDavid du Colombier  */
14309ef1f84bSDavid du Colombier void
ipifcaddmulti(Conv * c,uchar * ma,uchar * ia)14319ef1f84bSDavid du Colombier ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
14329ef1f84bSDavid du Colombier {
14339ef1f84bSDavid du Colombier 	Ipifc *ifc;
14349ef1f84bSDavid du Colombier 	Iplifc *lifc;
14359ef1f84bSDavid du Colombier 	Conv **p;
14369ef1f84bSDavid du Colombier 	Ipmulti *multi, **l;
14379ef1f84bSDavid du Colombier 	Fs *f;
14389ef1f84bSDavid du Colombier 
14399ef1f84bSDavid du Colombier 	f = c->p->f;
14409ef1f84bSDavid du Colombier 
14419ef1f84bSDavid du Colombier 	for(l = &c->multi; *l; l = &(*l)->next)
14429ef1f84bSDavid du Colombier 		if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
14439ef1f84bSDavid du Colombier 			return;		/* it's already there */
14449ef1f84bSDavid du Colombier 
14459ef1f84bSDavid du Colombier 	multi = *l = smalloc(sizeof(*multi));
14469ef1f84bSDavid du Colombier 	ipmove(multi->ma, ma);
14479ef1f84bSDavid du Colombier 	ipmove(multi->ia, ia);
14489ef1f84bSDavid du Colombier 	multi->next = nil;
14499ef1f84bSDavid du Colombier 
14509ef1f84bSDavid du Colombier 	for(p = f->ipifc->conv; *p; p++){
14519ef1f84bSDavid du Colombier 		if((*p)->inuse == 0)
14529ef1f84bSDavid du Colombier 			continue;
14539ef1f84bSDavid du Colombier 		ifc = (Ipifc*)(*p)->ptcl;
14549ef1f84bSDavid du Colombier 		if(waserror()){
14559ef1f84bSDavid du Colombier 			wunlock(ifc);
14569ef1f84bSDavid du Colombier 			nexterror();
14579ef1f84bSDavid du Colombier 		}
14589ef1f84bSDavid du Colombier 		wlock(ifc);
14599ef1f84bSDavid du Colombier 		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
14609ef1f84bSDavid du Colombier 			if(ipcmp(ia, lifc->local) == 0)
14619ef1f84bSDavid du Colombier 				addselfcache(f, ifc, lifc, ma, Rmulti);
14629ef1f84bSDavid du Colombier 		wunlock(ifc);
14639ef1f84bSDavid du Colombier 		poperror();
14649ef1f84bSDavid du Colombier 	}
14659ef1f84bSDavid du Colombier }
14669ef1f84bSDavid du Colombier 
14679ef1f84bSDavid du Colombier 
14689ef1f84bSDavid du Colombier /*
14699ef1f84bSDavid du Colombier  *  remove a multicast address from an interface, called with c->car locked
14709ef1f84bSDavid du Colombier  */
14719ef1f84bSDavid du Colombier void
ipifcremmulti(Conv * c,uchar * ma,uchar * ia)14729ef1f84bSDavid du Colombier ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
14739ef1f84bSDavid du Colombier {
14749ef1f84bSDavid du Colombier 	Ipmulti *multi, **l;
14759ef1f84bSDavid du Colombier 	Iplifc *lifc;
14769ef1f84bSDavid du Colombier 	Conv **p;
14779ef1f84bSDavid du Colombier 	Ipifc *ifc;
14789ef1f84bSDavid du Colombier 	Fs *f;
14799ef1f84bSDavid du Colombier 
14809ef1f84bSDavid du Colombier 	f = c->p->f;
14819ef1f84bSDavid du Colombier 
14829ef1f84bSDavid du Colombier 	for(l = &c->multi; *l; l = &(*l)->next)
14839ef1f84bSDavid du Colombier 		if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
14849ef1f84bSDavid du Colombier 			break;
14859ef1f84bSDavid du Colombier 
14869ef1f84bSDavid du Colombier 	multi = *l;
14879ef1f84bSDavid du Colombier 	if(multi == nil)
14889ef1f84bSDavid du Colombier 		return;		/* we don't have it open */
14899ef1f84bSDavid du Colombier 
14909ef1f84bSDavid du Colombier 	*l = multi->next;
14919ef1f84bSDavid du Colombier 
14929ef1f84bSDavid du Colombier 	for(p = f->ipifc->conv; *p; p++){
14939ef1f84bSDavid du Colombier 		if((*p)->inuse == 0)
14949ef1f84bSDavid du Colombier 			continue;
14959ef1f84bSDavid du Colombier 
14969ef1f84bSDavid du Colombier 		ifc = (Ipifc*)(*p)->ptcl;
14979ef1f84bSDavid du Colombier 		if(waserror()){
14989ef1f84bSDavid du Colombier 			wunlock(ifc);
14999ef1f84bSDavid du Colombier 			nexterror();
15009ef1f84bSDavid du Colombier 		}
15019ef1f84bSDavid du Colombier 		wlock(ifc);
15029ef1f84bSDavid du Colombier 		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
15039ef1f84bSDavid du Colombier 			if(ipcmp(ia, lifc->local) == 0)
15049ef1f84bSDavid du Colombier 				remselfcache(f, ifc, lifc, ma);
15059ef1f84bSDavid du Colombier 		wunlock(ifc);
15069ef1f84bSDavid du Colombier 		poperror();
15079ef1f84bSDavid du Colombier 	}
15089ef1f84bSDavid du Colombier 
15099ef1f84bSDavid du Colombier 	free(multi);
15109ef1f84bSDavid du Colombier }
15119ef1f84bSDavid du Colombier 
15129ef1f84bSDavid du Colombier /*
15139ef1f84bSDavid du Colombier  *  make lifc's join and leave multicast groups
15149ef1f84bSDavid du Colombier  */
15159ef1f84bSDavid du Colombier static char*
ipifcjoinmulti(Ipifc * ifc,char ** argv,int argc)15169ef1f84bSDavid du Colombier ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
15179ef1f84bSDavid du Colombier {
15189ef1f84bSDavid du Colombier 	USED(ifc, argv, argc);
15199ef1f84bSDavid du Colombier 	return nil;
15209ef1f84bSDavid du Colombier }
15219ef1f84bSDavid du Colombier 
15229ef1f84bSDavid du Colombier static char*
ipifcleavemulti(Ipifc * ifc,char ** argv,int argc)15239ef1f84bSDavid du Colombier ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
15249ef1f84bSDavid du Colombier {
15259ef1f84bSDavid du Colombier 	USED(ifc, argv, argc);
15269ef1f84bSDavid du Colombier 	return nil;
15279ef1f84bSDavid du Colombier }
15289ef1f84bSDavid du Colombier 
15299ef1f84bSDavid du Colombier static void
ipifcregisterproxy(Fs * f,Ipifc * ifc,uchar * ip)15309ef1f84bSDavid du Colombier ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
15319ef1f84bSDavid du Colombier {
15329ef1f84bSDavid du Colombier 	Conv **cp, **e;
15339ef1f84bSDavid du Colombier 	Ipifc *nifc;
15349ef1f84bSDavid du Colombier 	Iplifc *lifc;
15359ef1f84bSDavid du Colombier 	Medium *medium;
15369ef1f84bSDavid du Colombier 	uchar net[IPaddrlen];
15379ef1f84bSDavid du Colombier 
15389ef1f84bSDavid du Colombier 	/* register the address on any network that will proxy for us */
15399ef1f84bSDavid du Colombier 	e = &f->ipifc->conv[f->ipifc->nc];
15409ef1f84bSDavid du Colombier 
15419ef1f84bSDavid du Colombier 	if(!isv4(ip)) {				/* V6 */
15429ef1f84bSDavid du Colombier 		for(cp = f->ipifc->conv; cp < e; cp++){
15439ef1f84bSDavid du Colombier 			if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
15449ef1f84bSDavid du Colombier 				continue;
15459ef1f84bSDavid du Colombier 			rlock(nifc);
15469ef1f84bSDavid du Colombier 			medium = nifc->medium;
15479ef1f84bSDavid du Colombier 			if(medium == nil || medium->addmulti == nil) {
15489ef1f84bSDavid du Colombier 				runlock(nifc);
15499ef1f84bSDavid du Colombier 				continue;
15509ef1f84bSDavid du Colombier 			}
15519ef1f84bSDavid du Colombier 			for(lifc = nifc->lifc; lifc; lifc = lifc->next){
15529ef1f84bSDavid du Colombier 				maskip(ip, lifc->mask, net);
15539ef1f84bSDavid du Colombier 				if(ipcmp(net, lifc->remote) == 0) {
15549ef1f84bSDavid du Colombier 					/* add solicited-node multicast addr */
15559ef1f84bSDavid du Colombier 					ipv62smcast(net, ip);
15569ef1f84bSDavid du Colombier 					addselfcache(f, nifc, lifc, net, Rmulti);
15579ef1f84bSDavid du Colombier 					arpenter(f, V6, ip, nifc->mac, 6, 0);
15589ef1f84bSDavid du Colombier 					// (*medium->addmulti)(nifc, net, ip);
15599ef1f84bSDavid du Colombier 					break;
15609ef1f84bSDavid du Colombier 				}
15619ef1f84bSDavid du Colombier 			}
15629ef1f84bSDavid du Colombier 			runlock(nifc);
15639ef1f84bSDavid du Colombier 		}
15649ef1f84bSDavid du Colombier 	}
15659ef1f84bSDavid du Colombier 	else {					/* V4 */
15669ef1f84bSDavid du Colombier 		for(cp = f->ipifc->conv; cp < e; cp++){
15679ef1f84bSDavid du Colombier 			if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
15689ef1f84bSDavid du Colombier 				continue;
15699ef1f84bSDavid du Colombier 			rlock(nifc);
15709ef1f84bSDavid du Colombier 			medium = nifc->medium;
15719ef1f84bSDavid du Colombier 			if(medium == nil || medium->areg == nil){
15729ef1f84bSDavid du Colombier 				runlock(nifc);
15739ef1f84bSDavid du Colombier 				continue;
15749ef1f84bSDavid du Colombier 			}
15759ef1f84bSDavid du Colombier 			for(lifc = nifc->lifc; lifc; lifc = lifc->next){
15769ef1f84bSDavid du Colombier 				maskip(ip, lifc->mask, net);
15779ef1f84bSDavid du Colombier 				if(ipcmp(net, lifc->remote) == 0){
15789ef1f84bSDavid du Colombier 					(*medium->areg)(nifc, ip);
15799ef1f84bSDavid du Colombier 					break;
15809ef1f84bSDavid du Colombier 				}
15819ef1f84bSDavid du Colombier 			}
15829ef1f84bSDavid du Colombier 			runlock(nifc);
15839ef1f84bSDavid du Colombier 		}
15849ef1f84bSDavid du Colombier 	}
15859ef1f84bSDavid du Colombier }
15869ef1f84bSDavid du Colombier 
15879ef1f84bSDavid du Colombier 
15889ef1f84bSDavid du Colombier /* added for new v6 mesg types */
15899ef1f84bSDavid du Colombier static void
adddefroute6(Fs * f,uchar * gate,int force)15909ef1f84bSDavid du Colombier adddefroute6(Fs *f, uchar *gate, int force)
15919ef1f84bSDavid du Colombier {
15929ef1f84bSDavid du Colombier 	Route *r;
15939ef1f84bSDavid du Colombier 
15949ef1f84bSDavid du Colombier 	r = v6lookup(f, v6Unspecified, nil);
15959ef1f84bSDavid du Colombier 	/*
15969ef1f84bSDavid du Colombier 	 * route entries generated by all other means take precedence
15979ef1f84bSDavid du Colombier 	 * over router announcements.
15989ef1f84bSDavid du Colombier 	 */
15999ef1f84bSDavid du Colombier 	if (r && !force && strcmp(r->tag, "ra") != 0)
16009ef1f84bSDavid du Colombier 		return;
16019ef1f84bSDavid du Colombier 
16029ef1f84bSDavid du Colombier 	v6delroute(f, v6Unspecified, v6Unspecified, 1);
16039ef1f84bSDavid du Colombier 	v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
16049ef1f84bSDavid du Colombier }
16059ef1f84bSDavid du Colombier 
16069ef1f84bSDavid du Colombier enum {
16079ef1f84bSDavid du Colombier 	Ngates = 3,
16089ef1f84bSDavid du Colombier };
16099ef1f84bSDavid du Colombier 
16109ef1f84bSDavid du Colombier char*
ipifcadd6(Ipifc * ifc,char ** argv,int argc)16119ef1f84bSDavid du Colombier ipifcadd6(Ipifc *ifc, char**argv, int argc)
16129ef1f84bSDavid du Colombier {
16139ef1f84bSDavid du Colombier 	int plen = 64;
16149ef1f84bSDavid du Colombier 	long origint = NOW / 1000, preflt = ~0L, validlt = ~0L;
1615*a3323688SDavid du Colombier 	char addr[Maxv6repr], preflen[6];
16169ef1f84bSDavid du Colombier 	char *params[3];
16179ef1f84bSDavid du Colombier 	uchar autoflag = 1, onlink = 1;
16189ef1f84bSDavid du Colombier 	uchar prefix[IPaddrlen];
16199ef1f84bSDavid du Colombier 	Iplifc *lifc;
16209ef1f84bSDavid du Colombier 
16219ef1f84bSDavid du Colombier 	switch(argc) {
16229ef1f84bSDavid du Colombier 	case 7:
16239ef1f84bSDavid du Colombier 		preflt = atoi(argv[6]);
16249ef1f84bSDavid du Colombier 		/* fall through */
16259ef1f84bSDavid du Colombier 	case 6:
16269ef1f84bSDavid du Colombier 		validlt = atoi(argv[5]);
16279ef1f84bSDavid du Colombier 		/* fall through */
16289ef1f84bSDavid du Colombier 	case 5:
16299ef1f84bSDavid du Colombier 		autoflag = atoi(argv[4]);
16309ef1f84bSDavid du Colombier 		/* fall through */
16319ef1f84bSDavid du Colombier 	case 4:
16329ef1f84bSDavid du Colombier 		onlink = atoi(argv[3]);
16339ef1f84bSDavid du Colombier 		/* fall through */
16349ef1f84bSDavid du Colombier 	case 3:
16359ef1f84bSDavid du Colombier 		plen = atoi(argv[2]);
16369ef1f84bSDavid du Colombier 		/* fall through */
16379ef1f84bSDavid du Colombier 	case 2:
16389ef1f84bSDavid du Colombier 		break;
16399ef1f84bSDavid du Colombier 	default:
16409ef1f84bSDavid du Colombier 		return Ebadarg;
16419ef1f84bSDavid du Colombier 	}
16429ef1f84bSDavid du Colombier 
1643*a3323688SDavid du Colombier 	if (parseip(prefix, argv[1]) != 6)
1644*a3323688SDavid du Colombier 		return "bad ipv6 address";
1645*a3323688SDavid du Colombier 	if (validlt < preflt)
1646*a3323688SDavid du Colombier 		return "valid ipv6 lifetime less than preferred lifetime";
1647*a3323688SDavid du Colombier 	if (plen < 0)
1648*a3323688SDavid du Colombier 		return "negative ipv6 prefix length";
1649*a3323688SDavid du Colombier 	/* i think that this length limit is bogus - geoff */
1650*a3323688SDavid du Colombier //	if (plen > 64)
1651*a3323688SDavid du Colombier //		return "ipv6 prefix length greater than 64;
1652*a3323688SDavid du Colombier 	if (islinklocal(prefix))
1653*a3323688SDavid du Colombier 		return "ipv6 prefix is link-local";
16549ef1f84bSDavid du Colombier 
16559ef1f84bSDavid du Colombier 	lifc = smalloc(sizeof(Iplifc));
16569ef1f84bSDavid du Colombier 	lifc->onlink = (onlink != 0);
16579ef1f84bSDavid du Colombier 	lifc->autoflag = (autoflag != 0);
16589ef1f84bSDavid du Colombier 	lifc->validlt = validlt;
16599ef1f84bSDavid du Colombier 	lifc->preflt = preflt;
16609ef1f84bSDavid du Colombier 	lifc->origint = origint;
16619ef1f84bSDavid du Colombier 
16629ef1f84bSDavid du Colombier 	/* issue "add" ctl msg for v6 link-local addr and prefix len */
16639ef1f84bSDavid du Colombier 	if(!ifc->medium->pref2addr)
1664*a3323688SDavid du Colombier 		return "no pref2addr on interface";
16659ef1f84bSDavid du Colombier 	ifc->medium->pref2addr(prefix, ifc->mac);	/* mac → v6 link-local addr */
1666*a3323688SDavid du Colombier 	snprint(addr, sizeof addr, "%I", prefix);
1667*a3323688SDavid du Colombier 	snprint(preflen, sizeof preflen, "/%d", plen);
16689ef1f84bSDavid du Colombier 	params[0] = "add";
16699ef1f84bSDavid du Colombier 	params[1] = addr;
16709ef1f84bSDavid du Colombier 	params[2] = preflen;
16719ef1f84bSDavid du Colombier 
16729ef1f84bSDavid du Colombier 	return ipifcadd(ifc, params, 3, 0, lifc);
16739ef1f84bSDavid du Colombier }
1674