xref: /plan9/sys/src/9/ip/ipifc.c (revision c1dd2601e42f5138f07719cdf2819a51c0f6f850)
17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "../port/error.h"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier #include "ip.h"
93ff48bf5SDavid du Colombier #include "ipv6.h"
107dd7cddfSDavid du Colombier 
117dd7cddfSDavid du Colombier #define DPRINT if(0)print
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier enum {
147dd7cddfSDavid du Colombier 	Maxmedia	= 32,
157dd7cddfSDavid du Colombier 	Nself		= Maxmedia*5,
16107aedb4SDavid du Colombier 	NHASH		= 1<<6,
177dd7cddfSDavid du Colombier 	NCACHE		= 256,
187ec5746aSDavid du Colombier 	QMAX		= 192*1024-1,
19*c1dd2601SDavid du Colombier 	Maxv6repr	= (128/(4*4))*(4+1), /* limit of xxxx:xxxx:⋯ notation */
207dd7cddfSDavid du Colombier };
217dd7cddfSDavid du Colombier 
22107aedb4SDavid du Colombier Medium *media[Maxmedia] = { 0 };
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier /*
257dd7cddfSDavid du Colombier  *  cache of local addresses (addresses we answer to)
267dd7cddfSDavid du Colombier  */
277dd7cddfSDavid du Colombier struct Ipself
287dd7cddfSDavid du Colombier {
297dd7cddfSDavid du Colombier 	uchar	a[IPaddrlen];
307dd7cddfSDavid du Colombier 	Ipself	*hnext;		/* next address in the hash table */
317dd7cddfSDavid du Colombier 	Iplink	*link;		/* binding twixt Ipself and Ipifc */
327dd7cddfSDavid du Colombier 	ulong	expire;
337dd7cddfSDavid du Colombier 	uchar	type;		/* type of address */
347dd7cddfSDavid du Colombier 	int	ref;
357dd7cddfSDavid du Colombier 	Ipself	*next;		/* free list */
367dd7cddfSDavid du Colombier };
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier struct Ipselftab
397dd7cddfSDavid du Colombier {
407dd7cddfSDavid du Colombier 	QLock;
417dd7cddfSDavid du Colombier 	int	inited;
427dd7cddfSDavid du Colombier 	int	acceptall;	/* true if an interface has the null address */
437dd7cddfSDavid du Colombier 	Ipself	*hash[NHASH];	/* hash chains */
447dd7cddfSDavid du Colombier };
457dd7cddfSDavid du Colombier 
467dd7cddfSDavid du Colombier /*
477dd7cddfSDavid du Colombier  *  Multicast addresses are chained onto a Chan so that
487dd7cddfSDavid du Colombier  *  we can remove them when the Chan is closed.
497dd7cddfSDavid du Colombier  */
507dd7cddfSDavid du Colombier typedef struct Ipmcast Ipmcast;
517dd7cddfSDavid du Colombier struct Ipmcast
527dd7cddfSDavid du Colombier {
537dd7cddfSDavid du Colombier 	Ipmcast	*next;
547dd7cddfSDavid du Colombier 	uchar	ma[IPaddrlen];	/* multicast address */
557dd7cddfSDavid du Colombier 	uchar	ia[IPaddrlen];	/* interface address */
567dd7cddfSDavid du Colombier };
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier /* quick hash for ip addresses */
597dd7cddfSDavid du Colombier #define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )
607dd7cddfSDavid du Colombier 
617dd7cddfSDavid du Colombier static char tifc[] = "ifc ";
627dd7cddfSDavid du Colombier 
637dd7cddfSDavid du Colombier static void	addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
647dd7cddfSDavid du Colombier static void	remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
657dd7cddfSDavid du Colombier static char*	ipifcjoinmulti(Ipifc *ifc, char **argv, int argc);
667dd7cddfSDavid du Colombier static char*	ipifcleavemulti(Ipifc *ifc, char **argv, int argc);
677dd7cddfSDavid du Colombier static void	ipifcregisterproxy(Fs*, Ipifc*, uchar*);
6839734e7eSDavid du Colombier static char*	ipifcremlifc(Ipifc*, Iplifc*);
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier /*
717dd7cddfSDavid du Colombier  *  link in a new medium
727dd7cddfSDavid du Colombier  */
737dd7cddfSDavid du Colombier void
addipmedium(Medium * med)747dd7cddfSDavid du Colombier addipmedium(Medium *med)
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier 	int i;
777dd7cddfSDavid du Colombier 
787dd7cddfSDavid du Colombier 	for(i = 0; i < nelem(media)-1; i++)
797dd7cddfSDavid du Colombier 		if(media[i] == nil){
807dd7cddfSDavid du Colombier 			media[i] = med;
817dd7cddfSDavid du Colombier 			break;
827dd7cddfSDavid du Colombier 		}
837dd7cddfSDavid du Colombier }
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier /*
867dd7cddfSDavid du Colombier  *  find the medium with this name
877dd7cddfSDavid du Colombier  */
887dd7cddfSDavid du Colombier Medium*
ipfindmedium(char * name)897dd7cddfSDavid du Colombier ipfindmedium(char *name)
907dd7cddfSDavid du Colombier {
917dd7cddfSDavid du Colombier 	Medium **mp;
927dd7cddfSDavid du Colombier 
937dd7cddfSDavid du Colombier 	for(mp = media; *mp != nil; mp++)
947dd7cddfSDavid du Colombier 		if(strcmp((*mp)->name, name) == 0)
957dd7cddfSDavid du Colombier 			break;
967dd7cddfSDavid du Colombier 	return *mp;
977dd7cddfSDavid du Colombier }
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier /*
1007dd7cddfSDavid du Colombier  *  attach a device (or pkt driver) to the interface.
10180ee5cbfSDavid du Colombier  *  called with c locked
1027dd7cddfSDavid du Colombier  */
1037dd7cddfSDavid du Colombier static char*
ipifcbind(Conv * c,char ** argv,int argc)1047dd7cddfSDavid du Colombier ipifcbind(Conv *c, char **argv, int argc)
1057dd7cddfSDavid du Colombier {
1067dd7cddfSDavid du Colombier 	Ipifc *ifc;
1077dd7cddfSDavid du Colombier 	Medium *m;
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier 	if(argc < 2)
1107dd7cddfSDavid du Colombier 		return Ebadarg;
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier 	/* bind the device to the interface */
1157dd7cddfSDavid du Colombier 	m = ipfindmedium(argv[1]);
1167dd7cddfSDavid du Colombier 	if(m == nil)
1177dd7cddfSDavid du Colombier 		return "unknown interface type";
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier 	wlock(ifc);
1207dd7cddfSDavid du Colombier 	if(ifc->m != nil){
1217dd7cddfSDavid du Colombier 		wunlock(ifc);
1227dd7cddfSDavid du Colombier 		return "interface already bound";
1237dd7cddfSDavid du Colombier 	}
1247dd7cddfSDavid du Colombier 	if(waserror()){
1257dd7cddfSDavid du Colombier 		wunlock(ifc);
1267dd7cddfSDavid du Colombier 		nexterror();
1277dd7cddfSDavid du Colombier 	}
1287dd7cddfSDavid du Colombier 
129ef9eff0bSDavid du Colombier 	/* do medium specific binding */
1307dd7cddfSDavid du Colombier 	(*m->bind)(ifc, argc, argv);
131ef9eff0bSDavid du Colombier 
132ef9eff0bSDavid du Colombier 	/* set the bound device name */
1337dd7cddfSDavid du Colombier 	if(argc > 2)
1347dd7cddfSDavid du Colombier 		strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
1357dd7cddfSDavid du Colombier 	else
136208510e1SDavid du Colombier 		snprint(ifc->dev, sizeof ifc->dev, "%s%d", m->name, c->x);
1377dd7cddfSDavid du Colombier 	ifc->dev[sizeof(ifc->dev)-1] = 0;
138ef9eff0bSDavid du Colombier 
139ef9eff0bSDavid du Colombier 	/* set up parameters */
1407dd7cddfSDavid du Colombier 	ifc->m = m;
1413f695129SDavid du Colombier 	ifc->mintu = ifc->m->mintu;
1423f695129SDavid du Colombier 	ifc->maxtu = ifc->m->maxtu;
14380ee5cbfSDavid du Colombier 	if(ifc->m->unbindonclose == 0)
1447dd7cddfSDavid du Colombier 		ifc->conv->inuse++;
145107aedb4SDavid du Colombier 	ifc->rp.mflag = 0;		/* default not managed */
1463ff48bf5SDavid du Colombier 	ifc->rp.oflag = 0;
147107aedb4SDavid du Colombier 	ifc->rp.maxraint = 600000;	/* millisecs */
1483ff48bf5SDavid du Colombier 	ifc->rp.minraint = 200000;
149107aedb4SDavid du Colombier 	ifc->rp.linkmtu = 0;		/* no mtu sent */
1503ff48bf5SDavid du Colombier 	ifc->rp.reachtime = 0;
1513ff48bf5SDavid du Colombier 	ifc->rp.rxmitra = 0;
1523ff48bf5SDavid du Colombier 	ifc->rp.ttl = MAXTTL;
153107aedb4SDavid du Colombier 	ifc->rp.routerlt = 3 * ifc->rp.maxraint;
1543ff48bf5SDavid du Colombier 
155ef9eff0bSDavid du Colombier 	/* any ancillary structures (like routes) no longer pertain */
1567dd7cddfSDavid du Colombier 	ifc->ifcid++;
1577dd7cddfSDavid du Colombier 
158ef9eff0bSDavid du Colombier 	/* reopen all the queues closed by a previous unbind */
159ef9eff0bSDavid du Colombier 	qreopen(c->rq);
160ef9eff0bSDavid du Colombier 	qreopen(c->eq);
161ef9eff0bSDavid du Colombier 	qreopen(c->sq);
162ef9eff0bSDavid du Colombier 
1637dd7cddfSDavid du Colombier 	wunlock(ifc);
1647dd7cddfSDavid du Colombier 	poperror();
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier 	return nil;
1677dd7cddfSDavid du Colombier }
1687dd7cddfSDavid du Colombier 
1697dd7cddfSDavid du Colombier /*
1707dd7cddfSDavid du Colombier  *  detach a device from an interface, close the interface
17180ee5cbfSDavid du Colombier  *  called with ifc->conv closed
1727dd7cddfSDavid du Colombier  */
1737dd7cddfSDavid du Colombier static char*
ipifcunbind(Ipifc * ifc)1747dd7cddfSDavid du Colombier ipifcunbind(Ipifc *ifc)
1757dd7cddfSDavid du Colombier {
1763ff48bf5SDavid du Colombier 	char *err;
1777dd7cddfSDavid du Colombier 
1787dd7cddfSDavid du Colombier 	if(waserror()){
1797dd7cddfSDavid du Colombier 		wunlock(ifc);
1807dd7cddfSDavid du Colombier 		nexterror();
1817dd7cddfSDavid du Colombier 	}
1827dd7cddfSDavid du Colombier 	wlock(ifc);
1837dd7cddfSDavid du Colombier 
1847dd7cddfSDavid du Colombier 	/* dissociate routes */
18580ee5cbfSDavid du Colombier 	if(ifc->m != nil && ifc->m->unbindonclose == 0)
1867dd7cddfSDavid du Colombier 		ifc->conv->inuse--;
1877dd7cddfSDavid du Colombier 	ifc->ifcid++;
1887dd7cddfSDavid du Colombier 
189378023d3SDavid du Colombier 	/* disassociate logical interfaces (before zeroing ifc->arg) */
190378023d3SDavid du Colombier 	while(ifc->lifc){
191378023d3SDavid du Colombier 		err = ipifcremlifc(ifc, ifc->lifc);
192378023d3SDavid du Colombier 		/*
193378023d3SDavid du Colombier 		 * note: err non-zero means lifc not found,
194378023d3SDavid du Colombier 		 * which can't happen in this case.
195378023d3SDavid du Colombier 		 */
196378023d3SDavid du Colombier 		if(err)
197378023d3SDavid du Colombier 			error(err);
198378023d3SDavid du Colombier 	}
199378023d3SDavid du Colombier 
2007dd7cddfSDavid du Colombier 	/* disassociate device */
201107aedb4SDavid du Colombier 	if(ifc->m && ifc->m->unbind)
2027dd7cddfSDavid du Colombier 		(*ifc->m->unbind)(ifc);
2037dd7cddfSDavid du Colombier 	memset(ifc->dev, 0, sizeof(ifc->dev));
2047dd7cddfSDavid du Colombier 	ifc->arg = nil;
2059a747e4fSDavid du Colombier 	ifc->reassemble = 0;
2067dd7cddfSDavid du Colombier 
207ef9eff0bSDavid du Colombier 	/* close queues to stop queuing of packets */
208ef9eff0bSDavid du Colombier 	qclose(ifc->conv->rq);
209ef9eff0bSDavid du Colombier 	qclose(ifc->conv->wq);
210ef9eff0bSDavid du Colombier 	qclose(ifc->conv->sq);
2117dd7cddfSDavid du Colombier 
2127dd7cddfSDavid du Colombier 	ifc->m = nil;
2137dd7cddfSDavid du Colombier 	wunlock(ifc);
2147dd7cddfSDavid du Colombier 	poperror();
2157dd7cddfSDavid du Colombier 	return nil;
2167dd7cddfSDavid du Colombier }
2177dd7cddfSDavid du Colombier 
218107aedb4SDavid du Colombier char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag"
219107aedb4SDavid du Colombier " %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt"
220107aedb4SDavid du Colombier " %d pktin %lud pktout %lud errin %lud errout %lud\n";
2213ff48bf5SDavid du Colombier 
22239734e7eSDavid du Colombier char slineformat[] = "	%-40I %-10M %-40I %-12lud %-12lud\n";
2233ff48bf5SDavid du Colombier 
2247dd7cddfSDavid du Colombier static int
ipifcstate(Conv * c,char * state,int n)2257dd7cddfSDavid du Colombier ipifcstate(Conv *c, char *state, int n)
2267dd7cddfSDavid du Colombier {
2277dd7cddfSDavid du Colombier 	Ipifc *ifc;
2287dd7cddfSDavid du Colombier 	Iplifc *lifc;
2297dd7cddfSDavid du Colombier 	int m;
2307dd7cddfSDavid du Colombier 
2317dd7cddfSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
2323ff48bf5SDavid du Colombier 	m = snprint(state, n, sfixedformat,
2333f695129SDavid du Colombier 		ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
2343ff48bf5SDavid du Colombier 		ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
2353ff48bf5SDavid du Colombier 		ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
2363ff48bf5SDavid du Colombier 		ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
2373ff48bf5SDavid du Colombier 		ifc->in, ifc->out, ifc->inerr, ifc->outerr);
2387dd7cddfSDavid du Colombier 
2397dd7cddfSDavid du Colombier 	rlock(ifc);
2407dd7cddfSDavid du Colombier 	for(lifc = ifc->lifc; lifc && n > m; lifc = lifc->next)
241107aedb4SDavid du Colombier 		m += snprint(state+m, n - m, slineformat, lifc->local,
242107aedb4SDavid du Colombier 			lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
2437dd7cddfSDavid du Colombier 	if(ifc->lifc == nil)
2447dd7cddfSDavid du Colombier 		m += snprint(state+m, n - m, "\n");
2457dd7cddfSDavid du Colombier 	runlock(ifc);
2467dd7cddfSDavid du Colombier 	return m;
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier 
2497dd7cddfSDavid du Colombier static int
ipifclocal(Conv * c,char * state,int n)2507dd7cddfSDavid du Colombier ipifclocal(Conv *c, char *state, int n)
2517dd7cddfSDavid du Colombier {
2527dd7cddfSDavid du Colombier 	Ipifc *ifc;
2537dd7cddfSDavid du Colombier 	Iplifc *lifc;
2547dd7cddfSDavid du Colombier 	Iplink *link;
2557dd7cddfSDavid du Colombier 	int m;
2567dd7cddfSDavid du Colombier 
2577dd7cddfSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
2587dd7cddfSDavid du Colombier 	m = 0;
2597dd7cddfSDavid du Colombier 
2607dd7cddfSDavid du Colombier 	rlock(ifc);
2617dd7cddfSDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
2623ff48bf5SDavid du Colombier 		m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
2637dd7cddfSDavid du Colombier 		for(link = lifc->link; link; link = link->lifclink)
2643ff48bf5SDavid du Colombier 			m += snprint(state+m, n - m, " %-40.40I", link->self->a);
2657dd7cddfSDavid du Colombier 		m += snprint(state+m, n - m, "\n");
2667dd7cddfSDavid du Colombier 	}
2677dd7cddfSDavid du Colombier 	runlock(ifc);
2687dd7cddfSDavid du Colombier 	return m;
2697dd7cddfSDavid du Colombier }
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier static int
ipifcinuse(Conv * c)2727dd7cddfSDavid du Colombier ipifcinuse(Conv *c)
2737dd7cddfSDavid du Colombier {
2747dd7cddfSDavid du Colombier 	Ipifc *ifc;
2757dd7cddfSDavid du Colombier 
2767dd7cddfSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
2777dd7cddfSDavid du Colombier 	return ifc->m != nil;
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier /*
2817dd7cddfSDavid du Colombier  *  called when a process writes to an interface's 'data'
2827dd7cddfSDavid du Colombier  */
2837dd7cddfSDavid du Colombier static void
ipifckick(void * x)2843ff48bf5SDavid du Colombier ipifckick(void *x)
2857dd7cddfSDavid du Colombier {
2863ff48bf5SDavid du Colombier 	Conv *c = x;
2877dd7cddfSDavid du Colombier 	Block *bp;
2887dd7cddfSDavid du Colombier 	Ipifc *ifc;
2897dd7cddfSDavid du Colombier 
2907dd7cddfSDavid du Colombier 	bp = qget(c->wq);
2917dd7cddfSDavid du Colombier 	if(bp == nil)
2927dd7cddfSDavid du Colombier 		return;
2937dd7cddfSDavid du Colombier 
2947dd7cddfSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
29504b73bddSDavid du Colombier 	if(!canrlock(ifc)){
29604b73bddSDavid du Colombier 		freeb(bp);
29704b73bddSDavid du Colombier 		return;
29804b73bddSDavid du Colombier 	}
29904b73bddSDavid du Colombier 	if(waserror()){
30004b73bddSDavid du Colombier 		runlock(ifc);
30104b73bddSDavid du Colombier 		nexterror();
30204b73bddSDavid du Colombier 	}
3037dd7cddfSDavid du Colombier 	if(ifc->m == nil || ifc->m->pktin == nil)
3047dd7cddfSDavid du Colombier 		freeb(bp);
3057dd7cddfSDavid du Colombier 	else
3067dd7cddfSDavid du Colombier 		(*ifc->m->pktin)(c->p->f, ifc, bp);
30704b73bddSDavid du Colombier 	runlock(ifc);
308eaa278a2SDavid du Colombier 	poperror();
3097dd7cddfSDavid du Colombier }
3107dd7cddfSDavid du Colombier 
3117dd7cddfSDavid du Colombier /*
312ef9eff0bSDavid du Colombier  *  called when a new ipifc structure is created
3137dd7cddfSDavid du Colombier  */
3147dd7cddfSDavid du Colombier static void
ipifccreate(Conv * c)3157dd7cddfSDavid du Colombier ipifccreate(Conv *c)
3167dd7cddfSDavid du Colombier {
3177dd7cddfSDavid du Colombier 	Ipifc *ifc;
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier 	c->rq = qopen(QMAX, 0, 0, 0);
3207ec5746aSDavid du Colombier 	c->sq = qopen(QMAX, 0, 0, 0);
3213ff48bf5SDavid du Colombier 	c->wq = qopen(QMAX, Qkick, ipifckick, c);
3227dd7cddfSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
3237dd7cddfSDavid du Colombier 	ifc->conv = c;
3247dd7cddfSDavid du Colombier 	ifc->unbinding = 0;
3257dd7cddfSDavid du Colombier 	ifc->m = nil;
3269a747e4fSDavid du Colombier 	ifc->reassemble = 0;
3277dd7cddfSDavid du Colombier }
3287dd7cddfSDavid du Colombier 
3297dd7cddfSDavid du Colombier /*
3307dd7cddfSDavid du Colombier  *  called after last close of ipifc data or ctl
3317dd7cddfSDavid du Colombier  *  called with c locked, we must unlock
3327dd7cddfSDavid du Colombier  */
3337dd7cddfSDavid du Colombier static void
ipifcclose(Conv * c)3347dd7cddfSDavid du Colombier ipifcclose(Conv *c)
3357dd7cddfSDavid du Colombier {
3367dd7cddfSDavid du Colombier 	Ipifc *ifc;
3377dd7cddfSDavid du Colombier 	Medium *m;
3387dd7cddfSDavid du Colombier 
3397dd7cddfSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
3407dd7cddfSDavid du Colombier 	m = ifc->m;
341107aedb4SDavid du Colombier 	if(m && m->unbindonclose)
3427dd7cddfSDavid du Colombier 		ipifcunbind(ifc);
3437dd7cddfSDavid du Colombier }
3447dd7cddfSDavid du Colombier 
3457dd7cddfSDavid du Colombier /*
3467dd7cddfSDavid du Colombier  *  change an interface's mtu
3477dd7cddfSDavid du Colombier  */
3487dd7cddfSDavid du Colombier char*
ipifcsetmtu(Ipifc * ifc,char ** argv,int argc)3497dd7cddfSDavid du Colombier ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
3507dd7cddfSDavid du Colombier {
3517dd7cddfSDavid du Colombier 	int mtu;
3527dd7cddfSDavid du Colombier 
353107aedb4SDavid du Colombier 	if(argc < 2 || ifc->m == nil)
3547dd7cddfSDavid du Colombier 		return Ebadarg;
3557dd7cddfSDavid du Colombier 	mtu = strtoul(argv[1], 0, 0);
3563f695129SDavid du Colombier 	if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
3577dd7cddfSDavid du Colombier 		return Ebadarg;
3583f695129SDavid du Colombier 	ifc->maxtu = mtu;
3597dd7cddfSDavid du Colombier 	return nil;
3607dd7cddfSDavid du Colombier }
3617dd7cddfSDavid du Colombier 
3627dd7cddfSDavid du Colombier /*
3637dd7cddfSDavid du Colombier  *  add an address to an interface.
3647dd7cddfSDavid du Colombier  */
3657dd7cddfSDavid du Colombier char*
ipifcadd(Ipifc * ifc,char ** argv,int argc,int tentative,Iplifc * lifcp)3663ff48bf5SDavid du Colombier ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
3677dd7cddfSDavid du Colombier {
368107aedb4SDavid du Colombier 	int i, type, mtu, sendnbrdisc = 0;
3697dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
3707dd7cddfSDavid du Colombier 	uchar bcast[IPaddrlen], net[IPaddrlen];
3717dd7cddfSDavid du Colombier 	Iplifc *lifc, **l;
3727dd7cddfSDavid du Colombier 	Fs *f;
3737dd7cddfSDavid du Colombier 
3747dd7cddfSDavid du Colombier 	if(ifc->m == nil)
3757dd7cddfSDavid du Colombier 		return "ipifc not yet bound to device";
3767dd7cddfSDavid du Colombier 
3777dd7cddfSDavid du Colombier 	f = ifc->conv->p->f;
3787dd7cddfSDavid du Colombier 
3797dd7cddfSDavid du Colombier 	type = Rifc;
3807dd7cddfSDavid du Colombier 	memset(ip, 0, IPaddrlen);
3817dd7cddfSDavid du Colombier 	memset(mask, 0, IPaddrlen);
3827dd7cddfSDavid du Colombier 	memset(rem, 0, IPaddrlen);
3837dd7cddfSDavid du Colombier 	switch(argc){
3847dd7cddfSDavid du Colombier 	case 6:
3857dd7cddfSDavid du Colombier 		if(strcmp(argv[5], "proxy") == 0)
3867dd7cddfSDavid du Colombier 			type |= Rproxy;
3877dd7cddfSDavid du Colombier 		/* fall through */
3887dd7cddfSDavid du Colombier 	case 5:
3897dd7cddfSDavid du Colombier 		mtu = strtoul(argv[4], 0, 0);
3903f695129SDavid du Colombier 		if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
3913f695129SDavid du Colombier 			ifc->maxtu = mtu;
3927dd7cddfSDavid du Colombier 		/* fall through */
3937dd7cddfSDavid du Colombier 	case 4:
394ea58ad6fSDavid du Colombier 		if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
395ea58ad6fSDavid du Colombier 			return Ebadip;
3967dd7cddfSDavid du Colombier 		parseipmask(mask, argv[2]);
3977dd7cddfSDavid du Colombier 		maskip(rem, mask, net);
3987dd7cddfSDavid du Colombier 		break;
3997dd7cddfSDavid du Colombier 	case 3:
400ea58ad6fSDavid du Colombier 		if (parseip(ip, argv[1]) == -1)
401ea58ad6fSDavid du Colombier 			return Ebadip;
4027dd7cddfSDavid du Colombier 		parseipmask(mask, argv[2]);
4037dd7cddfSDavid du Colombier 		maskip(ip, mask, rem);
4047dd7cddfSDavid du Colombier 		maskip(rem, mask, net);
4057dd7cddfSDavid du Colombier 		break;
4067dd7cddfSDavid du Colombier 	case 2:
407ea58ad6fSDavid du Colombier 		if (parseip(ip, argv[1]) == -1)
408ea58ad6fSDavid du Colombier 			return Ebadip;
4097dd7cddfSDavid du Colombier 		memmove(mask, defmask(ip), IPaddrlen);
4107dd7cddfSDavid du Colombier 		maskip(ip, mask, rem);
4117dd7cddfSDavid du Colombier 		maskip(rem, mask, net);
4127dd7cddfSDavid du Colombier 		break;
4137dd7cddfSDavid du Colombier 	default:
4147dd7cddfSDavid du Colombier 		return Ebadarg;
4157dd7cddfSDavid du Colombier 	}
4163ff48bf5SDavid du Colombier 	if(isv4(ip))
4173ff48bf5SDavid du Colombier 		tentative = 0;
4187dd7cddfSDavid du Colombier 	wlock(ifc);
4197dd7cddfSDavid du Colombier 
4207dd7cddfSDavid du Colombier 	/* ignore if this is already a local address for this ifc */
421f2c197d9SDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
4223ff48bf5SDavid du Colombier 		if(ipcmp(lifc->local, ip) == 0) {
4233ff48bf5SDavid du Colombier 			if(lifc->tentative != tentative)
4243ff48bf5SDavid du Colombier 				lifc->tentative = tentative;
4253179bee6SDavid du Colombier 			if(lifcp) {
4263ff48bf5SDavid du Colombier 				lifc->onlink = lifcp->onlink;
4273ff48bf5SDavid du Colombier 				lifc->autoflag = lifcp->autoflag;
4283ff48bf5SDavid du Colombier 				lifc->validlt = lifcp->validlt;
4293ff48bf5SDavid du Colombier 				lifc->preflt = lifcp->preflt;
4303ff48bf5SDavid du Colombier 				lifc->origint = lifcp->origint;
4313ff48bf5SDavid du Colombier 			}
4327dd7cddfSDavid du Colombier 			goto out;
4333ff48bf5SDavid du Colombier 		}
434f2c197d9SDavid du Colombier 	}
4357dd7cddfSDavid du Colombier 
4367dd7cddfSDavid du Colombier 	/* add the address to the list of logical ifc's for this ifc */
4377dd7cddfSDavid du Colombier 	lifc = smalloc(sizeof(Iplifc));
4387dd7cddfSDavid du Colombier 	ipmove(lifc->local, ip);
4397dd7cddfSDavid du Colombier 	ipmove(lifc->mask, mask);
4407dd7cddfSDavid du Colombier 	ipmove(lifc->remote, rem);
4417dd7cddfSDavid du Colombier 	ipmove(lifc->net, net);
4423ff48bf5SDavid du Colombier 	lifc->tentative = tentative;
4433179bee6SDavid du Colombier 	if(lifcp) {
4443ff48bf5SDavid du Colombier 		lifc->onlink = lifcp->onlink;
4453ff48bf5SDavid du Colombier 		lifc->autoflag = lifcp->autoflag;
4463ff48bf5SDavid du Colombier 		lifc->validlt = lifcp->validlt;
4473ff48bf5SDavid du Colombier 		lifc->preflt = lifcp->preflt;
4483ff48bf5SDavid du Colombier 		lifc->origint = lifcp->origint;
449107aedb4SDavid du Colombier 	} else {		/* default values */
4503179bee6SDavid du Colombier 		lifc->onlink = lifc->autoflag = 1;
4513179bee6SDavid du Colombier 		lifc->validlt = lifc->preflt = ~0L;
452107aedb4SDavid du Colombier 		lifc->origint = NOW / 1000;
4533ff48bf5SDavid du Colombier 	}
4547dd7cddfSDavid du Colombier 	lifc->next = nil;
4553ff48bf5SDavid du Colombier 
4567dd7cddfSDavid du Colombier 	for(l = &ifc->lifc; *l; l = &(*l)->next)
4577dd7cddfSDavid du Colombier 		;
4587dd7cddfSDavid du Colombier 	*l = lifc;
4597dd7cddfSDavid du Colombier 
4603ff48bf5SDavid du Colombier 	/* check for point-to-point interface */
4613ff48bf5SDavid du Colombier 	if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
46239734e7eSDavid du Colombier 	if(ipcmp(mask, IPallbits) == 0)
4637dd7cddfSDavid du Colombier 		type |= Rptpt;
4643ff48bf5SDavid du Colombier 
4653ff48bf5SDavid du Colombier 	/* add local routes */
4667dd7cddfSDavid du Colombier 	if(isv4(ip))
4679a747e4fSDavid du Colombier 		v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
4687dd7cddfSDavid du Colombier 	else
4699a747e4fSDavid du Colombier 		v6addroute(f, tifc, rem, mask, rem, type);
4707dd7cddfSDavid du Colombier 
4717dd7cddfSDavid du Colombier 	addselfcache(f, ifc, lifc, ip, Runi);
4727dd7cddfSDavid du Colombier 
4735d82c6aeSDavid du Colombier 	if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){
4747dd7cddfSDavid du Colombier 		ipifcregisterproxy(f, ifc, rem);
4757dd7cddfSDavid du Colombier 		goto out;
4767dd7cddfSDavid du Colombier 	}
4777dd7cddfSDavid du Colombier 
4783ff48bf5SDavid du Colombier 	if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
4793ff48bf5SDavid du Colombier 		/* add subnet directed broadcast address to the self cache */
4807dd7cddfSDavid du Colombier 		for(i = 0; i < IPaddrlen; i++)
4817dd7cddfSDavid du Colombier 			bcast[i] = (ip[i] & mask[i]) | ~mask[i];
4827dd7cddfSDavid du Colombier 		addselfcache(f, ifc, lifc, bcast, Rbcast);
4837dd7cddfSDavid du Colombier 
4843ff48bf5SDavid du Colombier 		/* add subnet directed network address to the self cache */
4857dd7cddfSDavid du Colombier 		for(i = 0; i < IPaddrlen; i++)
4867dd7cddfSDavid du Colombier 			bcast[i] = (ip[i] & mask[i]) & mask[i];
4877dd7cddfSDavid du Colombier 		addselfcache(f, ifc, lifc, bcast, Rbcast);
4887dd7cddfSDavid du Colombier 
4893ff48bf5SDavid du Colombier 		/* add network directed broadcast address to the self cache */
4907dd7cddfSDavid du Colombier 		memmove(mask, defmask(ip), IPaddrlen);
4917dd7cddfSDavid du Colombier 		for(i = 0; i < IPaddrlen; i++)
4927dd7cddfSDavid du Colombier 			bcast[i] = (ip[i] & mask[i]) | ~mask[i];
4937dd7cddfSDavid du Colombier 		addselfcache(f, ifc, lifc, bcast, Rbcast);
4947dd7cddfSDavid du Colombier 
4953ff48bf5SDavid du Colombier 		/* add network directed network address to the self cache */
4967dd7cddfSDavid du Colombier 		memmove(mask, defmask(ip), IPaddrlen);
4977dd7cddfSDavid du Colombier 		for(i = 0; i < IPaddrlen; i++)
4987dd7cddfSDavid du Colombier 			bcast[i] = (ip[i] & mask[i]) & mask[i];
4997dd7cddfSDavid du Colombier 		addselfcache(f, ifc, lifc, bcast, Rbcast);
5007dd7cddfSDavid du Colombier 
5017dd7cddfSDavid du Colombier 		addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
502f2c197d9SDavid du Colombier 	}
503f2c197d9SDavid du Colombier 	else {
5043ff48bf5SDavid du Colombier 		if(ipcmp(ip, v6loopback) == 0) {
5053ff48bf5SDavid du Colombier 			/* add node-local mcast address */
5063ff48bf5SDavid du Colombier 			addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
5073ff48bf5SDavid du Colombier 
5083ff48bf5SDavid du Colombier 			/* add route for all node multicast */
509107aedb4SDavid du Colombier 			v6addroute(f, tifc, v6allnodesN, v6allnodesNmask,
510107aedb4SDavid du Colombier 				v6allnodesN, Rmulti);
5113ff48bf5SDavid du Colombier 		}
5123ff48bf5SDavid du Colombier 
51367493d07SDavid du Colombier 		/* add all nodes multicast address */
5143ff48bf5SDavid du Colombier 		addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
5153ff48bf5SDavid du Colombier 
51667493d07SDavid du Colombier 		/* add route for all nodes multicast */
517107aedb4SDavid du Colombier 		v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL,
518107aedb4SDavid du Colombier 			Rmulti);
5193ff48bf5SDavid du Colombier 
5203ff48bf5SDavid du Colombier 		/* add solicited-node multicast address */
5213ff48bf5SDavid du Colombier 		ipv62smcast(bcast, ip);
5223ff48bf5SDavid du Colombier 		addselfcache(f, ifc, lifc, bcast, Rmulti);
5233ff48bf5SDavid du Colombier 
5243ff48bf5SDavid du Colombier 		sendnbrdisc = 1;
5253ff48bf5SDavid du Colombier 	}
5267dd7cddfSDavid du Colombier 
5277dd7cddfSDavid du Colombier 	/* register the address on this network for address resolution */
5283ff48bf5SDavid du Colombier 	if(isv4(ip) && ifc->m->areg != nil)
5297dd7cddfSDavid du Colombier 		(*ifc->m->areg)(ifc, ip);
5307dd7cddfSDavid du Colombier 
5317dd7cddfSDavid du Colombier out:
5327dd7cddfSDavid du Colombier 	wunlock(ifc);
5333ff48bf5SDavid du Colombier 	if(tentative && sendnbrdisc)
5343ff48bf5SDavid du Colombier 		icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
5357dd7cddfSDavid du Colombier 	return nil;
5367dd7cddfSDavid du Colombier }
5377dd7cddfSDavid du Colombier 
5387dd7cddfSDavid du Colombier /*
53939734e7eSDavid du Colombier  *  remove a logical interface from an ifc
54039734e7eSDavid du Colombier  *  always called with ifc wlock'd
5417dd7cddfSDavid du Colombier  */
54239734e7eSDavid du Colombier static char*
ipifcremlifc(Ipifc * ifc,Iplifc * lifc)54339734e7eSDavid du Colombier ipifcremlifc(Ipifc *ifc, Iplifc *lifc)
5447dd7cddfSDavid du Colombier {
54539734e7eSDavid du Colombier 	Iplifc **l;
5467dd7cddfSDavid du Colombier 	Fs *f;
5477dd7cddfSDavid du Colombier 
5487dd7cddfSDavid du Colombier 	f = ifc->conv->p->f;
5497dd7cddfSDavid du Colombier 
5507dd7cddfSDavid du Colombier 	/*
5517dd7cddfSDavid du Colombier 	 *  find address on this interface and remove from chain.
552ef9eff0bSDavid du Colombier 	 *  for pt to pt we actually specify the remote address as the
5537dd7cddfSDavid du Colombier 	 *  addresss to remove.
5547dd7cddfSDavid du Colombier 	 */
55539734e7eSDavid du Colombier 	for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next)
55639734e7eSDavid du Colombier 		;
55739734e7eSDavid du Colombier 	if(*l == nil)
5587dd7cddfSDavid du Colombier 		return "address not on this interface";
55939734e7eSDavid du Colombier 	*l = lifc->next;
5607dd7cddfSDavid du Colombier 
5617dd7cddfSDavid du Colombier 	/* disassociate any addresses */
5627dd7cddfSDavid du Colombier 	while(lifc->link)
5637dd7cddfSDavid du Colombier 		remselfcache(f, ifc, lifc, lifc->link->self->a);
5647dd7cddfSDavid du Colombier 
5657dd7cddfSDavid du Colombier 	/* remove the route for this logical interface */
56639734e7eSDavid du Colombier 	if(isv4(lifc->local))
5677dd7cddfSDavid du Colombier 		v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
5683ff48bf5SDavid du Colombier 	else {
5697dd7cddfSDavid du Colombier 		v6delroute(f, lifc->remote, lifc->mask, 1);
57039734e7eSDavid du Colombier 		if(ipcmp(lifc->local, v6loopback) == 0)
5713ff48bf5SDavid du Colombier 			/* remove route for all node multicast */
5723ff48bf5SDavid du Colombier 			v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
57367493d07SDavid du Colombier 		else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
5743ff48bf5SDavid du Colombier 			/* remove route for all link multicast */
5753ff48bf5SDavid du Colombier 			v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
5763ff48bf5SDavid du Colombier 	}
5777dd7cddfSDavid du Colombier 
5787dd7cddfSDavid du Colombier 	free(lifc);
5797dd7cddfSDavid du Colombier 	return nil;
58039734e7eSDavid du Colombier }
58139734e7eSDavid du Colombier 
58239734e7eSDavid du Colombier /*
58339734e7eSDavid du Colombier  *  remove an address from an interface.
58439734e7eSDavid du Colombier  *  called with c->car locked
58539734e7eSDavid du Colombier  */
58639734e7eSDavid du Colombier char*
ipifcrem(Ipifc * ifc,char ** argv,int argc)58739734e7eSDavid du Colombier ipifcrem(Ipifc *ifc, char **argv, int argc)
58839734e7eSDavid du Colombier {
58939734e7eSDavid du Colombier 	char *rv;
590107aedb4SDavid du Colombier 	uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
591107aedb4SDavid du Colombier 	Iplifc *lifc;
59239734e7eSDavid du Colombier 
59339734e7eSDavid du Colombier 	if(argc < 3)
59439734e7eSDavid du Colombier 		return Ebadarg;
59539734e7eSDavid du Colombier 
596ea58ad6fSDavid du Colombier 	if (parseip(ip, argv[1]) == -1)
597ea58ad6fSDavid du Colombier 		return Ebadip;
59839734e7eSDavid du Colombier 	parseipmask(mask, argv[2]);
59939734e7eSDavid du Colombier 	if(argc < 4)
60039734e7eSDavid du Colombier 		maskip(ip, mask, rem);
60139734e7eSDavid du Colombier 	else
602ea58ad6fSDavid du Colombier 		if (parseip(rem, argv[3]) == -1)
603ea58ad6fSDavid du Colombier 			return Ebadip;
60439734e7eSDavid du Colombier 
60539734e7eSDavid du Colombier 	wlock(ifc);
60639734e7eSDavid du Colombier 
60739734e7eSDavid du Colombier 	/*
60839734e7eSDavid du Colombier 	 *  find address on this interface and remove from chain.
60939734e7eSDavid du Colombier 	 *  for pt to pt we actually specify the remote address as the
61039734e7eSDavid du Colombier 	 *  addresss to remove.
61139734e7eSDavid du Colombier 	 */
612f2c197d9SDavid du Colombier 	for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
61339734e7eSDavid du Colombier 		if (memcmp(ip, lifc->local, IPaddrlen) == 0
61439734e7eSDavid du Colombier 		&& memcmp(mask, lifc->mask, IPaddrlen) == 0
61539734e7eSDavid du Colombier 		&& memcmp(rem, lifc->remote, IPaddrlen) == 0)
61639734e7eSDavid du Colombier 			break;
617f2c197d9SDavid du Colombier 	}
61839734e7eSDavid du Colombier 
61939734e7eSDavid du Colombier 	rv = ipifcremlifc(ifc, lifc);
62039734e7eSDavid du Colombier 	wunlock(ifc);
62139734e7eSDavid du Colombier 	return rv;
6227dd7cddfSDavid du Colombier }
6237dd7cddfSDavid du Colombier 
6247dd7cddfSDavid du Colombier /*
6253ff48bf5SDavid du Colombier  * distribute routes to active interfaces like the
6267dd7cddfSDavid du Colombier  * TRIP linecards
6277dd7cddfSDavid du Colombier  */
6287dd7cddfSDavid du Colombier void
ipifcaddroute(Fs * f,int vers,uchar * addr,uchar * mask,uchar * gate,int type)6297dd7cddfSDavid du Colombier ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
6307dd7cddfSDavid du Colombier {
6317dd7cddfSDavid du Colombier 	Medium *m;
6327dd7cddfSDavid du Colombier 	Conv **cp, **e;
6337dd7cddfSDavid du Colombier 	Ipifc *ifc;
6347dd7cddfSDavid du Colombier 
6357dd7cddfSDavid du Colombier 	e = &f->ipifc->conv[f->ipifc->nc];
636f2c197d9SDavid du Colombier 	for(cp = f->ipifc->conv; cp < e; cp++){
6377dd7cddfSDavid du Colombier 		if(*cp != nil) {
6387dd7cddfSDavid du Colombier 			ifc = (Ipifc*)(*cp)->ptcl;
6397dd7cddfSDavid du Colombier 			m = ifc->m;
640107aedb4SDavid du Colombier 			if(m && m->addroute)
6417dd7cddfSDavid du Colombier 				m->addroute(ifc, vers, addr, mask, gate, type);
6427dd7cddfSDavid du Colombier 		}
6437dd7cddfSDavid du Colombier 	}
644f2c197d9SDavid du Colombier }
6457dd7cddfSDavid du Colombier 
6467dd7cddfSDavid du Colombier void
ipifcremroute(Fs * f,int vers,uchar * addr,uchar * mask)6477dd7cddfSDavid du Colombier ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
6487dd7cddfSDavid du Colombier {
6497dd7cddfSDavid du Colombier 	Medium *m;
6507dd7cddfSDavid du Colombier 	Conv **cp, **e;
6517dd7cddfSDavid du Colombier 	Ipifc *ifc;
6527dd7cddfSDavid du Colombier 
6537dd7cddfSDavid du Colombier 	e = &f->ipifc->conv[f->ipifc->nc];
654f2c197d9SDavid du Colombier 	for(cp = f->ipifc->conv; cp < e; cp++){
6557dd7cddfSDavid du Colombier 		if(*cp != nil) {
6567dd7cddfSDavid du Colombier 			ifc = (Ipifc*)(*cp)->ptcl;
6577dd7cddfSDavid du Colombier 			m = ifc->m;
658107aedb4SDavid du Colombier 			if(m && m->remroute)
6597dd7cddfSDavid du Colombier 				m->remroute(ifc, vers, addr, mask);
6607dd7cddfSDavid du Colombier 		}
6617dd7cddfSDavid du Colombier 	}
662f2c197d9SDavid du Colombier }
6637dd7cddfSDavid du Colombier 
6647dd7cddfSDavid du Colombier /*
6657dd7cddfSDavid du Colombier  *  associate an address with the interface.  This wipes out any previous
6667dd7cddfSDavid du Colombier  *  addresses.  This is a macro that means, remove all the old interfaces
6677dd7cddfSDavid du Colombier  *  and add a new one.
6687dd7cddfSDavid du Colombier  */
6697dd7cddfSDavid du Colombier static char*
ipifcconnect(Conv * c,char ** argv,int argc)6707dd7cddfSDavid du Colombier ipifcconnect(Conv* c, char **argv, int argc)
6717dd7cddfSDavid du Colombier {
6727dd7cddfSDavid du Colombier 	char *err;
6737dd7cddfSDavid du Colombier 	Ipifc *ifc;
6747dd7cddfSDavid du Colombier 
6757dd7cddfSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
6767dd7cddfSDavid du Colombier 
6777dd7cddfSDavid du Colombier 	if(ifc->m == nil)
6787dd7cddfSDavid du Colombier 		 return "ipifc not yet bound to device";
6797dd7cddfSDavid du Colombier 
6807dd7cddfSDavid du Colombier 	if(waserror()){
6817dd7cddfSDavid du Colombier 		wunlock(ifc);
6827dd7cddfSDavid du Colombier 		nexterror();
6837dd7cddfSDavid du Colombier 	}
6847dd7cddfSDavid du Colombier 	wlock(ifc);
6857dd7cddfSDavid du Colombier 	while(ifc->lifc){
68639734e7eSDavid du Colombier 		err = ipifcremlifc(ifc, ifc->lifc);
68739734e7eSDavid du Colombier 		if(err)
68839734e7eSDavid du Colombier 			error(err);
6897dd7cddfSDavid du Colombier 	}
6907dd7cddfSDavid du Colombier 	wunlock(ifc);
6917dd7cddfSDavid du Colombier 	poperror();
6927dd7cddfSDavid du Colombier 
6933ff48bf5SDavid du Colombier 	err = ipifcadd(ifc, argv, argc, 0, nil);
6947dd7cddfSDavid du Colombier 	if(err)
6957dd7cddfSDavid du Colombier 		return err;
6967dd7cddfSDavid du Colombier 
6977dd7cddfSDavid du Colombier 	Fsconnected(c, nil);
6987dd7cddfSDavid du Colombier 	return nil;
6997dd7cddfSDavid du Colombier }
7007dd7cddfSDavid du Colombier 
7013ff48bf5SDavid du Colombier char*
ipifcra6(Ipifc * ifc,char ** argv,int argc)7023179bee6SDavid du Colombier ipifcra6(Ipifc *ifc, char **argv, int argc)
7033ff48bf5SDavid du Colombier {
7043ff48bf5SDavid du Colombier 	int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
7053ff48bf5SDavid du Colombier 
7063ff48bf5SDavid du Colombier 	argsleft = argc - 1;
7073ff48bf5SDavid du Colombier 	i = 1;
7083ff48bf5SDavid du Colombier 
7093ff48bf5SDavid du Colombier 	if(argsleft % 2 != 0)
7103ff48bf5SDavid du Colombier 		return Ebadarg;
7113ff48bf5SDavid du Colombier 
7123ff48bf5SDavid du Colombier 	while (argsleft > 1) {
7133ff48bf5SDavid du Colombier 		if(strcmp(argv[i], "recvra") == 0)
7143ff48bf5SDavid du Colombier 			ifc->recvra6 = (atoi(argv[i+1]) != 0);
7153ff48bf5SDavid du Colombier 		else if(strcmp(argv[i], "sendra") == 0)
7163ff48bf5SDavid du Colombier 			ifc->sendra6 = (atoi(argv[i+1]) != 0);
7173ff48bf5SDavid du Colombier 		else if(strcmp(argv[i], "mflag") == 0)
7183ff48bf5SDavid du Colombier 			ifc->rp.mflag = (atoi(argv[i+1]) != 0);
7193ff48bf5SDavid du Colombier 		else if(strcmp(argv[i], "oflag") == 0)
7203ff48bf5SDavid du Colombier 			ifc->rp.oflag = (atoi(argv[i+1]) != 0);
7213ff48bf5SDavid du Colombier 		else if(strcmp(argv[i], "maxraint") == 0)
7223ff48bf5SDavid du Colombier 			ifc->rp.maxraint = atoi(argv[i+1]);
7233ff48bf5SDavid du Colombier 		else if(strcmp(argv[i], "minraint") == 0)
7243ff48bf5SDavid du Colombier 			ifc->rp.minraint = atoi(argv[i+1]);
7253ff48bf5SDavid du Colombier 		else if(strcmp(argv[i], "linkmtu") == 0)
7263ff48bf5SDavid du Colombier 			ifc->rp.linkmtu = atoi(argv[i+1]);
7273ff48bf5SDavid du Colombier 		else if(strcmp(argv[i], "reachtime") == 0)
7283ff48bf5SDavid du Colombier 			ifc->rp.reachtime = atoi(argv[i+1]);
7293ff48bf5SDavid du Colombier 		else if(strcmp(argv[i], "rxmitra") == 0)
7303ff48bf5SDavid du Colombier 			ifc->rp.rxmitra = atoi(argv[i+1]);
7313ff48bf5SDavid du Colombier 		else if(strcmp(argv[i], "ttl") == 0)
7323ff48bf5SDavid du Colombier 			ifc->rp.ttl = atoi(argv[i+1]);
7333ff48bf5SDavid du Colombier 		else if(strcmp(argv[i], "routerlt") == 0)
7343ff48bf5SDavid du Colombier 			ifc->rp.routerlt = atoi(argv[i+1]);
7353ff48bf5SDavid du Colombier 		else
7363ff48bf5SDavid du Colombier 			return Ebadarg;
7373ff48bf5SDavid du Colombier 
7383ff48bf5SDavid du Colombier 		argsleft -= 2;
7393ff48bf5SDavid du Colombier 		i += 2;
7403ff48bf5SDavid du Colombier 	}
7413ff48bf5SDavid du Colombier 
742107aedb4SDavid du Colombier 	/* consistency check */
7433ff48bf5SDavid du Colombier 	if(ifc->rp.maxraint < ifc->rp.minraint) {
7443ff48bf5SDavid du Colombier 		ifc->rp.maxraint = vmax;
7453ff48bf5SDavid du Colombier 		ifc->rp.minraint = vmin;
7463ff48bf5SDavid du Colombier 		return Ebadarg;
7473ff48bf5SDavid du Colombier 	}
7483ff48bf5SDavid du Colombier 	return nil;
7493ff48bf5SDavid du Colombier }
7503ff48bf5SDavid du Colombier 
7517dd7cddfSDavid du Colombier /*
7527dd7cddfSDavid du Colombier  *  non-standard control messages.
7537dd7cddfSDavid du Colombier  *  called with c->car locked.
7547dd7cddfSDavid du Colombier  */
7557dd7cddfSDavid du Colombier static char*
ipifcctl(Conv * c,char ** argv,int argc)7567dd7cddfSDavid du Colombier ipifcctl(Conv* c, char**argv, int argc)
7577dd7cddfSDavid du Colombier {
7587dd7cddfSDavid du Colombier 	Ipifc *ifc;
759f2c197d9SDavid du Colombier 	int i;
7607dd7cddfSDavid du Colombier 
7617dd7cddfSDavid du Colombier 	ifc = (Ipifc*)c->ptcl;
7627dd7cddfSDavid du Colombier 	if(strcmp(argv[0], "add") == 0)
7633ff48bf5SDavid du Colombier 		return ipifcadd(ifc, argv, argc, 0, nil);
7643ff48bf5SDavid du Colombier 	else if(strcmp(argv[0], "try") == 0)
7653ff48bf5SDavid du Colombier 		return ipifcadd(ifc, argv, argc, 1, nil);
7667dd7cddfSDavid du Colombier 	else if(strcmp(argv[0], "remove") == 0)
76739734e7eSDavid du Colombier 		return ipifcrem(ifc, argv, argc);
7687dd7cddfSDavid du Colombier 	else if(strcmp(argv[0], "unbind") == 0)
7697dd7cddfSDavid du Colombier 		return ipifcunbind(ifc);
7707dd7cddfSDavid du Colombier 	else if(strcmp(argv[0], "joinmulti") == 0)
7717dd7cddfSDavid du Colombier 		return ipifcjoinmulti(ifc, argv, argc);
7727dd7cddfSDavid du Colombier 	else if(strcmp(argv[0], "leavemulti") == 0)
7737dd7cddfSDavid du Colombier 		return ipifcleavemulti(ifc, argv, argc);
7747dd7cddfSDavid du Colombier 	else if(strcmp(argv[0], "mtu") == 0)
7757dd7cddfSDavid du Colombier 		return ipifcsetmtu(ifc, argv, argc);
7769a747e4fSDavid du Colombier 	else if(strcmp(argv[0], "reassemble") == 0){
7779a747e4fSDavid du Colombier 		ifc->reassemble = 1;
7789a747e4fSDavid du Colombier 		return nil;
779f2c197d9SDavid du Colombier 	}
780f2c197d9SDavid du Colombier 	else if(strcmp(argv[0], "iprouting") == 0){
781f2c197d9SDavid du Colombier 		i = 1;
782f2c197d9SDavid du Colombier 		if(argc > 1)
783f2c197d9SDavid du Colombier 			i = atoi(argv[1]);
784f2c197d9SDavid du Colombier 		iprouting(c->p->f, i);
7857dd7cddfSDavid du Colombier 		return nil;
786f2c197d9SDavid du Colombier 	}
787f2c197d9SDavid du Colombier 	else if(strcmp(argv[0], "add6") == 0)
7883179bee6SDavid du Colombier 		return ipifcadd6(ifc, argv, argc);
7893179bee6SDavid du Colombier 	else if(strcmp(argv[0], "ra6") == 0)
7903179bee6SDavid du Colombier 		return ipifcra6(ifc, argv, argc);
7917dd7cddfSDavid du Colombier 	return "unsupported ctl";
7927dd7cddfSDavid du Colombier }
7937dd7cddfSDavid du Colombier 
794eed6406fSDavid du Colombier int
ipifcstats(Proto * ipifc,char * buf,int len)7957dd7cddfSDavid du Colombier ipifcstats(Proto *ipifc, char *buf, int len)
7967dd7cddfSDavid du Colombier {
7977dd7cddfSDavid du Colombier 	return ipstats(ipifc->f, buf, len);
7987dd7cddfSDavid du Colombier }
7997dd7cddfSDavid du Colombier 
8007dd7cddfSDavid du Colombier void
ipifcinit(Fs * f)8017dd7cddfSDavid du Colombier ipifcinit(Fs *f)
8027dd7cddfSDavid du Colombier {
8037dd7cddfSDavid du Colombier 	Proto *ipifc;
8047dd7cddfSDavid du Colombier 
80559cc4ca5SDavid du Colombier 	ipifc = smalloc(sizeof(Proto));
8067dd7cddfSDavid du Colombier 	ipifc->name = "ipifc";
8077dd7cddfSDavid du Colombier 	ipifc->connect = ipifcconnect;
8087dd7cddfSDavid du Colombier 	ipifc->announce = nil;
8097dd7cddfSDavid du Colombier 	ipifc->bind = ipifcbind;
8107dd7cddfSDavid du Colombier 	ipifc->state = ipifcstate;
8117dd7cddfSDavid du Colombier 	ipifc->create = ipifccreate;
8127dd7cddfSDavid du Colombier 	ipifc->close = ipifcclose;
8137dd7cddfSDavid du Colombier 	ipifc->rcv = nil;
8147dd7cddfSDavid du Colombier 	ipifc->ctl = ipifcctl;
8157dd7cddfSDavid du Colombier 	ipifc->advise = nil;
8167dd7cddfSDavid du Colombier 	ipifc->stats = ipifcstats;
8177dd7cddfSDavid du Colombier 	ipifc->inuse = ipifcinuse;
8187dd7cddfSDavid du Colombier 	ipifc->local = ipifclocal;
8197dd7cddfSDavid du Colombier 	ipifc->ipproto = -1;
8207dd7cddfSDavid du Colombier 	ipifc->nc = Maxmedia;
8217dd7cddfSDavid du Colombier 	ipifc->ptclsize = sizeof(Ipifc);
8227dd7cddfSDavid du Colombier 
8237dd7cddfSDavid du Colombier 	f->ipifc = ipifc;	/* hack for ipifcremroute, findipifc, ... */
8247dd7cddfSDavid du Colombier 	f->self = smalloc(sizeof(Ipselftab));	/* hack for ipforme */
8257dd7cddfSDavid du Colombier 
8267dd7cddfSDavid du Colombier 	Fsproto(f, ipifc);
8277dd7cddfSDavid du Colombier }
8287dd7cddfSDavid du Colombier 
8297dd7cddfSDavid du Colombier /*
8307dd7cddfSDavid du Colombier  *  add to self routing cache
8317dd7cddfSDavid du Colombier  *	called with c->car locked
8327dd7cddfSDavid du Colombier  */
8337dd7cddfSDavid du Colombier static void
addselfcache(Fs * f,Ipifc * ifc,Iplifc * lifc,uchar * a,int type)8347dd7cddfSDavid du Colombier addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
8357dd7cddfSDavid du Colombier {
8367dd7cddfSDavid du Colombier 	Ipself *p;
8377dd7cddfSDavid du Colombier 	Iplink *lp;
8387dd7cddfSDavid du Colombier 	int h;
8397dd7cddfSDavid du Colombier 
8407dd7cddfSDavid du Colombier 	qlock(f->self);
8417dd7cddfSDavid du Colombier 
8427dd7cddfSDavid du Colombier 	/* see if the address already exists */
8437dd7cddfSDavid du Colombier 	h = hashipa(a);
8447dd7cddfSDavid du Colombier 	for(p = f->self->hash[h]; p; p = p->next)
8457dd7cddfSDavid du Colombier 		if(memcmp(a, p->a, IPaddrlen) == 0)
8467dd7cddfSDavid du Colombier 			break;
8477dd7cddfSDavid du Colombier 
8487dd7cddfSDavid du Colombier 	/* allocate a local address and add to hash chain */
8497dd7cddfSDavid du Colombier 	if(p == nil){
8507dd7cddfSDavid du Colombier 		p = smalloc(sizeof(*p));
8517dd7cddfSDavid du Colombier 		ipmove(p->a, a);
8527dd7cddfSDavid du Colombier 		p->type = type;
8537dd7cddfSDavid du Colombier 		p->next = f->self->hash[h];
8547dd7cddfSDavid du Colombier 		f->self->hash[h] = p;
8557dd7cddfSDavid du Colombier 
8567dd7cddfSDavid du Colombier 		/* if the null address, accept all packets */
8577dd7cddfSDavid du Colombier 		if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
8587dd7cddfSDavid du Colombier 			f->self->acceptall = 1;
8597dd7cddfSDavid du Colombier 	}
8607dd7cddfSDavid du Colombier 
8617dd7cddfSDavid du Colombier 	/* look for a link for this lifc */
8627dd7cddfSDavid du Colombier 	for(lp = p->link; lp; lp = lp->selflink)
8637dd7cddfSDavid du Colombier 		if(lp->lifc == lifc)
8647dd7cddfSDavid du Colombier 			break;
8657dd7cddfSDavid du Colombier 
8667dd7cddfSDavid du Colombier 	/* allocate a lifc-to-local link and link to both */
8677dd7cddfSDavid du Colombier 	if(lp == nil){
8687dd7cddfSDavid du Colombier 		lp = smalloc(sizeof(*lp));
8697dd7cddfSDavid du Colombier 		lp->ref = 1;
8707dd7cddfSDavid du Colombier 		lp->lifc = lifc;
8717dd7cddfSDavid du Colombier 		lp->self = p;
8727dd7cddfSDavid du Colombier 		lp->selflink = p->link;
8737dd7cddfSDavid du Colombier 		p->link = lp;
8747dd7cddfSDavid du Colombier 		lp->lifclink = lifc->link;
8757dd7cddfSDavid du Colombier 		lifc->link = lp;
8767dd7cddfSDavid du Colombier 
8777dd7cddfSDavid du Colombier 		/* add to routing table */
8787dd7cddfSDavid du Colombier 		if(isv4(a))
879107aedb4SDavid du Colombier 			v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off,
880107aedb4SDavid du Colombier 				a+IPv4off, type);
8817dd7cddfSDavid du Colombier 		else
8827dd7cddfSDavid du Colombier 			v6addroute(f, tifc, a, IPallbits, a, type);
8837dd7cddfSDavid du Colombier 
8847dd7cddfSDavid du Colombier 		if((type & Rmulti) && ifc->m->addmulti != nil)
8857dd7cddfSDavid du Colombier 			(*ifc->m->addmulti)(ifc, a, lifc->local);
886107aedb4SDavid du Colombier 	} else
8877dd7cddfSDavid du Colombier 		lp->ref++;
8887dd7cddfSDavid du Colombier 
8897dd7cddfSDavid du Colombier 	qunlock(f->self);
8907dd7cddfSDavid du Colombier }
8917dd7cddfSDavid du Colombier 
8927dd7cddfSDavid du Colombier /*
8937dd7cddfSDavid du Colombier  *  These structures are unlinked from their chains while
8947dd7cddfSDavid du Colombier  *  other threads may be using them.  To avoid excessive locking,
8957dd7cddfSDavid du Colombier  *  just put them aside for a while before freeing them.
8967dd7cddfSDavid du Colombier  *	called with f->self locked
8977dd7cddfSDavid du Colombier  */
8987dd7cddfSDavid du Colombier static Iplink *freeiplink;
8997dd7cddfSDavid du Colombier static Ipself *freeipself;
9007dd7cddfSDavid du Colombier 
9017dd7cddfSDavid du Colombier static void
iplinkfree(Iplink * p)9027dd7cddfSDavid du Colombier iplinkfree(Iplink *p)
9037dd7cddfSDavid du Colombier {
9047dd7cddfSDavid du Colombier 	Iplink **l, *np;
9053ff48bf5SDavid du Colombier 	ulong now = NOW;
9067dd7cddfSDavid du Colombier 
9077dd7cddfSDavid du Colombier 	l = &freeiplink;
9087dd7cddfSDavid du Colombier 	for(np = *l; np; np = *l){
9097dd7cddfSDavid du Colombier 		if(np->expire > now){
9107dd7cddfSDavid du Colombier 			*l = np->next;
9117dd7cddfSDavid du Colombier 			free(np);
9127dd7cddfSDavid du Colombier 			continue;
9137dd7cddfSDavid du Colombier 		}
9147dd7cddfSDavid du Colombier 		l = &np->next;
9157dd7cddfSDavid du Colombier 	}
9167dd7cddfSDavid du Colombier 	p->expire = now + 5000;	/* give other threads 5 secs to get out */
9177dd7cddfSDavid du Colombier 	p->next = nil;
9187dd7cddfSDavid du Colombier 	*l = p;
9197dd7cddfSDavid du Colombier }
920f2c197d9SDavid du Colombier 
9217dd7cddfSDavid du Colombier static void
ipselffree(Ipself * p)9227dd7cddfSDavid du Colombier ipselffree(Ipself *p)
9237dd7cddfSDavid du Colombier {
9247dd7cddfSDavid du Colombier 	Ipself **l, *np;
9253ff48bf5SDavid du Colombier 	ulong now = NOW;
9267dd7cddfSDavid du Colombier 
9277dd7cddfSDavid du Colombier 	l = &freeipself;
9287dd7cddfSDavid du Colombier 	for(np = *l; np; np = *l){
9297dd7cddfSDavid du Colombier 		if(np->expire > now){
9307dd7cddfSDavid du Colombier 			*l = np->next;
9317dd7cddfSDavid du Colombier 			free(np);
9327dd7cddfSDavid du Colombier 			continue;
9337dd7cddfSDavid du Colombier 		}
9347dd7cddfSDavid du Colombier 		l = &np->next;
9357dd7cddfSDavid du Colombier 	}
9367dd7cddfSDavid du Colombier 	p->expire = now + 5000;	/* give other threads 5 secs to get out */
9377dd7cddfSDavid du Colombier 	p->next = nil;
9387dd7cddfSDavid du Colombier 	*l = p;
9397dd7cddfSDavid du Colombier }
9407dd7cddfSDavid du Colombier 
9417dd7cddfSDavid du Colombier /*
9427dd7cddfSDavid du Colombier  *  Decrement reference for this address on this link.
9437dd7cddfSDavid du Colombier  *  Unlink from selftab if this is the last ref.
9447dd7cddfSDavid du Colombier  *	called with c->car locked
9457dd7cddfSDavid du Colombier  */
9467dd7cddfSDavid du Colombier static void
remselfcache(Fs * f,Ipifc * ifc,Iplifc * lifc,uchar * a)9477dd7cddfSDavid du Colombier remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
9487dd7cddfSDavid du Colombier {
9497dd7cddfSDavid du Colombier 	Ipself *p, **l;
9507dd7cddfSDavid du Colombier 	Iplink *link, **l_self, **l_lifc;
9517dd7cddfSDavid du Colombier 
9527dd7cddfSDavid du Colombier 	qlock(f->self);
9537dd7cddfSDavid du Colombier 
9547dd7cddfSDavid du Colombier 	/* find the unique selftab entry */
9557dd7cddfSDavid du Colombier 	l = &f->self->hash[hashipa(a)];
9567dd7cddfSDavid du Colombier 	for(p = *l; p; p = *l){
9577dd7cddfSDavid du Colombier 		if(ipcmp(p->a, a) == 0)
9587dd7cddfSDavid du Colombier 			break;
9597dd7cddfSDavid du Colombier 		l = &p->next;
9607dd7cddfSDavid du Colombier 	}
9617dd7cddfSDavid du Colombier 
9627dd7cddfSDavid du Colombier 	if(p == nil)
9637dd7cddfSDavid du Colombier 		goto out;
9647dd7cddfSDavid du Colombier 
9657dd7cddfSDavid du Colombier 	/*
9667dd7cddfSDavid du Colombier 	 *  walk down links from an ifc looking for one
9677dd7cddfSDavid du Colombier 	 *  that matches the selftab entry
9687dd7cddfSDavid du Colombier 	 */
9697dd7cddfSDavid du Colombier 	l_lifc = &lifc->link;
9707dd7cddfSDavid du Colombier 	for(link = *l_lifc; link; link = *l_lifc){
9717dd7cddfSDavid du Colombier 		if(link->self == p)
9727dd7cddfSDavid du Colombier 			break;
9737dd7cddfSDavid du Colombier 		l_lifc = &link->lifclink;
9747dd7cddfSDavid du Colombier 	}
9757dd7cddfSDavid du Colombier 
9767dd7cddfSDavid du Colombier 	if(link == nil)
9777dd7cddfSDavid du Colombier 		goto out;
9787dd7cddfSDavid du Colombier 
9797dd7cddfSDavid du Colombier 	/*
9807dd7cddfSDavid du Colombier 	 *  walk down the links from the selftab looking for
9817dd7cddfSDavid du Colombier 	 *  the one we just found
9827dd7cddfSDavid du Colombier 	 */
9837dd7cddfSDavid du Colombier 	l_self = &p->link;
9847dd7cddfSDavid du Colombier 	for(link = *l_self; link; link = *l_self){
985107aedb4SDavid du Colombier 		if(link == *l_lifc)
9867dd7cddfSDavid du Colombier 			break;
9877dd7cddfSDavid du Colombier 		l_self = &link->selflink;
9887dd7cddfSDavid du Colombier 	}
9897dd7cddfSDavid du Colombier 
9907dd7cddfSDavid du Colombier 	if(link == nil)
9917dd7cddfSDavid du Colombier 		panic("remselfcache");
9927dd7cddfSDavid du Colombier 
9937dd7cddfSDavid du Colombier 	if(--(link->ref) != 0)
9947dd7cddfSDavid du Colombier 		goto out;
9957dd7cddfSDavid du Colombier 
9967dd7cddfSDavid du Colombier 	if((p->type & Rmulti) && ifc->m->remmulti != nil)
9977dd7cddfSDavid du Colombier 		(*ifc->m->remmulti)(ifc, a, lifc->local);
9987dd7cddfSDavid du Colombier 
9997dd7cddfSDavid du Colombier 	/* ref == 0, remove from both chains and free the link */
10007dd7cddfSDavid du Colombier 	*l_lifc = link->lifclink;
10017dd7cddfSDavid du Colombier 	*l_self = link->selflink;
10027dd7cddfSDavid du Colombier 	iplinkfree(link);
10037dd7cddfSDavid du Colombier 
10047dd7cddfSDavid du Colombier 	if(p->link != nil)
10057dd7cddfSDavid du Colombier 		goto out;
10067dd7cddfSDavid du Colombier 
10077dd7cddfSDavid du Colombier 	/* remove from routing table */
10087dd7cddfSDavid du Colombier 	if(isv4(a))
10097dd7cddfSDavid du Colombier 		v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
10107dd7cddfSDavid du Colombier 	else
10117dd7cddfSDavid du Colombier 		v6delroute(f, a, IPallbits, 1);
10127dd7cddfSDavid du Colombier 
10137dd7cddfSDavid du Colombier 	/* no more links, remove from hash and free */
10147dd7cddfSDavid du Colombier 	*l = p->next;
10157dd7cddfSDavid du Colombier 	ipselffree(p);
10167dd7cddfSDavid du Colombier 
10177dd7cddfSDavid du Colombier 	/* if IPnoaddr, forget */
10187dd7cddfSDavid du Colombier 	if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
10197dd7cddfSDavid du Colombier 		f->self->acceptall = 0;
10207dd7cddfSDavid du Colombier 
10217dd7cddfSDavid du Colombier out:
10227dd7cddfSDavid du Colombier 	qunlock(f->self);
10237dd7cddfSDavid du Colombier }
10247dd7cddfSDavid du Colombier 
102567493d07SDavid du Colombier static char *stformat = "%-44.44I %2.2d %4.4s\n";
10263ff48bf5SDavid du Colombier enum
10273ff48bf5SDavid du Colombier {
10283ff48bf5SDavid du Colombier 	Nstformat= 41,
10293ff48bf5SDavid du Colombier };
10307dd7cddfSDavid du Colombier 
10317dd7cddfSDavid du Colombier long
ipselftabread(Fs * f,char * cp,ulong offset,int n)10327dd7cddfSDavid du Colombier ipselftabread(Fs *f, char *cp, ulong offset, int n)
10337dd7cddfSDavid du Colombier {
10349a747e4fSDavid du Colombier 	int i, m, nifc, off;
10357dd7cddfSDavid du Colombier 	Ipself *p;
10367dd7cddfSDavid du Colombier 	Iplink *link;
10377dd7cddfSDavid du Colombier 	char state[8];
10387dd7cddfSDavid du Colombier 
10397dd7cddfSDavid du Colombier 	m = 0;
10409a747e4fSDavid du Colombier 	off = offset;
10417dd7cddfSDavid du Colombier 	qlock(f->self);
1042f2c197d9SDavid du Colombier 	for(i = 0; i < NHASH && m < n; i++){
10437dd7cddfSDavid du Colombier 		for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
10447dd7cddfSDavid du Colombier 			nifc = 0;
10457dd7cddfSDavid du Colombier 			for(link = p->link; link; link = link->selflink)
10467dd7cddfSDavid du Colombier 				nifc++;
10477dd7cddfSDavid du Colombier 			routetype(p->type, state);
10487dd7cddfSDavid du Colombier 			m += snprint(cp + m, n - m, stformat, p->a, nifc, state);
10499a747e4fSDavid du Colombier 			if(off > 0){
10509a747e4fSDavid du Colombier 				off -= m;
10519a747e4fSDavid du Colombier 				m = 0;
10527dd7cddfSDavid du Colombier 			}
10537dd7cddfSDavid du Colombier 		}
1054f2c197d9SDavid du Colombier 	}
10557dd7cddfSDavid du Colombier 	qunlock(f->self);
10567dd7cddfSDavid du Colombier 	return m;
10577dd7cddfSDavid du Colombier }
10587dd7cddfSDavid du Colombier 
10593ff48bf5SDavid du Colombier int
iptentative(Fs * f,uchar * addr)10603ff48bf5SDavid du Colombier iptentative(Fs *f, uchar *addr)
10613ff48bf5SDavid du Colombier {
10623ff48bf5SDavid du Colombier  	Ipself *p;
10633ff48bf5SDavid du Colombier 
10643ff48bf5SDavid du Colombier 	p = f->self->hash[hashipa(addr)];
1065f2c197d9SDavid du Colombier 	for(; p; p = p->next){
1066107aedb4SDavid du Colombier 		if(ipcmp(addr, p->a) == 0)
10673ff48bf5SDavid du Colombier 			return p->link->lifc->tentative;
1068f2c197d9SDavid du Colombier 	}
10693ff48bf5SDavid du Colombier 	return 0;
10703ff48bf5SDavid du Colombier }
10717dd7cddfSDavid du Colombier 
10727dd7cddfSDavid du Colombier /*
10737dd7cddfSDavid du Colombier  *  returns
10747dd7cddfSDavid du Colombier  *	0		- no match
10757dd7cddfSDavid du Colombier  *	Runi
10767dd7cddfSDavid du Colombier  *	Rbcast
10777dd7cddfSDavid du Colombier  *	Rmcast
10787dd7cddfSDavid du Colombier  */
10797dd7cddfSDavid du Colombier int
ipforme(Fs * f,uchar * addr)10807dd7cddfSDavid du Colombier ipforme(Fs *f, uchar *addr)
10817dd7cddfSDavid du Colombier {
10827dd7cddfSDavid du Colombier 	Ipself *p;
10837dd7cddfSDavid du Colombier 
10847dd7cddfSDavid du Colombier 	p = f->self->hash[hashipa(addr)];
1085f2c197d9SDavid du Colombier 	for(; p; p = p->next){
10867dd7cddfSDavid du Colombier 		if(ipcmp(addr, p->a) == 0)
10877dd7cddfSDavid du Colombier 			return p->type;
1088f2c197d9SDavid du Colombier 	}
10897dd7cddfSDavid du Colombier 
10907dd7cddfSDavid du Colombier 	/* hack to say accept anything */
10917dd7cddfSDavid du Colombier 	if(f->self->acceptall)
10927dd7cddfSDavid du Colombier 		return Runi;
10937dd7cddfSDavid du Colombier 	return 0;
10947dd7cddfSDavid du Colombier }
10957dd7cddfSDavid du Colombier 
10967dd7cddfSDavid du Colombier /*
10977dd7cddfSDavid du Colombier  *  find the ifc on same net as the remote system.  If none,
10987dd7cddfSDavid du Colombier  *  return nil.
10997dd7cddfSDavid du Colombier  */
11007dd7cddfSDavid du Colombier Ipifc*
findipifc(Fs * f,uchar * remote,int type)11017dd7cddfSDavid du Colombier findipifc(Fs *f, uchar *remote, int type)
11027dd7cddfSDavid du Colombier {
11037dd7cddfSDavid du Colombier 	Ipifc *ifc, *x;
11047dd7cddfSDavid du Colombier 	Iplifc *lifc;
11057dd7cddfSDavid du Colombier 	Conv **cp, **e;
1106107aedb4SDavid du Colombier 	uchar gnet[IPaddrlen], xmask[IPaddrlen];
11077dd7cddfSDavid du Colombier 
1108107aedb4SDavid du Colombier 	x = nil;
1109107aedb4SDavid du Colombier 	memset(xmask, 0, IPaddrlen);
11107dd7cddfSDavid du Colombier 
11117dd7cddfSDavid du Colombier 	/* find most specific match */
11127dd7cddfSDavid du Colombier 	e = &f->ipifc->conv[f->ipifc->nc];
11137dd7cddfSDavid du Colombier 	for(cp = f->ipifc->conv; cp < e; cp++){
11147dd7cddfSDavid du Colombier 		if(*cp == 0)
11157dd7cddfSDavid du Colombier 			continue;
11167dd7cddfSDavid du Colombier 		ifc = (Ipifc*)(*cp)->ptcl;
11177dd7cddfSDavid du Colombier 		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
11187dd7cddfSDavid du Colombier 			maskip(remote, lifc->mask, gnet);
1119f2c197d9SDavid du Colombier 			if(ipcmp(gnet, lifc->net) == 0){
11207dd7cddfSDavid du Colombier 				if(x == nil || ipcmp(lifc->mask, xmask) > 0){
11217dd7cddfSDavid du Colombier 					x = ifc;
11227dd7cddfSDavid du Colombier 					ipmove(xmask, lifc->mask);
11237dd7cddfSDavid du Colombier 				}
11247dd7cddfSDavid du Colombier 			}
11257dd7cddfSDavid du Colombier 		}
1126f2c197d9SDavid du Colombier 	}
11277dd7cddfSDavid du Colombier 	if(x != nil)
11287dd7cddfSDavid du Colombier 		return x;
11297dd7cddfSDavid du Colombier 
11307dd7cddfSDavid du Colombier 	/* for now for broadcast and multicast, just use first interface */
1131f2c197d9SDavid du Colombier 	if(type & (Rbcast|Rmulti)){
11327dd7cddfSDavid du Colombier 		for(cp = f->ipifc->conv; cp < e; cp++){
11337dd7cddfSDavid du Colombier 			if(*cp == 0)
11347dd7cddfSDavid du Colombier 				continue;
11357dd7cddfSDavid du Colombier 			ifc = (Ipifc*)(*cp)->ptcl;
11367dd7cddfSDavid du Colombier 			if(ifc->lifc != nil)
11377dd7cddfSDavid du Colombier 				return ifc;
11387dd7cddfSDavid du Colombier 		}
1139f2c197d9SDavid du Colombier 	}
11407dd7cddfSDavid du Colombier 	return nil;
11417dd7cddfSDavid du Colombier }
11427dd7cddfSDavid du Colombier 
11433ff48bf5SDavid du Colombier enum {
1144107aedb4SDavid du Colombier 	unknownv6,		/* UGH */
1145f2c197d9SDavid du Colombier //	multicastv6,
11463ff48bf5SDavid du Colombier 	unspecifiedv6,
11473ff48bf5SDavid du Colombier 	linklocalv6,
11483ff48bf5SDavid du Colombier 	globalv6,
11493ff48bf5SDavid du Colombier };
11503ff48bf5SDavid du Colombier 
11513ff48bf5SDavid du Colombier int
v6addrtype(uchar * addr)11523ff48bf5SDavid du Colombier v6addrtype(uchar *addr)
11533ff48bf5SDavid du Colombier {
1154976d3a68SDavid du Colombier 	if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
1155976d3a68SDavid du Colombier 		return unknownv6;
1156976d3a68SDavid du Colombier 	else if(islinklocal(addr) ||
1157f2c197d9SDavid du Colombier 	    isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
11583ff48bf5SDavid du Colombier 		return linklocalv6;
1159d36a2583SDavid du Colombier 	else
1160d36a2583SDavid du Colombier 		return globalv6;
11613ff48bf5SDavid du Colombier }
11623ff48bf5SDavid du Colombier 
1163d36a2583SDavid du Colombier #define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
1164d36a2583SDavid du Colombier 			(lifc)->origint + (lifc)->preflt >= NOW/1000)
11653ff48bf5SDavid du Colombier 
11669acf0835SDavid du Colombier static void
findprimaryipv6(Fs * f,uchar * local)11679acf0835SDavid du Colombier findprimaryipv6(Fs *f, uchar *local)
11683ff48bf5SDavid du Colombier {
1169107aedb4SDavid du Colombier 	int atype, atypel;
11703ff48bf5SDavid du Colombier 	Conv **cp, **e;
11713ff48bf5SDavid du Colombier 	Ipifc *ifc;
11723ff48bf5SDavid du Colombier 	Iplifc *lifc;
11733ff48bf5SDavid du Colombier 
11743ff48bf5SDavid du Colombier 	ipmove(local, v6Unspecified);
11753ff48bf5SDavid du Colombier 	atype = unspecifiedv6;
11763ff48bf5SDavid du Colombier 
1177f2c197d9SDavid du Colombier 	/*
1178f2c197d9SDavid du Colombier 	 * find "best" (global > link local > unspecified)
1179f2c197d9SDavid du Colombier 	 * local address; address must be current.
1180f2c197d9SDavid du Colombier 	 */
11813ff48bf5SDavid du Colombier 	e = &f->ipifc->conv[f->ipifc->nc];
11823ff48bf5SDavid du Colombier 	for(cp = f->ipifc->conv; cp < e; cp++){
11833ff48bf5SDavid du Colombier 		if(*cp == 0)
11843ff48bf5SDavid du Colombier 			continue;
11853ff48bf5SDavid du Colombier 		ifc = (Ipifc*)(*cp)->ptcl;
11863ff48bf5SDavid du Colombier 		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
11873ff48bf5SDavid du Colombier 			atypel = v6addrtype(lifc->local);
1188107aedb4SDavid du Colombier 			if(atypel > atype && v6addrcurr(lifc)) {
11893ff48bf5SDavid du Colombier 				ipmove(local, lifc->local);
11903ff48bf5SDavid du Colombier 				atype = atypel;
11913ff48bf5SDavid du Colombier 				if(atype == globalv6)
11923ff48bf5SDavid du Colombier 					return;
11933ff48bf5SDavid du Colombier 			}
11943ff48bf5SDavid du Colombier 		}
11953ff48bf5SDavid du Colombier 	}
11963ff48bf5SDavid du Colombier }
11973ff48bf5SDavid du Colombier 
11987dd7cddfSDavid du Colombier /*
11997dd7cddfSDavid du Colombier  *  returns first ip address configured
12007dd7cddfSDavid du Colombier  */
12019acf0835SDavid du Colombier static void
findprimaryipv4(Fs * f,uchar * local)12029acf0835SDavid du Colombier findprimaryipv4(Fs *f, uchar *local)
12037dd7cddfSDavid du Colombier {
12047dd7cddfSDavid du Colombier 	Conv **cp, **e;
12057dd7cddfSDavid du Colombier 	Ipifc *ifc;
12067dd7cddfSDavid du Colombier 	Iplifc *lifc;
12077dd7cddfSDavid du Colombier 
12087dd7cddfSDavid du Colombier 	/* find first ifc local address */
12097dd7cddfSDavid du Colombier 	e = &f->ipifc->conv[f->ipifc->nc];
12107dd7cddfSDavid du Colombier 	for(cp = f->ipifc->conv; cp < e; cp++){
12117dd7cddfSDavid du Colombier 		if(*cp == 0)
12127dd7cddfSDavid du Colombier 			continue;
12137dd7cddfSDavid du Colombier 		ifc = (Ipifc*)(*cp)->ptcl;
12149acf0835SDavid du Colombier 		if((lifc = ifc->lifc) != nil){
12157dd7cddfSDavid du Colombier 			ipmove(local, lifc->local);
12167dd7cddfSDavid du Colombier 			return;
12177dd7cddfSDavid du Colombier 		}
12187dd7cddfSDavid du Colombier 	}
12197dd7cddfSDavid du Colombier }
12207dd7cddfSDavid du Colombier 
12217dd7cddfSDavid du Colombier /*
12227dd7cddfSDavid du Colombier  *  find the local address 'closest' to the remote system, copy it to
12237dd7cddfSDavid du Colombier  *  local and return the ifc for that address
12247dd7cddfSDavid du Colombier  */
12257dd7cddfSDavid du Colombier void
findlocalip(Fs * f,uchar * local,uchar * remote)12267dd7cddfSDavid du Colombier findlocalip(Fs *f, uchar *local, uchar *remote)
12277dd7cddfSDavid du Colombier {
1228107aedb4SDavid du Colombier 	int version, atype = unspecifiedv6, atypel = unknownv6;
1229d36a2583SDavid du Colombier 	int atyper, deprecated;
1230107aedb4SDavid du Colombier 	uchar gate[IPaddrlen], gnet[IPaddrlen];
12317dd7cddfSDavid du Colombier 	Ipifc *ifc;
12327dd7cddfSDavid du Colombier 	Iplifc *lifc;
12337dd7cddfSDavid du Colombier 	Route *r;
12347dd7cddfSDavid du Colombier 
12353ff48bf5SDavid du Colombier 	USED(atype);
12363ff48bf5SDavid du Colombier 	USED(atypel);
12377dd7cddfSDavid du Colombier 	qlock(f->ipifc);
1238a6a9e072SDavid du Colombier 	r = v6lookup(f, remote, nil);
12393ff48bf5SDavid du Colombier  	version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;
12407dd7cddfSDavid du Colombier 
12417dd7cddfSDavid du Colombier 	if(r != nil){
12427dd7cddfSDavid du Colombier 		ifc = r->ifc;
12437dd7cddfSDavid du Colombier 		if(r->type & Rv4)
12447dd7cddfSDavid du Colombier 			v4tov6(gate, r->v4.gate);
12453ff48bf5SDavid du Colombier 		else {
12467dd7cddfSDavid du Colombier 			ipmove(gate, r->v6.gate);
12473ff48bf5SDavid du Colombier 			ipmove(local, v6Unspecified);
12483ff48bf5SDavid du Colombier 		}
12497dd7cddfSDavid du Colombier 
12503ff48bf5SDavid du Colombier 		switch(version) {
12513ff48bf5SDavid du Colombier 		case V4:
1252d36a2583SDavid du Colombier 			/* find ifc address closest to the gateway to use */
12537dd7cddfSDavid du Colombier 			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
12547dd7cddfSDavid du Colombier 				maskip(gate, lifc->mask, gnet);
12557dd7cddfSDavid du Colombier 				if(ipcmp(gnet, lifc->net) == 0){
12567dd7cddfSDavid du Colombier 					ipmove(local, lifc->local);
12577dd7cddfSDavid du Colombier 					goto out;
12587dd7cddfSDavid du Colombier 				}
12597dd7cddfSDavid du Colombier 			}
12603ff48bf5SDavid du Colombier 			break;
12613ff48bf5SDavid du Colombier 		case V6:
1262d36a2583SDavid du Colombier 			/* find ifc address with scope matching the destination */
1263d36a2583SDavid du Colombier 			atyper = v6addrtype(remote);
1264d36a2583SDavid du Colombier 			deprecated = 0;
12653ff48bf5SDavid du Colombier 			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
12663ff48bf5SDavid du Colombier 				atypel = v6addrtype(lifc->local);
1267d36a2583SDavid du Colombier 				/* prefer appropriate scope */
1268d36a2583SDavid du Colombier 				if(atypel > atype && atype < atyper ||
1269d36a2583SDavid du Colombier 				   atypel < atype && atype > atyper){
1270d36a2583SDavid du Colombier 					ipmove(local, lifc->local);
1271d36a2583SDavid du Colombier 					deprecated = !v6addrcurr(lifc);
1272d36a2583SDavid du Colombier 					atype = atypel;
1273d36a2583SDavid du Colombier 				} else if(atypel == atype){
1274d36a2583SDavid du Colombier 					/* avoid deprecated addresses */
1275d36a2583SDavid du Colombier 					if(deprecated && v6addrcurr(lifc)){
12763ff48bf5SDavid du Colombier 						ipmove(local, lifc->local);
12773ff48bf5SDavid du Colombier 						atype = atypel;
1278d36a2583SDavid du Colombier 						deprecated = 0;
12793ff48bf5SDavid du Colombier 					}
12803ff48bf5SDavid du Colombier 				}
1281d36a2583SDavid du Colombier 				if(atype == atyper && !deprecated)
1282d36a2583SDavid du Colombier 					goto out;
1283d36a2583SDavid du Colombier 			}
1284d36a2583SDavid du Colombier 			if(atype >= atyper)
12853ff48bf5SDavid du Colombier 				goto out;
12863ff48bf5SDavid du Colombier 			break;
12873ff48bf5SDavid du Colombier 		default:
12883ff48bf5SDavid du Colombier 			panic("findlocalip: version %d", version);
12893ff48bf5SDavid du Colombier 		}
12907dd7cddfSDavid du Colombier 	}
12917dd7cddfSDavid du Colombier 
12923ff48bf5SDavid du Colombier 	switch(version){
12933ff48bf5SDavid du Colombier 	case V4:
12949acf0835SDavid du Colombier 		findprimaryipv4(f, local);
12953ff48bf5SDavid du Colombier 		break;
12963ff48bf5SDavid du Colombier 	case V6:
12979acf0835SDavid du Colombier 		findprimaryipv6(f, local);
12983ff48bf5SDavid du Colombier 		break;
12993ff48bf5SDavid du Colombier 	default:
13003ff48bf5SDavid du Colombier 		panic("findlocalip2: version %d", version);
13013ff48bf5SDavid du Colombier 	}
13027dd7cddfSDavid du Colombier 
13037dd7cddfSDavid du Colombier out:
13047dd7cddfSDavid du Colombier 	qunlock(f->ipifc);
13057dd7cddfSDavid du Colombier }
13067dd7cddfSDavid du Colombier 
13077dd7cddfSDavid du Colombier /*
13087dd7cddfSDavid du Colombier  *  return first v4 address associated with an interface
13097dd7cddfSDavid du Colombier  */
13107dd7cddfSDavid du Colombier int
ipv4local(Ipifc * ifc,uchar * addr)13117dd7cddfSDavid du Colombier ipv4local(Ipifc *ifc, uchar *addr)
13127dd7cddfSDavid du Colombier {
13137dd7cddfSDavid du Colombier 	Iplifc *lifc;
13147dd7cddfSDavid du Colombier 
1315f2c197d9SDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
13167dd7cddfSDavid du Colombier 		if(isv4(lifc->local)){
13177dd7cddfSDavid du Colombier 			memmove(addr, lifc->local+IPv4off, IPv4addrlen);
13187dd7cddfSDavid du Colombier 			return 1;
13197dd7cddfSDavid du Colombier 		}
1320f2c197d9SDavid du Colombier 	}
13217dd7cddfSDavid du Colombier 	return 0;
13227dd7cddfSDavid du Colombier }
13237dd7cddfSDavid du Colombier 
13247dd7cddfSDavid du Colombier /*
13257dd7cddfSDavid du Colombier  *  return first v6 address associated with an interface
13267dd7cddfSDavid du Colombier  */
13277dd7cddfSDavid du Colombier int
ipv6local(Ipifc * ifc,uchar * addr)13287dd7cddfSDavid du Colombier ipv6local(Ipifc *ifc, uchar *addr)
13297dd7cddfSDavid du Colombier {
13307dd7cddfSDavid du Colombier 	Iplifc *lifc;
13317dd7cddfSDavid du Colombier 
1332f2c197d9SDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
13333ff48bf5SDavid du Colombier 		if(!isv4(lifc->local) && !(lifc->tentative)){
13343ff48bf5SDavid du Colombier 			ipmove(addr, lifc->local);
13353ff48bf5SDavid du Colombier 			return 1;
13363ff48bf5SDavid du Colombier 		}
1337f2c197d9SDavid du Colombier 	}
13383ff48bf5SDavid du Colombier 	return 0;
13393ff48bf5SDavid du Colombier }
13403ff48bf5SDavid du Colombier 
13413ff48bf5SDavid du Colombier int
ipv6anylocal(Ipifc * ifc,uchar * addr)13423ff48bf5SDavid du Colombier ipv6anylocal(Ipifc *ifc, uchar *addr)
13433ff48bf5SDavid du Colombier {
13443ff48bf5SDavid du Colombier 	Iplifc *lifc;
13453ff48bf5SDavid du Colombier 
1346f2c197d9SDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
13477dd7cddfSDavid du Colombier 		if(!isv4(lifc->local)){
13487dd7cddfSDavid du Colombier 			ipmove(addr, lifc->local);
134908fd2d13SDavid du Colombier 			return SRC_UNI;
13507dd7cddfSDavid du Colombier 		}
1351f2c197d9SDavid du Colombier 	}
135208fd2d13SDavid du Colombier 	return SRC_UNSPEC;
13537dd7cddfSDavid du Colombier }
13547dd7cddfSDavid du Colombier 
13557dd7cddfSDavid du Colombier /*
13567dd7cddfSDavid du Colombier  *  see if this address is bound to the interface
13577dd7cddfSDavid du Colombier  */
13587dd7cddfSDavid du Colombier Iplifc*
iplocalonifc(Ipifc * ifc,uchar * ip)13597dd7cddfSDavid du Colombier iplocalonifc(Ipifc *ifc, uchar *ip)
13607dd7cddfSDavid du Colombier {
13617dd7cddfSDavid du Colombier 	Iplifc *lifc;
13627dd7cddfSDavid du Colombier 
13637dd7cddfSDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next)
13647dd7cddfSDavid du Colombier 		if(ipcmp(ip, lifc->local) == 0)
13657dd7cddfSDavid du Colombier 			return lifc;
13667dd7cddfSDavid du Colombier 	return nil;
13677dd7cddfSDavid du Colombier }
13687dd7cddfSDavid du Colombier 
13697dd7cddfSDavid du Colombier 
13707dd7cddfSDavid du Colombier /*
13717dd7cddfSDavid du Colombier  *  See if we're proxying for this address on this interface
13727dd7cddfSDavid du Colombier  */
13737dd7cddfSDavid du Colombier int
ipproxyifc(Fs * f,Ipifc * ifc,uchar * ip)13747dd7cddfSDavid du Colombier ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
13757dd7cddfSDavid du Colombier {
13767dd7cddfSDavid du Colombier 	Route *r;
13777dd7cddfSDavid du Colombier 	uchar net[IPaddrlen];
13787dd7cddfSDavid du Colombier 	Iplifc *lifc;
13797dd7cddfSDavid du Colombier 
13807dd7cddfSDavid du Colombier 	/* see if this is a direct connected pt to pt address */
1381a6a9e072SDavid du Colombier 	r = v6lookup(f, ip, nil);
1382107aedb4SDavid du Colombier 	if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
13837dd7cddfSDavid du Colombier 		return 0;
13847dd7cddfSDavid du Colombier 
13857dd7cddfSDavid du Colombier 	/* see if this is on the right interface */
13867dd7cddfSDavid du Colombier 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
13877dd7cddfSDavid du Colombier 		maskip(ip, lifc->mask, net);
13887dd7cddfSDavid du Colombier 		if(ipcmp(net, lifc->remote) == 0)
13897dd7cddfSDavid du Colombier 			return 1;
13907dd7cddfSDavid du Colombier 	}
13917dd7cddfSDavid du Colombier 	return 0;
13927dd7cddfSDavid du Colombier }
13937dd7cddfSDavid du Colombier 
13947dd7cddfSDavid du Colombier /*
13957dd7cddfSDavid du Colombier  *  return multicast version if any
13967dd7cddfSDavid du Colombier  */
13977dd7cddfSDavid du Colombier int
ipismulticast(uchar * ip)13987dd7cddfSDavid du Colombier ipismulticast(uchar *ip)
13997dd7cddfSDavid du Colombier {
14007dd7cddfSDavid du Colombier 	if(isv4(ip)){
14017dd7cddfSDavid du Colombier 		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
14027dd7cddfSDavid du Colombier 			return V4;
1403f2c197d9SDavid du Colombier 	}
1404f2c197d9SDavid du Colombier 	else if(ip[0] == 0xff)
14057dd7cddfSDavid du Colombier 		return V6;
14067dd7cddfSDavid du Colombier 	return 0;
14077dd7cddfSDavid du Colombier }
14087dd7cddfSDavid du Colombier int
ipisbm(uchar * ip)14097dd7cddfSDavid du Colombier ipisbm(uchar *ip)
14107dd7cddfSDavid du Colombier {
1411f2c197d9SDavid du Colombier 	if(isv4(ip)){
14127dd7cddfSDavid du Colombier 		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
14137dd7cddfSDavid du Colombier 			return V4;
1414107aedb4SDavid du Colombier 		else if(ipcmp(ip, IPv4bcast) == 0)
14157dd7cddfSDavid du Colombier 			return V4;
1416f2c197d9SDavid du Colombier 	}
1417f2c197d9SDavid du Colombier 	else if(ip[0] == 0xff)
14187dd7cddfSDavid du Colombier 		return V6;
14197dd7cddfSDavid du Colombier 	return 0;
14207dd7cddfSDavid du Colombier }
14217dd7cddfSDavid du Colombier 
14227dd7cddfSDavid du Colombier 
14237dd7cddfSDavid du Colombier /*
14247dd7cddfSDavid du Colombier  *  add a multicast address to an interface, called with c->car locked
14257dd7cddfSDavid du Colombier  */
14267dd7cddfSDavid du Colombier void
ipifcaddmulti(Conv * c,uchar * ma,uchar * ia)14277dd7cddfSDavid du Colombier ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
14287dd7cddfSDavid du Colombier {
14297dd7cddfSDavid du Colombier 	Ipifc *ifc;
14307dd7cddfSDavid du Colombier 	Iplifc *lifc;
14317dd7cddfSDavid du Colombier 	Conv **p;
14327dd7cddfSDavid du Colombier 	Ipmulti *multi, **l;
14337dd7cddfSDavid du Colombier 	Fs *f;
14347dd7cddfSDavid du Colombier 
14357dd7cddfSDavid du Colombier 	f = c->p->f;
14367dd7cddfSDavid du Colombier 
14377dd7cddfSDavid du Colombier 	for(l = &c->multi; *l; l = &(*l)->next)
1438107aedb4SDavid du Colombier 		if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
14397dd7cddfSDavid du Colombier 			return;		/* it's already there */
14407dd7cddfSDavid du Colombier 
14417dd7cddfSDavid du Colombier 	multi = *l = smalloc(sizeof(*multi));
14427dd7cddfSDavid du Colombier 	ipmove(multi->ma, ma);
14437dd7cddfSDavid du Colombier 	ipmove(multi->ia, ia);
14447dd7cddfSDavid du Colombier 	multi->next = nil;
14457dd7cddfSDavid du Colombier 
14467dd7cddfSDavid du Colombier 	for(p = f->ipifc->conv; *p; p++){
14477dd7cddfSDavid du Colombier 		if((*p)->inuse == 0)
14487dd7cddfSDavid du Colombier 			continue;
14497dd7cddfSDavid du Colombier 		ifc = (Ipifc*)(*p)->ptcl;
14507dd7cddfSDavid du Colombier 		if(waserror()){
14517dd7cddfSDavid du Colombier 			wunlock(ifc);
14527dd7cddfSDavid du Colombier 			nexterror();
14537dd7cddfSDavid du Colombier 		}
14547dd7cddfSDavid du Colombier 		wlock(ifc);
14557dd7cddfSDavid du Colombier 		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
14567dd7cddfSDavid du Colombier 			if(ipcmp(ia, lifc->local) == 0)
14577dd7cddfSDavid du Colombier 				addselfcache(f, ifc, lifc, ma, Rmulti);
14587dd7cddfSDavid du Colombier 		wunlock(ifc);
14597dd7cddfSDavid du Colombier 		poperror();
14607dd7cddfSDavid du Colombier 	}
14617dd7cddfSDavid du Colombier }
14627dd7cddfSDavid du Colombier 
14637dd7cddfSDavid du Colombier 
14647dd7cddfSDavid du Colombier /*
14657dd7cddfSDavid du Colombier  *  remove a multicast address from an interface, called with c->car locked
14667dd7cddfSDavid du Colombier  */
14677dd7cddfSDavid du Colombier void
ipifcremmulti(Conv * c,uchar * ma,uchar * ia)14687dd7cddfSDavid du Colombier ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
14697dd7cddfSDavid du Colombier {
14707dd7cddfSDavid du Colombier 	Ipmulti *multi, **l;
14717dd7cddfSDavid du Colombier 	Iplifc *lifc;
14727dd7cddfSDavid du Colombier 	Conv **p;
14737dd7cddfSDavid du Colombier 	Ipifc *ifc;
14747dd7cddfSDavid du Colombier 	Fs *f;
14757dd7cddfSDavid du Colombier 
14767dd7cddfSDavid du Colombier 	f = c->p->f;
14777dd7cddfSDavid du Colombier 
14787dd7cddfSDavid du Colombier 	for(l = &c->multi; *l; l = &(*l)->next)
1479107aedb4SDavid du Colombier 		if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
14807dd7cddfSDavid du Colombier 			break;
14817dd7cddfSDavid du Colombier 
14827dd7cddfSDavid du Colombier 	multi = *l;
14837dd7cddfSDavid du Colombier 	if(multi == nil)
14847dd7cddfSDavid du Colombier 		return; 	/* we don't have it open */
14857dd7cddfSDavid du Colombier 
14867dd7cddfSDavid du Colombier 	*l = multi->next;
14877dd7cddfSDavid du Colombier 
14887dd7cddfSDavid du Colombier 	for(p = f->ipifc->conv; *p; p++){
14897dd7cddfSDavid du Colombier 		if((*p)->inuse == 0)
14907dd7cddfSDavid du Colombier 			continue;
14917dd7cddfSDavid du Colombier 
14927dd7cddfSDavid du Colombier 		ifc = (Ipifc*)(*p)->ptcl;
14937dd7cddfSDavid du Colombier 		if(waserror()){
14947dd7cddfSDavid du Colombier 			wunlock(ifc);
14957dd7cddfSDavid du Colombier 			nexterror();
14967dd7cddfSDavid du Colombier 		}
14977dd7cddfSDavid du Colombier 		wlock(ifc);
14987dd7cddfSDavid du Colombier 		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
14997dd7cddfSDavid du Colombier 			if(ipcmp(ia, lifc->local) == 0)
15007dd7cddfSDavid du Colombier 				remselfcache(f, ifc, lifc, ma);
15017dd7cddfSDavid du Colombier 		wunlock(ifc);
15027dd7cddfSDavid du Colombier 		poperror();
15037dd7cddfSDavid du Colombier 	}
15047dd7cddfSDavid du Colombier 
15057dd7cddfSDavid du Colombier 	free(multi);
15067dd7cddfSDavid du Colombier }
15077dd7cddfSDavid du Colombier 
15087dd7cddfSDavid du Colombier /*
15097dd7cddfSDavid du Colombier  *  make lifc's join and leave multicast groups
15107dd7cddfSDavid du Colombier  */
15117dd7cddfSDavid du Colombier static char*
ipifcjoinmulti(Ipifc * ifc,char ** argv,int argc)15127dd7cddfSDavid du Colombier ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
15137dd7cddfSDavid du Colombier {
15147dd7cddfSDavid du Colombier 	USED(ifc, argv, argc);
15157dd7cddfSDavid du Colombier 	return nil;
15167dd7cddfSDavid du Colombier }
15177dd7cddfSDavid du Colombier 
15187dd7cddfSDavid du Colombier static char*
ipifcleavemulti(Ipifc * ifc,char ** argv,int argc)15197dd7cddfSDavid du Colombier ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
15207dd7cddfSDavid du Colombier {
15217dd7cddfSDavid du Colombier 	USED(ifc, argv, argc);
15227dd7cddfSDavid du Colombier 	return nil;
15237dd7cddfSDavid du Colombier }
15247dd7cddfSDavid du Colombier 
15257dd7cddfSDavid du Colombier static void
ipifcregisterproxy(Fs * f,Ipifc * ifc,uchar * ip)15267dd7cddfSDavid du Colombier ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
15277dd7cddfSDavid du Colombier {
15287dd7cddfSDavid du Colombier 	Conv **cp, **e;
15297dd7cddfSDavid du Colombier 	Ipifc *nifc;
15307dd7cddfSDavid du Colombier 	Iplifc *lifc;
15317dd7cddfSDavid du Colombier 	Medium *m;
15327dd7cddfSDavid du Colombier 	uchar net[IPaddrlen];
15337dd7cddfSDavid du Colombier 
15347dd7cddfSDavid du Colombier 	/* register the address on any network that will proxy for us */
15357dd7cddfSDavid du Colombier 	e = &f->ipifc->conv[f->ipifc->nc];
15363ff48bf5SDavid du Colombier 
1537f2c197d9SDavid du Colombier 	if(!isv4(ip)) {				/* V6 */
15383ff48bf5SDavid du Colombier 		for(cp = f->ipifc->conv; cp < e; cp++){
1539107aedb4SDavid du Colombier 			if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
15403ff48bf5SDavid du Colombier 				continue;
15413ff48bf5SDavid du Colombier 			rlock(nifc);
15423ff48bf5SDavid du Colombier 			m = nifc->m;
15433ff48bf5SDavid du Colombier 			if(m == nil || m->addmulti == nil) {
15443ff48bf5SDavid du Colombier 				runlock(nifc);
15453ff48bf5SDavid du Colombier 				continue;
15463ff48bf5SDavid du Colombier 			}
15473ff48bf5SDavid du Colombier 			for(lifc = nifc->lifc; lifc; lifc = lifc->next){
15483ff48bf5SDavid du Colombier 				maskip(ip, lifc->mask, net);
1549107aedb4SDavid du Colombier 				if(ipcmp(net, lifc->remote) == 0) {
1550107aedb4SDavid du Colombier 					/* add solicited-node multicast addr */
15513ff48bf5SDavid du Colombier 					ipv62smcast(net, ip);
15523ff48bf5SDavid du Colombier 					addselfcache(f, nifc, lifc, net, Rmulti);
15533ff48bf5SDavid du Colombier 					arpenter(f, V6, ip, nifc->mac, 6, 0);
15543ff48bf5SDavid du Colombier 					// (*m->addmulti)(nifc, net, ip);
15553ff48bf5SDavid du Colombier 					break;
15563ff48bf5SDavid du Colombier 				}
15573ff48bf5SDavid du Colombier 			}
15583ff48bf5SDavid du Colombier 			runlock(nifc);
15593ff48bf5SDavid du Colombier 		}
1560f2c197d9SDavid du Colombier 	}
1561f2c197d9SDavid du Colombier 	else {					/* V4 */
15627dd7cddfSDavid du Colombier 		for(cp = f->ipifc->conv; cp < e; cp++){
1563107aedb4SDavid du Colombier 			if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
15647dd7cddfSDavid du Colombier 				continue;
15657dd7cddfSDavid du Colombier 			rlock(nifc);
15667dd7cddfSDavid du Colombier 			m = nifc->m;
15677dd7cddfSDavid du Colombier 			if(m == nil || m->areg == nil){
15687dd7cddfSDavid du Colombier 				runlock(nifc);
15697dd7cddfSDavid du Colombier 				continue;
15707dd7cddfSDavid du Colombier 			}
15717dd7cddfSDavid du Colombier 			for(lifc = nifc->lifc; lifc; lifc = lifc->next){
15727dd7cddfSDavid du Colombier 				maskip(ip, lifc->mask, net);
15737dd7cddfSDavid du Colombier 				if(ipcmp(net, lifc->remote) == 0){
15747dd7cddfSDavid du Colombier 					(*m->areg)(nifc, ip);
15757dd7cddfSDavid du Colombier 					break;
15767dd7cddfSDavid du Colombier 				}
15777dd7cddfSDavid du Colombier 			}
15787dd7cddfSDavid du Colombier 			runlock(nifc);
15797dd7cddfSDavid du Colombier 		}
15807dd7cddfSDavid du Colombier 	}
1581f2c197d9SDavid du Colombier }
15823ff48bf5SDavid du Colombier 
15833ff48bf5SDavid du Colombier 
1584107aedb4SDavid du Colombier /* added for new v6 mesg types */
15853ff48bf5SDavid du Colombier static void
adddefroute6(Fs * f,uchar * gate,int force)15863ff48bf5SDavid du Colombier adddefroute6(Fs *f, uchar *gate, int force)
15873ff48bf5SDavid du Colombier {
15883ff48bf5SDavid du Colombier 	Route *r;
15893ff48bf5SDavid du Colombier 
1590a6a9e072SDavid du Colombier 	r = v6lookup(f, v6Unspecified, nil);
1591107aedb4SDavid du Colombier 	/*
1592107aedb4SDavid du Colombier 	 * route entries generated by all other means take precedence
1593107aedb4SDavid du Colombier 	 * over router announcements.
1594107aedb4SDavid du Colombier 	 */
1595107aedb4SDavid du Colombier 	if (r && !force && strcmp(r->tag, "ra") != 0)
1596107aedb4SDavid du Colombier 		return;
15973ff48bf5SDavid du Colombier 
15983ff48bf5SDavid du Colombier 	v6delroute(f, v6Unspecified, v6Unspecified, 1);
15993ff48bf5SDavid du Colombier 	v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
16003ff48bf5SDavid du Colombier }
16013ff48bf5SDavid du Colombier 
1602107aedb4SDavid du Colombier enum {
16033ff48bf5SDavid du Colombier 	Ngates = 3,
16043ff48bf5SDavid du Colombier };
16053ff48bf5SDavid du Colombier 
16063ff48bf5SDavid du Colombier char*
ipifcadd6(Ipifc * ifc,char ** argv,int argc)16073179bee6SDavid du Colombier ipifcadd6(Ipifc *ifc, char**argv, int argc)
16083ff48bf5SDavid du Colombier {
16093ff48bf5SDavid du Colombier 	int plen = 64;
1610107aedb4SDavid du Colombier 	long origint = NOW / 1000, preflt = ~0L, validlt = ~0L;
1611*c1dd2601SDavid du Colombier 	char addr[Maxv6repr], preflen[6];
16123ff48bf5SDavid du Colombier 	char *params[3];
1613107aedb4SDavid du Colombier 	uchar autoflag = 1, onlink = 1;
1614107aedb4SDavid du Colombier 	uchar prefix[IPaddrlen];
1615107aedb4SDavid du Colombier 	Iplifc *lifc;
16163ff48bf5SDavid du Colombier 
16173ff48bf5SDavid du Colombier 	switch(argc) {
16183ff48bf5SDavid du Colombier 	case 7:
16193ff48bf5SDavid du Colombier 		preflt = atoi(argv[6]);
16203ff48bf5SDavid du Colombier 		/* fall through */
16213ff48bf5SDavid du Colombier 	case 6:
16223ff48bf5SDavid du Colombier 		validlt = atoi(argv[5]);
16233ff48bf5SDavid du Colombier 		/* fall through */
16243ff48bf5SDavid du Colombier 	case 5:
16253ff48bf5SDavid du Colombier 		autoflag = atoi(argv[4]);
16263ff48bf5SDavid du Colombier 		/* fall through */
16273ff48bf5SDavid du Colombier 	case 4:
16283ff48bf5SDavid du Colombier 		onlink = atoi(argv[3]);
16293ff48bf5SDavid du Colombier 		/* fall through */
16303ff48bf5SDavid du Colombier 	case 3:
16313ff48bf5SDavid du Colombier 		plen = atoi(argv[2]);
1632107aedb4SDavid du Colombier 		/* fall through */
16333ff48bf5SDavid du Colombier 	case 2:
16343ff48bf5SDavid du Colombier 		break;
16353ff48bf5SDavid du Colombier 	default:
16363ff48bf5SDavid du Colombier 		return Ebadarg;
16373ff48bf5SDavid du Colombier 	}
16383ff48bf5SDavid du Colombier 
1639*c1dd2601SDavid du Colombier 	if (parseip(prefix, argv[1]) != 6)
1640*c1dd2601SDavid du Colombier 		return "bad ipv6 address";
1641*c1dd2601SDavid du Colombier 	if (validlt < preflt)
1642*c1dd2601SDavid du Colombier 		return "valid ipv6 lifetime less than preferred lifetime";
1643*c1dd2601SDavid du Colombier 	if (plen < 0)
1644*c1dd2601SDavid du Colombier 		return "negative ipv6 prefix length";
1645*c1dd2601SDavid du Colombier 	/* i think that this length limit is bogus - geoff */
1646*c1dd2601SDavid du Colombier //	if (plen > 64)
1647*c1dd2601SDavid du Colombier //		return "ipv6 prefix length greater than 64;
1648*c1dd2601SDavid du Colombier 	if (islinklocal(prefix))
1649*c1dd2601SDavid du Colombier 		return "ipv6 prefix is link-local";
16503ff48bf5SDavid du Colombier 
16513ff48bf5SDavid du Colombier 	lifc = smalloc(sizeof(Iplifc));
16523ff48bf5SDavid du Colombier 	lifc->onlink = (onlink != 0);
16533ff48bf5SDavid du Colombier 	lifc->autoflag = (autoflag != 0);
16543ff48bf5SDavid du Colombier 	lifc->validlt = validlt;
16553ff48bf5SDavid du Colombier 	lifc->preflt = preflt;
16563ff48bf5SDavid du Colombier 	lifc->origint = origint;
16573ff48bf5SDavid du Colombier 
16583179bee6SDavid du Colombier 	/* issue "add" ctl msg for v6 link-local addr and prefix len */
16593179bee6SDavid du Colombier 	if(!ifc->m->pref2addr)
1660*c1dd2601SDavid du Colombier 		return "no pref2addr on interface";
16613179bee6SDavid du Colombier 	ifc->m->pref2addr(prefix, ifc->mac);	/* mac → v6 link-local addr */
16624e3613abSDavid du Colombier 	snprint(addr, sizeof addr, "%I", prefix);
16634e3613abSDavid du Colombier 	snprint(preflen, sizeof preflen, "/%d", plen);
16643ff48bf5SDavid du Colombier 	params[0] = "add";
16653ff48bf5SDavid du Colombier 	params[1] = addr;
166667493d07SDavid du Colombier 	params[2] = preflen;
16673ff48bf5SDavid du Colombier 
16683ff48bf5SDavid du Colombier 	return ipifcadd(ifc, params, 3, 0, lifc);
16693ff48bf5SDavid du Colombier }
1670