Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/ip/ipifc.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname ip/ipifc.c 1998/0306
## diff -e /dev/null /n/emeliedump/1998/0306/sys/src/brazil/ip/ipifc.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"

#include "ip.h"

#define DPRINT if(0)print

enum {
	Maxmedia	= 16,
	Nself		= Maxmedia*5,
	NHASH		= (1<<6),
	NCACHE		= 256,
	QMAX		= 64*1024-1,
};

	Proto	ipifc;
extern	Fs	fs;

Medium *media[] =
{
	&ethermedium,
	&nullmedium,
	0
};

/*
 *  cache of local addresses (addresses we answer to)
 */
typedef struct Ipself Ipself;
struct Ipself
{
	uchar	a[IPaddrlen];
	Ipself	*hnext;		/* next address in the hash table */
	Iplink	*link;		/* binding twixt Ipself and Ipifc */
	ulong	expire;
	uchar	type;		/* type of address */
	int	ref;
	Ipself	*next;		/* free list */
};

typedef struct Ipselftab Ipselftab;
struct Ipselftab
{
	QLock;
	int	inited;
	int	acceptall;	/* true if an interface has the null address */
	Ipself	*hash[NHASH];	/* hash chains */
};
Ipselftab	selftab;

/*
 *  Multicast addresses are chained onto a Chan so that
 *  we can remove them when the Chan is closed.
 */
typedef struct Ipmcast Ipmcast;
struct Ipmcast
{
	Ipmcast	*next;
	uchar	ma[IPaddrlen];	/* multicast address */
	uchar	ia[IPaddrlen];	/* interface address */
};

/* quick hash for ip addresses */
#define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )

static char tifc[] = "ifc ";

static void	addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
static void	remselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a);
static char*	ipifcjoinmulti(Ipifc *ifc, char **argv, int argc);
static char*	ipifcleavemulti(Ipifc *ifc, char **argv, int argc);

/*
 *  find the medium with this name
 */
Medium*
ipfindmedium(char *name)
{
	Medium **mp;

	for(mp = media; *mp != nil; mp++)
		if(strcmp((*mp)->name, name) == 0)
			break;
	return *mp;
}

/*
 *  attach a device (or pkt driver) to the interface.
 *  called with c->car locked
 */
static char*
ipifcbind(Conv *c, char **argv, int argc)
{
	Ipifc *ifc;
	Medium *m;

	if(argc < 2)
		return Ebadarg;

	ifc = (Ipifc*)c->ptcl;

	/* bind the device to the interface */
	m = ipfindmedium(argv[1]);
	if(m == nil)
		return "unknown interface type";

	wlock(ifc);
	if(ifc->m != nil){
		wunlock(ifc);
		return "interface already bound";	
	}
	if(waserror()){
		wunlock(ifc);
		nexterror();
	}

	(*m->bind)(ifc, argc, argv);
	if(argc > 2)
		strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
	else
		sprint(ifc->dev, "%s%d", m->name, c->x);
	ifc->dev[sizeof(ifc->dev)-1] = 0;
	ifc->m = m;
	ifc->minmtu = ifc->m->minmtu;
	ifc->maxmtu = ifc->m->maxmtu;
	ifc->ifcid++;

	wunlock(ifc);
	poperror();

	return nil;
}

/*
 *  detach a device from an interface, close the interface
 */
static char*
ipifcunbind(Ipifc *ifc)
{
	char *av[4];
	char ip[32];
	char mask[32];

	if(waserror()){
		wunlock(ifc);
		nexterror();
	}
	wlock(ifc);

	if(ipifcgrab(ifc) == 0);
		goto out;

	/* hangup queues to stop queuing of packets */
	qhangup(ifc->conv->rq, "unbind");
	qhangup(ifc->conv->wq, "unbind");

	/* dissociate routes */
	ifc->ifcid++;

	/* disassociate logical interfaces */
	av[0] = "remove";
	av[1] = ip;
	av[2] = mask;
	av[3] = 0;
	while(ifc->lifc){
		sprint(ip, "%I", ifc->lifc->local);
		sprint(mask, "%M", ifc->lifc->mask);
		ipifcrem(ifc, av, 3, 0);
	}

	/* disassociate device */
	(*ifc->m->unbind)(ifc);
	memset(ifc->dev, 0, sizeof(ifc->dev));
	ifc->arg = nil;
	ifc->m = &nullmedium;
	ifc->unbinding = 0;

out:
	wunlock(ifc);
	poperror();
	return nil;
}

static int
ipifcstate(Conv *c, char *state, int n)
{
	Ipifc *ifc;
	Iplifc *lifc;
	int m;

	ifc = (Ipifc*)c->ptcl;

	m = snprint(state, n, "%-12.12s %-5d", ifc->dev, ifc->maxmtu);

	rlock(ifc);
	for(lifc = ifc->lifc; lifc; lifc = lifc->next)
		m += snprint(state+m, n - m,
			" %-20.20I %-20.20M %-20.20I %-7d %-7d %-7d %-7d",
				lifc->local, lifc->mask, lifc->remote,
				ifc->in, ifc->out, ifc->inerr, ifc->outerr);
	m += snprint(state+m, n - m, "\n");
	runlock(ifc);
	return m;
}

static int
ipifclocal(Conv *c, char *state, int n)
{
	Ipifc *ifc;
	Iplifc *lifc;
	Iplink *link;
	int m;

	ifc = (Ipifc*)c->ptcl;

	m = 0;

	rlock(ifc);
	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
		m += snprint(state+m, n - m, "%-20.20I ->", lifc->local);
		for(link = lifc->link; link; link = link->lifclink)
			m += snprint(state+m, n - m, " %-20.20I", link->local->a);
		m += snprint(state+m, n - m, "\n");
	}
	runlock(ifc);
	return m;
}

static int
ipifcinuse(Conv *c)
{
	Ipifc *ifc;

	ifc = (Ipifc*)c->ptcl;
	return ifc->m != nil;
}

/*
 *  called when a process writes to an interface's 'data'
 */
static void
ipifckick(Conv *c, int)
{
	Block *bp;
	Ipifc *ifc;

	bp = qget(c->wq);
	if(bp == nil)
		return;

	ifc = (Ipifc*)c->ptcl;
	if(ifc->m == nil || ifc->m->pktin == nil)
		freeb(bp);
	else
		(*ifc->m->pktin)(ifc, bp);
}

/*
 *  we'll have to have a kick routine at
 *  some point to deal with these
 */
static void
ipifccreate(Conv *c)
{
	Ipifc *ifc;

	c->rq = qopen(QMAX, 0, 0, 0);
	c->wq = qopen(QMAX, 0, 0, 0);
	ifc = (Ipifc*)c->ptcl;
	ifc->conv = c;
}

/* 
 *  called after last close of ipifc data or ctl
 *  called with c locked, we must unlock
 */
static void
ipifcclose(Conv *c)
{
	/*
	 *  nothing to do since conversation stays open
	 *  till the device is unbound.
	 */
	unlock(c);
}

/*
 *  add an address to an interface.
 */
char*
ipifcadd(Ipifc *ifc, char **argv, int argc)
{
	uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
	uchar bcast[IPaddrlen], net[IPaddrlen];
	Iplifc *lifc, **l;
	int i, type, mtu;

	memset(ip, 0, IPaddrlen);
	memset(mask, 0, IPaddrlen);
	memset(rem, 0, IPaddrlen);
	switch(argc){
	case 5:
		mtu = strtoul(argv[4], 0, 0);
		if(mtu >= ifc->m->minmtu && mtu <= ifc->m->maxmtu)
			ifc->maxmtu = mtu;
		/* fall through */
	case 4:
		parseip(ip, argv[1]);
		parseipmask(mask, argv[2]);
		parseip(rem, argv[3]);
		maskip(rem, mask, net);
		break;
	case 3:
		parseip(ip, argv[1]);
		parseipmask(mask, argv[2]);
		maskip(ip, mask, rem);
		maskip(rem, mask, net);
		break;
	case 2:
		parseip(ip, argv[1]);
		memmove(mask, defmask(ip), IPaddrlen);
		maskip(ip, mask, rem);
		maskip(rem, mask, net);
		break;
	default:
		return Ebadarg;
		break;
	}

	if(waserror()){
		wunlock(ifc);
		panic("ipifcadd");
	}
	wlock(ifc);

	/* ignore if this is already a local address for this ifc */
	for(lifc = ifc->lifc; lifc; lifc = lifc->next)
		if(ipcmp(lifc->local, ip) == 0)
			goto out;

	/* add the address to the list of logical ifc's for this ifc */
	lifc = smalloc(sizeof(Iplifc));
	ipmove(lifc->local, ip);
	ipmove(lifc->mask, mask);
	ipmove(lifc->remote, rem);
	ipmove(lifc->net, net);
	lifc->next = nil;
	for(l = &ifc->lifc; *l; l = &(*l)->next)
		;
	*l = lifc;

	/* add a route for the local network */
	type = Rifc;
	if(ipcmp(mask, IPallbits) == 0)
		type |= Rptpt;
	if(isv4(ip))
		v4addroute(tifc, rem+IPv4off, mask+IPv4off, ip+IPv4off, type);
	else
		v6addroute(tifc, ip, mask, rem, type);

	addselfcache(ifc, lifc, ip, Runi);

	/* add subnet directed broadcast addresses to the self cache */
	for(i = 0; i < IPaddrlen; i++)
		bcast[i] = (ip[i] & mask[i]) | ~mask[i];
	addselfcache(ifc, lifc, bcast, Rbcast);

	/* add network directed broadcast addresses to the self cache */
	memmove(mask, defmask(ip), IPaddrlen);
	for(i = 0; i < IPaddrlen; i++)
		bcast[i] = (ip[i] & mask[i]) | ~mask[i];
	addselfcache(ifc, lifc, bcast, Rbcast);

	addselfcache(ifc, lifc, IPv4bcast, Rbcast);

out:
	wunlock(ifc);
	poperror();
	return nil;
}

/*
 *  remove an address from an interface.
 *  called with c->car locked
 */
char*
ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock)
{
	uchar ip[IPaddrlen];
	uchar mask[IPaddrlen];
	Iplifc *lifc, **l;

	if(argc < 3)
		return Ebadarg;

	parseip(ip, argv[1]);
	parseipmask(mask, argv[2]);

	if(dolock){
		if(waserror()){
			wunlock(ifc);
			nexterror();
		}
		wlock(ifc);
	}

	/* find address on this interface and remove from chain */
	lifc = nil;
	for(l = &ifc->lifc; *l; l = &(*l)->next)
		if(memcmp(ip, (*l)->local, IPaddrlen) == 0)
		if(memcmp(mask, (*l)->mask, IPaddrlen) == 0){
			lifc = *l;
			*l = lifc->next;
			break;
		}

	if(lifc == nil)
		return "address not on this interface";

	/* disassociate any addresses */
	while(lifc->link)
		remselfcache(ifc, lifc, lifc->link->local->a);

	/* remove the route for this logical interface */
	if(isv4(ip))
		v4delroute(lifc->remote+IPv4off, lifc->mask+IPv4off);
	else
		v6delroute(lifc->remote, lifc->mask);

	free(lifc);

out:
	if(dolock){
		wunlock(ifc);
		poperror();
	}
	return nil;
}

/*
 * distrbute routes to active interfaces like the
 * TRIP linecards
 */
void
ipifcaddroute(int vers, uchar *addr, uchar *mask, uchar *gate, int type)
{
	Medium *m;
	Conv **cp;
	Ipifc *ifc;

	for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
		if(*cp != nil) {
			ifc = (Ipifc*)(*cp)->ptcl;
			m = ifc->m;
			if(m->addroute != nil)
				m->addroute(ifc, vers, addr, mask, gate, type);
		}
	}
}

void
ipifcremroute(int vers, uchar *addr, uchar *mask)
{
	Medium *m;
	Conv **cp;
	Ipifc *ifc;

	for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
		if(*cp != nil) {
			ifc = (Ipifc*)(*cp)->ptcl;
			m = ifc->m;
			if(m->remroute != nil)
				m->remroute(ifc, vers, addr, mask);
		}
	}
}

/*
 *  associate an address with the interface.  This wipes out any previous
 *  addresses.  This is a macro that means, remove all the old interfaces
 *  and add a new one.
 */
static char*
ipifcconnect(Conv* c, char **argv, int argc)
{
	char *err;
	Ipifc *ifc;
	char *av[4];
	char ip[80], mask[80];

	ifc = (Ipifc*)c->ptcl;

	if(ifc->m == nil)
		 return "ipifc not yet bound to device";

	av[0] = "remove";
	av[1] = ip;
	av[2] = mask;
	av[3] = 0;
	if(waserror()){
		wunlock(ifc);
		nexterror();
	}
	wlock(ifc);
	while(ifc->lifc){
		sprint(ip, "%I", ifc->lifc->local);
		sprint(mask, "%I", ifc->lifc->mask);
		ipifcrem(ifc, av, 3, 0);
	}
	wunlock(ifc);
	poperror();

	err = ipifcadd(ifc, argv, argc);
	if(err)
		return err;

	Fsconnected(&fs, c, nil);

	return nil;
}

/*
 *  non-standard control messages.
 *  called with c->car locked.
 */
static char*
ipifcctl(Conv* c, char**argv, int argc)
{
	Ipifc *ifc;

	ifc = (Ipifc*)c->ptcl;
	if(strcmp(argv[0], "add") == 0)
		return ipifcadd(ifc, argv, argc);
	else if(strcmp(argv[0], "remove") == 0)
		return ipifcrem(ifc, argv, argc, 1);
	else if(strcmp(argv[0], "unbind") == 0)
		return ipifcunbind(ifc);
	else if(strcmp(argv[0], "joinmulti") == 0)
		return ipifcjoinmulti(ifc, argv, argc);
	else if(strcmp(argv[0], "leavemulti") == 0)
		return ipifcleavemulti(ifc, argv, argc);
	return "unsupported ctl";
}

void
ipifcinit(Fs *fs)
{
	ipifc.name = "ipifc";
	ipifc.kick = ipifckick;
	ipifc.connect = ipifcconnect;
	ipifc.announce = nil;
	ipifc.bind = ipifcbind;
	ipifc.state = ipifcstate;
	ipifc.create = ipifccreate;
	ipifc.close = ipifcclose;
	ipifc.rcv = nil;
	ipifc.ctl = ipifcctl;
	ipifc.advise = nil;
	ipifc.stats = ipstats;
	ipifc.inuse = ipifcinuse;
	ipifc.local = ipifclocal;
	ipifc.ipproto = -1;
	ipifc.nc = Maxmedia;
	ipifc.ptclsize = sizeof(Ipifc);

	Fsproto(fs, &ipifc);
}

/*
 *  add to self routing cache
 *	called with c->car locked
 */
static void
addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
{
	Ipself *p;
	Iplink *lp;
	int h;

	qlock(&selftab);

	/* see if the address already exists */
	h = hashipa(a);
	for(p = selftab.hash[h]; p; p = p->next)
		if(memcmp(a, p->a, IPaddrlen) == 0)
			break;

	/* allocate a local address and add to hash chain */
	if(p == nil){
		p = smalloc(sizeof(*p));
		ipmove(p->a, a);
		p->type = type;
		p->next = selftab.hash[h];
		selftab.hash[h] = p;

		/* if the null address, accept all packets */
		if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
			selftab.acceptall = 1;
	}

	/* look for a link for this lifc */
	for(lp = p->link; lp; lp = lp->locallink)
		if(lp->lifc == lifc)
			break;

	/* allocate a lifc-to-local link and link to both */
	if(lp == nil){
		lp = smalloc(sizeof(*lp));
		lp->ref = 1;
		lp->lifc = lifc;
		lp->local = p;
		lp->locallink = p->link;
		p->link = lp;
		lp->lifclink = lifc->link;
		lifc->link = lp;

		/* add to routing table */
		if(isv4(a))
			v4addroute(tifc, a+IPv4off, IPallbits+IPv4off, a+IPv4off, type);
		else
			v6addroute(tifc, a, IPallbits, a, type);

		if((type & Rmulti) && ifc->m->addmulti != nil)
			(*ifc->m->addmulti)(ifc, a, lifc->local);
	} else {
		lp->ref++;
	}

	qunlock(&selftab);
}

/*
 *  These structures are unlinked from their chains while
 *  other threads may be using them.  To avoid excessive locking,
 *  just put them aside for a while before freeing them.
 *	called with &selftab locked
 */
static Iplink *freeiplink;
static Ipself *freeipself;

static void
iplinkfree(Iplink *p)
{
	Iplink **l, *np;
	ulong now = msec;

	l = &freeiplink;
	for(np = *l; np; np = *l){
		if(np->expire > now){
			*l = np->next;
			free(np);
			continue;
		}
		l = &np->next;
	}
	p->expire = now + 5000;		/* give other threads 5 secs to get out */
	p->next = nil;
	*l = p;
}
static void
ipselffree(Ipself *p)
{
	Ipself **l, *np;
	ulong now = msec;

	l = &freeipself;
	for(np = *l; np; np = *l){
		if(np->expire > now){
			*l = np->next;
			free(np);
			continue;
		}
		l = &np->next;
	}
	p->expire = now + 5000;		/* give other threads 5 secs to get out */
	p->next = nil;
	*l = p;
}

/*
 *  Decrement reference for this address on this link.
 *  Unlink from selftab if this is the last ref.
 *	called with c->car locked
 */
static void
remselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a)
{
	Ipself *p, **l;
	Iplink *lp, *llp, **ill, **lll;

	qlock(&selftab);

	/* find the unique selftab entry */
	l = &selftab.hash[hashipa(a)];
	for(p = *l; p; p = *l){
		if(ipcmp(p->a, a) == 0)
			break;
		l = &p->next;
	}

	if(p == nil)
		goto out;

	/*
	 *  walk down links from an ifc looking for one
	 *  that matches the selftab entry
	 */
	ill = &lifc->link;
	for(lp = *ill; lp; lp = *ill){
		if(lp->local == p)
			break;
		ill = &lp->lifclink;
	}

	if(lp == nil)
		goto out;

	/*
	 *  walk down the links from the selftab looking for
	 *  the one we just found
	 */
	lll = &p->link;
	for(llp = *lll; llp; llp = *lll){
		if(llp == lp)
			break;
		lll = &lp->locallink;
	}

	if(llp == nil)
		panic("remselfcache");

	if(--(llp->ref) != 0)
		goto out;

	if((p->type & Rmulti) && ifc->m->remmulti != nil)
		(*ifc->m->remmulti)(ifc, a, lifc->local);

	/* ref == 0, remove from both chains and free the link */
	*ill = lp->lifclink;
	*lll = llp->locallink;
	iplinkfree(lp);

	/* remove from routing table */
	if(isv4(a))
		v4delroute(a+IPv4off, IPallbits+IPv4off);
	else
		v6delroute(a, IPallbits);
	
	if(p->link != nil)
		goto out;

	/* no more links, remove from hash and free */
	*l = p->next;
	ipselffree(p);

	/* if IPnoaddr, forget */
	if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
		selftab.acceptall = 0;

out:
	qunlock(&selftab);
}

static void
dumpselftab(void)
{
	int i, count;
	Ipself *p;

	qlock(&selftab);
	for(i = 0; i < NHASH; i++){
		p = selftab.hash[i];
		if(p == nil)
			continue;
		count = 0;
		for(; p != nil && count++ < 6; p = p->next)
			print("(%i %d %lux)", p->a, p->type, p);
		print("\n");
	}
	qunlock(&selftab);
}


/*
 *  returns
 *	0		- no match
 *	Runi
 *	Rbcast
 *	Rmcast
 */
int
ipforme(uchar *addr)
{
	Ipself *p;
	int count;

	p = selftab.hash[hashipa(addr)];
	count = 0;
	for(; p; p = p->next){
		if(count++ > 1000){	/* check for loops */
			dumpselftab();
			break;
		}
		if(ipcmp(addr, p->a) == 0)
			return p->type;
	}

	/* hack to say accept anything */
	if(selftab.acceptall)
		return Runi;

	return 0;
}

/*
 *  find the ifc on same net as the remote system.  If none,
 *  return nil.
 */
Ipifc*
findipifc(uchar *remote, int type)
{
	Ipifc *ifc;
	Iplifc *lifc;
	Conv **cp;
	uchar gnet[IPaddrlen];

	for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
		if(*cp == 0)
			continue;
		ifc = (Ipifc*)(*cp)->ptcl;
		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
			maskip(remote, lifc->mask, gnet);
			if(ipcmp(gnet, lifc->net) == 0){
				qunlock(&ipifc);
				return ifc;
			}
		}
	}

	/* for now for broadcast and mutlicast, just use first interface */
	if(type & (Rbcast|Rmulti)){
		for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
			if(*cp == 0)
				continue;
			ifc = (Ipifc*)(*cp)->ptcl;
			if(ifc->lifc != nil)
				return ifc;
		}
	}
		
	return nil;
}

/*
 *  find the local address 'closest' to the remote system, copy it to
 *  local and return the ifc for that address
 */
void
findlocalip(uchar *local, uchar *remote)
{
	Ipifc *ifc;
	Iplifc *lifc;
	Conv **cp;
	Route *r;
	uchar gate[IPaddrlen];
	uchar gnet[IPaddrlen];

	qlock(&ipifc);
	r = v6lookup(remote);
	
	if(r != nil){
		ifc = r->ifc;
		if(r->type & Rv4)
			v4tov6(gate, r->v4.gate);
		else
			ipmove(gate, r->v6.gate);

		if(r->type & Rifc){
			ipmove(local, gate);
			goto out;
		}

		/* find ifc address closest to the gateway to use */
		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
			maskip(gate, lifc->mask, gnet);
			if(ipcmp(gnet, lifc->net) == 0){
				ipmove(local, lifc->local);
				goto out;
			}
		}
	}
		
	/* no match, choose first ifc local address */
	for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
		if(*cp == 0)
			continue;
		ifc = (Ipifc*)(*cp)->ptcl;
		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
			ipmove(local, lifc->local);
			goto out;
		}
	}

out:
	qunlock(&ipifc);
}

/*
 *  return first v4 address associated with an interface
 */
int
ipv4local(Ipifc *ifc, uchar *addr)
{
	Iplifc *lifc;

	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
		if(isv4(lifc->local)){
			memmove(addr, lifc->local+IPv4off, IPv4addrlen);
			return 1;
		}
	}
	return 0;
}

/*
 *  return first v6 address associated with an interface
 */
int
ipv6local(Ipifc *ifc, uchar *addr)
{
	Iplifc *lifc;

	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
		if(!isv4(lifc->local)){
			ipmove(addr, lifc->local);
			return 1;
		}
	}
	return 0;
}

/*
 *  see if this address is bound to the interface
 */
Iplifc*
iplocalonifc(Ipifc *ifc, uchar *ip)
{
	Iplifc *lifc;

	for(lifc = ifc->lifc; lifc; lifc = lifc->next)
		if(ipcmp(ip, lifc->local) == 0)
			return lifc;
	return nil;
}


/*
 *  See if we're proxying for this address on this interface
 */
int
ipproxyifc(Ipifc *ifc, uchar *ip)
{
	Route *r;
	uchar net[IPaddrlen];
	Iplifc *lifc;

	/* see if this is a direct connected pt to pt address */
	r = v6lookup(ip);
	if(r == nil)
		return 0;
	if((r->type & Rifc) == 0)
		return 0;
	if((r->type & Rptpt) == 0)
		return 0;

	/* see if this is on the right interface */
	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
		maskip(ip, lifc->mask, net);
		if(ipcmp(net, lifc->remote) == 0)
			return 1;
	}

	return 0;
}

/*
 *  return multicast version if any
 */
int
ipismulticast(uchar *ip)
{
	if(isv4(ip)){
		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
			return V4;
	} else {
		if(ip[0] == 0xff)
			return V6;
	}
	return 0;
}

/*
 *  used to allow on the fly unbinds, return -1 if interface unusable
 */
int
ipifccheckin(Ipifc *ifc, Medium *med)
{
	int rv;

	lock(&ifc->idlock);
	if(ifc->unbinding || ifc->m != med)
		rv = -1;
	else
		rv = ++(ifc->ref);
	if(ifc->ref < 0) panic("ipifccheckin");
	unlock(&ifc->idlock);
	return rv;
}

void
ipifccheckout(Ipifc *ifc)
{
	lock(&ifc->idlock);
	if(--(ifc->ref) == 0)
	if(ifc->unbinding)
		wakeup(&ifc->wait);
	if(ifc->ref < 0) panic("ipifccheckin");
	unlock(&ifc->idlock);
}

static int
allout(void *x)
{
	Ipifc *ifc = x;

	return ifc->ref == 0;
}

int
ipifcgrab(Ipifc *ifc)
{
	lock(&ifc->idlock);
	if(ifc->unbinding){
		unlock(&ifc->idlock);
		return 0;
	}
	ifc->unbinding = 1;		/* after this ref can only go down */
	unlock(&ifc->idlock);

	sleep(&ifc->wait, allout, ifc);

	return 1;
}

/*
 *  add a multicast address to an interface, called with c->car locked
 */
void
ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
{
	Ipifc *ifc;
	Iplifc *lifc;
	Conv **p;
	Ipmulti *multi, **l;
	
	for(l = &c->multi; *l; l = &(*l)->next)
		if(ipcmp(ma, (*l)->ma) == 0)
		if(ipcmp(ia, (*l)->ia) == 0)
			return;		/* it's already there */

	multi = *l = smalloc(sizeof(*multi));
	ipmove(multi->ma, ma);
	ipmove(multi->ia, ia);
	multi->next = nil;

	for(p = ipifc.conv; *p; p++){
		if((*p)->inuse == 0)
			continue;
		ifc = (Ipifc*)(*p)->ptcl;
		if(waserror()){
			wunlock(ifc);
			nexterror();
		}
		wlock(ifc);
		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
			if(ipcmp(ia, lifc->local) == 0)
				addselfcache(ifc, lifc, ma, Rmulti);
		wunlock(ifc);
		poperror();
	}
}


/*
 *  remove a multicast address from an interface, called with c->car locked
 */
void
ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
{
	Ipmulti *multi, **l;
	Iplifc *lifc;
	Conv **p;
	Ipifc *ifc;
	
	for(l = &c->multi; *l; l = &(*l)->next)
		if(ipcmp(ma, (*l)->ma) == 0)
		if(ipcmp(ia, (*l)->ia) == 0)
			break;

	multi = *l;
	if(multi == nil)
		return; 	/* we don't have it open */

	*l = multi->next;

	for(p = ipifc.conv; *p; p++){
		if((*p)->inuse == 0)
			continue;

		ifc = (Ipifc*)(*p)->ptcl;
		if(waserror()){
			wunlock(ifc);
			nexterror();
		}
		wlock(ifc);
		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
			if(ipcmp(ia, lifc->local) == 0)
				remselfcache(ifc, lifc, ma);
		wunlock(ifc);
		poperror();
	}

	free(multi);
}

/*
 *  make lifc's join and leave multicast groups
 */
static char*
ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
{
	USED(ifc, argv, argc);
	return nil;
}

static char*
ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
{
	USED(ifc, argv, argc);
	return nil;
}

.
## diffname ip/ipifc.c 1998/0307
## diff -e /n/emeliedump/1998/0306/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0307/sys/src/brazil/ip/ipifc.c
1004,1056d
743,745c
	*l_lifc = link->lifclink;
	*l_self = link->selflink;
	iplinkfree(link);
.
736c
	if(--(link->ref) != 0)
.
733c
	if(link == nil)
.
730c
		l_self = &link->selflink;
.
726,728c
	l_self = &p->link;
	for(link = *l_self; link; link = *l_self){
		if(link == *(l_lifc))
.
719c
	if(link == nil)
.
716c
		l_lifc = &link->lifclink;
.
712,714c
	l_lifc = &lifc->link;
	for(link = *l_lifc; link; link = *l_lifc){
		if(link->self == p)
.
693c
	Iplink *link, **l_self, **l_lifc;
.
615,616c
		lp->self = p;
		lp->selflink = p->link;
.
606c
	for(lp = p->link; lp; lp = lp->selflink)
.
475a
			if(m == nil)
				continue;
.
458a
			if(m == nil)
				continue;
.
426c
		remselfcache(ifc, lifc, lifc->link->self->a);
.
284,287c
	Ipifc *ifc;
	Medium *m;

	ifc = (Ipifc*)c->ptcl;
	m = ifc->m;
	if(m != nil && m->unbindonclose)
		ipifcunbind(ifc);
.
274a
	ifc->unbinding = 0;
	ifc->m = nil;
.
226c
			m += snprint(state+m, n - m, " %-20.20I", link->self->a);
.
175,182c
	ifc->m = nil;
.
161,163d
156a
	/* disassociate device */
	(*ifc->m->unbind)(ifc);
	memset(ifc->dev, 0, sizeof(ifc->dev));
	ifc->arg = nil;

.
154,155c
	/* dissociate routes */
	ifc->ifcid++;
.
25a
	&pktmedium,
.
## diffname ip/ipifc.c 1998/0310
## diff -e /n/emeliedump/1998/0307/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0310/sys/src/brazil/ip/ipifc.c
789a
}

static char *stformat = "%-32.32I %2.2d %4.4s\n";
enum
{
	Nstformat= 41,
};

long
ipselftabread(char *cp, ulong offset, int n)
{
	int i, m, nifc;
	Ipself *p;
	Iplink *link;
	char state[8];

	m = 0;
	qlock(&selftab);
	for(i = 0; i < NHASH && m < n; i++){
		for(p = selftab.hash[i]; p != nil && m < n; p = p->next){
			if(offset == 0){
				nifc = 0;
				for(link = p->link; link; link = link->selflink)
					nifc++;
				routetype(p->type, state);
				m += snprint(cp + m, n - m, stformat, p->a, nifc, state);
			}
			offset -= Nstformat;
		}
	}
	qunlock(&selftab);
	return m;
.
786c
			print("(%I %d %lux)", p->a, p->type, p);
.
758,760d
751a
	if(p->link != nil)
		goto out;

.
## diffname ip/ipifc.c 1998/0313
## diff -e /n/emeliedump/1998/0310/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0313/sys/src/brazil/ip/ipifc.c
1116c
				remselfcache(f, ifc, lifc, ma);
.
1104c
	for(p = f->ipifc->conv; *p; p++){
.
1091a
	Fs *f;

	f = c->p->f;
.
1075c
				addselfcache(f, ifc, lifc, ma, Rmulti);
.
1064c
	for(p = f->ipifc->conv; *p; p++){
.
1052a
	Fs *f;

	f = c->p->f;
.
1009c
	r = v6lookup(f, ip);
.
1002c
ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
.
946c
	qunlock(f->ipifc);
.
935c
	e = &f->ipifc->conv[f->ipifc->nc];
	for(cp = f->ipifc->conv; cp < e; cp++){
.
909,910c
	qlock(f->ipifc);
	r = v6lookup(f, remote);
.
904c
	Conv **cp, **e;
.
900c
findlocalip(Fs *f, uchar *local, uchar *remote)
.
883c
		for(cp = f->ipifc->conv; cp < e; cp++){
.
877d
874,875c
			if(ipcmp(gnet, lifc->net) == 0)
.
868c
	e = &f->ipifc->conv[f->ipifc->nc];
	for(cp = f->ipifc->conv; cp < e; cp++){
.
865c
	Conv **cp, **e;
.
861c
findipifc(Fs *f, uchar *remote, int type)
.
850c
	if(f->self->acceptall)
.
841,844d
838,839c
	p = f->self->hash[hashipa(addr)];
.
836d
833c
ipforme(Fs *f, uchar *addr)
.
820c
	qunlock(f->self);
.
809c
		for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
.
807c
	qlock(f->self);
.
799c
ipselftabread(Fs *f, char *cp, ulong offset, int n)
.
773,791d
770c
	qunlock(f->self);
.
767c
		f->self->acceptall = 0;
.
759c
		v6delroute(f, a, IPallbits);
.
757c
		v4delroute(f, a+IPv4off, IPallbits+IPv4off);
.
703c
	l = &f->self->hash[hashipa(a)];
.
700c
	qlock(f->self);
.
695c
remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
.
645c
 *	called with f->self locked
.
638c
	qunlock(f->self);
.
630c
			v6addroute(f, tifc, a, IPallbits, a, type);
.
628c
			v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off, a+IPv4off, type);
.
607c
			f->self->acceptall = 1;
.
602,603c
		p->next = f->self->hash[h];
		f->self->hash[h] = p;
.
593c
	for(p = f->self->hash[h]; p; p = p->next)
.
589c
	qlock(f->self);
.
583c
addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
.
575c
	ipifc = smalloc(sizeof(Ipifc));
	ipifc->name = "ipifc";
	ipifc->kick = ipifckick;
	ipifc->connect = ipifcconnect;
	ipifc->announce = nil;
	ipifc->bind = ipifcbind;
	ipifc->state = ipifcstate;
	ipifc->create = ipifccreate;
	ipifc->close = ipifcclose;
	ipifc->rcv = nil;
	ipifc->ctl = ipifcctl;
	ipifc->advise = nil;
	ipifc->stats = ipifcstats;
	ipifc->inuse = ipifcinuse;
	ipifc->local = ipifclocal;
	ipifc->ipproto = -1;
	ipifc->nc = Maxmedia;
	ipifc->ptclsize = sizeof(Ipifc);

	f->ipifc = ipifc;			/* hack for ipifcremroute, findipifc, ... */
	f->self = smalloc(sizeof(Ipselftab));	/* hack for ipforme */

	Fsproto(f, ipifc);
.
557,573c
	Proto *ipifc;
.
555c
ipifcinit(Fs *f)
.
553a
ipifcstats(Proto *ipifc, char *buf, int len)
{
	return ipstats(ipifc->f, buf, len);
}

.
542a
 	else if(strcmp(argv[0], "bootp") == 0)
		return bootp(ifc);
.
526c
	Fsconnected(c, nil);
.
475c
	e = &f->ipifc->conv[f->ipifc->nc];
	for(cp = f->ipifc->conv; cp < e; cp++){
.
472c
	Conv **cp, **e;
.
469c
ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
.
456c
	e = &f->ipifc->conv[f->ipifc->nc];
	for(cp = f->ipifc->conv; cp < e; cp++){
.
453c
	Conv **cp, **e;
.
450c
ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
.
433c
		v6delroute(f, lifc->remote, lifc->mask);
.
431c
		v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off);
.
427c
		remselfcache(f, ifc, lifc, lifc->link->self->a);
.
400a
	f = ifc->conv->p->f;

.
396a
	Fs *f;
.
379c
	addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
.
377c
	addselfcache(f, ifc, lifc, bcast, Rbcast);
.
371c
	addselfcache(f, ifc, lifc, bcast, Rbcast);
.
366c
	addselfcache(f, ifc, lifc, ip, Runi);
.
364c
		v6addroute(f, tifc, ip, mask, rem, type);
.
362c
		v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, ip+IPv4off, type);
.
302a
	f = ifc->conv->p->f;

.
301a
	Fs *f;
.
255c
		(*ifc->m->pktin)(c->p->f, ifc, bp);
.
73,74c
static void	addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
static void	remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
.
54d
46d
27a
	&tripmedium,
.
20,22d
## diffname ip/ipifc.c 1998/0314
## diff -e /n/emeliedump/1998/0313/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0314/sys/src/brazil/ip/ipifc.c
556a
	else if(strcmp(argv[0], "iprouting") == 0){
		i = 1;
		if(argc > 1)
			i = atoi(argv[1]);
		iprouting(c->p->f, i);
		return nil;
	}
.
542a
	int i;
.
## diffname ip/ipifc.c 1998/0316
## diff -e /n/emeliedump/1998/0314/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0316/sys/src/brazil/ip/ipifc.c
880c
	/* for now for broadcast and multicast, just use first interface */
.
878a
	if(x != nil)
		return x;
.
875,876c
			if(ipcmp(gnet, lifc->net) == 0){
				if(x == nil || ipcmp(lifc->mask, xmask) > 0){
					x = ifc;
					ipmove(xmask, lifc->mask);
				}
			}
.
867a
	x = nil;

	/* find most specific match */
.
866a
	uchar xmask[IPaddrlen];
.
863c
	Ipifc *ifc, *x;
.
363c
		v6addroute(f, tifc, rem, mask, ip, type);
.
## diffname ip/ipifc.c 1998/0318
## diff -e /n/emeliedump/1998/0316/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0318/sys/src/brazil/ip/ipifc.c
375a
	addselfcache(f, ifc, lifc, bcast, Rbcast);

	/* add old network directed broadcast addresses to the self cache */
	memmove(mask, defmask(ip), IPaddrlen);
	for(i = 0; i < IPaddrlen; i++)
		bcast[i] = (ip[i] & mask[i]) & mask[i];
.
371a
	/* add old subnet directed broadcast addresses to the self cache */
	for(i = 0; i < IPaddrlen; i++)
		bcast[i] = (ip[i] & mask[i]) & mask[i];
	addselfcache(f, ifc, lifc, bcast, Rbcast);

.
## diffname ip/ipifc.c 1998/0330
## diff -e /n/emeliedump/1998/0318/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0330/sys/src/brazil/ip/ipifc.c
568a
	else if(strcmp(argv[0], "mtu") == 0)
		return ipifcsetmtu(ifc, argv, argc);
.
288a
 *  change an interface's mtu
 */
char*
ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
{
	int mtu;

	if(argc < 2)
		return Ebadarg;
	if(ifc->m == nil)
		return Ebadarg;
	mtu = strtoul(argv[1], 0, 0);
	if(mtu < ifc->m->minmtu || mtu > ifc->m->maxmtu)
		return Ebadarg;
	ifc->maxmtu = mtu;
	return nil;
}

/*
.
## diffname ip/ipifc.c 1998/0423
## diff -e /n/emeliedump/1998/0330/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0423/sys/src/brazil/ip/ipifc.c
72a

/*
 *  link in a new medium
 */
void
addipmedium(Medium *med)
{
	int i;

	for(i = 0; i < nelem(media)-1; i++)
		if(media[i] == nil){
			media[i] = med;
			break;
		}
}
.
22,25d
20c
Medium *media[32] =
.
## diffname ip/ipifc.c 1998/0507
## diff -e /n/emeliedump/1998/0423/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0507/sys/src/brazil/ip/ipifc.c
162a
	ifc->conv->inuse--;
.
137a
	ifc->conv->inuse++;
.
## diffname ip/ipifc.c 1998/0515
## diff -e /n/emeliedump/1998/0507/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0515/sys/src/brazil/ip/ipifc.c
296c
	if(m == nil || m->unbindonclose)
.
168c
	if(ifc->m)
		(*ifc->m->unbind)(ifc);
.
## diffname ip/ipifc.c 1998/0516
## diff -e /n/emeliedump/1998/0515/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0516/sys/src/brazil/ip/ipifc.c
297c
	if(m != nil && m->unbindonclose)
.
190a

.
168c
	if(ifc->m != nil && ifc->m->unbind)
.
164c
	if(ifc->m != nil && ifc->m->unbindonclose == 0){
		lock(ifc->conv);
		ifc->conv->inuse--;
		unlock(ifc->conv);
	}
.
138c
	if(ifc->m->unbindonclose == 0){
		lock(ifc->conv);
		ifc->conv->inuse++;
		unlock(ifc->conv);
	}
.
## diffname ip/ipifc.c 1998/0630
## diff -e /n/emeliedump/1998/0516/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0630/sys/src/brazil/ip/ipifc.c
839c
		v6delroute(f, a, IPallbits, 1);
.
837c
		v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
.
488c
		v6delroute(f, lifc->remote, lifc->mask, 1);
.
486c
		v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
.
220c
	}
.
217c
			" %-20.20I %-20.20M %-20.20I %-7d %-7d %-7d %-7d\n",
.
215c
	m = 0;
	for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
		m += snprint(state, n, "%-12.12s %-5d", ifc->dev, ifc->maxmtu);
.
212,213d
199d
176,177c
	(*ifc->m->unbind)(ifc);
.
168,172c
	ifc->conv->inuse--;
.
138,142c
	ifc->conv->inuse++;
.
## diffname ip/ipifc.c 1998/0702
## diff -e /n/emeliedump/1998/0630/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0702/sys/src/brazil/ip/ipifc.c
331a
	if(ifc->m == nil)
		return "ipifc not yet bound to device";

.
## diffname ip/ipifc.c 1998/0709
## diff -e /n/emeliedump/1998/0702/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0709/sys/src/brazil/ip/ipifc.c
210d
203,205c
	for(lifc = ifc->lifc; lifc; lifc = lifc->next)
.
201a
	m = snprint(state, n, "%-12.12s %-5d", ifc->dev, ifc->maxmtu);

.
168c
	if(ifc->m != nil && ifc->m->unbind)
		(*ifc->m->unbind)(ifc);
.
164c
	if(ifc->m != nil && ifc->m->unbindonclose == 0){
		lock(ifc->conv);
		ifc->conv->inuse--;
		unlock(ifc->conv);
	}
.
138c
	if(ifc->m->unbindonclose == 0){
		lock(ifc->conv);
		ifc->conv->inuse++;
		unlock(ifc->conv);
	}
.
## diffname ip/ipifc.c 1998/0717
## diff -e /n/emeliedump/1998/0709/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0717/sys/src/brazil/ip/ipifc.c
496,497d
494c
	if(dolock)
.
479a
	}
.
478c
	if(lifc == nil){
		if(dolock)
			wunlock(ifc);
.
466d
460,464c
	if(dolock)
.
436d
377,380d
214c
	for(lifc = ifc->lifc; lifc && n > m; lifc = lifc->next)
.
## diffname ip/ipifc.c 1998/0728
## diff -e /n/emeliedump/1998/0717/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0728/sys/src/brazil/ip/ipifc.c
1098a
int
ipisbm(uchar *ip)
{
	if(isv4(ip)){
		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
			return V4;
		if(ipcmp(ip, IPv4bcast) == 0)
			return V4;
	} else {
		if(ip[0] == 0xff)
			return V6;
	}
	return 0;
}

.
## diffname ip/ipifc.c 1998/0825
## diff -e /n/emeliedump/1998/0728/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0825/sys/src/brazil/ip/ipifc.c
216c
			" %-20.20I %-20.20M %-20.20I %-7lud %-7lud %-7lud %-7lud\n",
.
## diffname ip/ipifc.c 1998/0930
## diff -e /n/emeliedump/1998/0825/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/0930/sys/src/brazil/ip/ipifc.c
486d
## diffname ip/ipifc.c 1998/1005
## diff -e /n/emeliedump/1998/0930/sys/src/brazil/ip/ipifc.c /n/emeliedump/1998/1005/sys/src/brazil/ip/ipifc.c
988,999c

	findprimaryip(f, local);
.
974,978d
959d
950a
 *  returns first ip address configured
 */
void
findprimaryip(Fs *f, uchar *local)
{
	Conv **cp, **e;
	Ipifc *ifc;
	Iplifc *lifc;

	/* find first ifc local address */
	e = &f->ipifc->conv[f->ipifc->nc];
	for(cp = f->ipifc->conv; cp < e; cp++){
		if(*cp == 0)
			continue;
		ifc = (Ipifc*)(*cp)->ptcl;
		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
			ipmove(local, lifc->local);
			return;
		}
	}
}

/*
.
405a
	if(type & Rptpt)
		goto out;

.
398a
	}
.
397c
	if(ipcmp(mask, IPallbits) == 0){
		/* point to point networks are a hack */
		if(ipcmp(ip, rem) == 0)
			findprimaryip(f, lifc->local);
.
218a
	if(ifc->lifc == nil)
		m += snprint(state+m, n - m, "\n");
.
## diffname ip/ipifc.c 1999/0223
## diff -e /n/emeliedump/1998/1005/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/0223/sys/src/brazil/ip/ipifc.c
211c
	m = snprint(state, n, "%-12s %-5d", ifc->dev, ifc->maxmtu);
.
## diffname ip/ipifc.c 1999/0302
## diff -e /n/emeliedump/1999/0223/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/0302/sys/src/brazil/ip/ipifc.c
308c
	qunlock(c);
.
171c
		qunlock(ifc->conv);
.
169c
		qlock(ifc->conv);
.
141c
		qunlock(ifc->conv);
.
139c
		qlock(ifc->conv);
.
## diffname ip/ipifc.c 1999/0731
## diff -e /n/emeliedump/1999/0302/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/0731/sys/src/brazil/ip/ipifc.c
1233a
static void
ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
{
	Conv **cp, **e;
	Ipifc *nifc;
	Iplifc *lifc;
	uchar net[IPaddrlen];

	/* register the address on any network that will proxy for us */
	e = &f->ipifc->conv[f->ipifc->nc];
	for(cp = f->ipifc->conv; cp < e; cp++){
		if(*cp == nil)
			continue;
		nifc = (Ipifc*)(*cp)->ptcl;
		if(nifc->m->areg == nil)
			continue;
		if(nifc == ifc)
			continue;
		for(lifc = nifc->lifc; lifc; lifc = lifc->next){
			maskip(ip, lifc->mask, net);
			if(ipcmp(net, lifc->remote) == 0){
				(*nifc->m->areg)(nifc, ip);
				break;
			}
		}
	}
}
.
438a
	/* register the address on this network for address resolution */
	if(ifc->m->areg != nil)
		(*ifc->m->areg)(ifc, ip);

.
413a
	}
.
412c
	if(type & Rptpt){
		ipifcregisterproxy(f, ifc, rem);
.
68a
static void	ipifcregisterproxy(Fs*, Ipifc*, uchar*);
.
## diffname ip/ipifc.c 1999/0803
## diff -e /n/emeliedump/1999/0731/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/0803/sys/src/brazil/ip/ipifc.c
1265a
		runlock(nifc);
.
1262c
				(*m->areg)(nifc, ip);
.
1258a

		rlock(nifc);
		m = nifc->m;
		if(m == nil || m->areg == nil){
			runlock(nifc);
			continue;
		}
.
1255,1256d
1246a
	Medium *m;
.
## diffname ip/ipifc.c 1999/0909
## diff -e /n/emeliedump/1999/0803/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/0909/sys/src/brazil/ip/ipifc.c
1091,1093c
	if((r->type & (Rifc|Rptpt|Rproxy)) != (Rifc|Rptpt|Rproxy))
.
413c
	if((type & (Rptpt|Rproxy)) == (Rptpt|Rproxy)){
.
399d
351a
	case 6:
		if(strcmp(argv[5], "proxy") == 0)
			type |= Rproxy;
		/* fall through */
.
347a
	type = Rifc;
.
## diffname ip/ipifc.c 1999/1029
## diff -e /n/emeliedump/1999/0909/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/1029/sys/src/brazil/ip/ipifc.c
486a
		l = &lifc->next;
	}
.
478,483c
	/* Are we point to point */
	type = 0;
	if(ipcmp(mask, IPallbits) == 0)
		type = Rptpt;

	/*
	 *  find address on this interface and remove from chain.
	 *  for pt to pt we actually specify the remote address at the
	 *  addresss to remove.
	 */
	l = &ifc->lifc;
	for(lifc = *l; lifc != nil; lifc = lifc->next) {
		addr = lifc->local;
		if(type == Rptpt)
			addr = lifc->remote;
		if(memcmp(ip, addr, IPaddrlen) == 0 && memcmp(mask, lifc->mask, IPaddrlen) == 0) {
.
## diffname ip/ipifc.c 1999/1031
## diff -e /n/emeliedump/1999/1029/sys/src/brazil/ip/ipifc.c /n/emeliedump/1999/1031/sys/src/9/ip/ipifc.c
493c
		if(memcmp(ip, addr, IPaddrlen) == 0)
		if(memcmp(mask, lifc->mask, IPaddrlen) == 0) {
.
465a
	uchar *addr;
	int type;
.
## diffname ip/ipifc.c 2000/0107
## diff -e /n/emeliedump/1999/1031/sys/src/9/ip/ipifc.c /n/emeliedump/2000/0107/sys/src/9/ip/ipifc.c
598,599c
		if(ipcmp(ifc->lifc->mask, IPallbits) == 0)
			sprint(ip, "%I", ifc->lifc->remote);
		else
			sprint(ip, "%I", ifc->lifc->local);
		sprint(mask, "%M", ifc->lifc->mask);
.
192c
		if(ipcmp(ifc->lifc->mask, IPallbits) == 0)
			sprint(ip, "%I", ifc->lifc->remote);
		else
			sprint(ip, "%I", ifc->lifc->local);
.
## diffname ip/ipifc.c 2000/0126
## diff -e /n/emeliedump/2000/0107/sys/src/9/ip/ipifc.c /n/emeliedump/2000/0126/sys/src/9/ip/ipifc.c
20c
Medium *media[Maxmedia] =
.
13c
	Maxmedia	= 32,
.
## diffname ip/ipifc.c 2000/0913
## diff -e /n/emeliedump/2000/0126/sys/src/9/ip/ipifc.c /n/emeliedump/2000/0913/sys/src/9/ip/ipifc.c
665c
	ipifc = smalloc(sizeof(Proto));
.
## diffname ip/ipifc.c 2000/1111
## diff -e /n/emeliedump/2000/0913/sys/src/9/ip/ipifc.c /n/emeliedump/2000/1111/sys/src/9/ip/ipifc.c
633,634d
## diffname ip/ipifc.c 2000/1220
## diff -e /n/emeliedump/2000/1111/sys/src/9/ip/ipifc.c /n/emeliedump/2000/1220/sys/src/9/ip/ipifc.c
312d
172,173d
169,170c
	if(ifc->m != nil && ifc->m->unbindonclose == 0)
.
153a
 *  called with ifc->conv closed
.
142,143d
139,140c
	if(ifc->m->unbindonclose == 0)
.
102c
 *  called with c locked
.
## diffname ip/ipifc.c 2001/0306
## diff -e /n/emeliedump/2000/1220/sys/src/9/ip/ipifc.c /n/emeliedump/2001/0306/sys/src/9/ip/ipifc.c
260c
ipifckick(Conv *c)
.
## diffname ip/ipifc.c 2001/0710
## diff -e /n/emeliedump/2001/0306/sys/src/9/ip/ipifc.c /n/emeliedump/2001/0710/sys/src/9/ip/ipifc.c
504a

	ifc->ifcid++;
.
410c
		v6addroute(f, tifc, rem, mask, rem, type);
.
408c
		v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
.
## diffname ip/ipifc.c 2001/1117
## diff -e /n/emeliedump/2001/0710/sys/src/9/ip/ipifc.c /n/emeliedump/2001/1117/sys/src/9/ip/ipifc.c
639c
	else if(strcmp(argv[0], "reassemble") == 0){
		ifc->reassemble = 1;
		return nil;
	} else if(strcmp(argv[0], "iprouting") == 0){
.
290a
	ifc->reassemble = 0;
.
175a
	ifc->reassemble = 0;
.
## diffname ip/ipifc.c 2002/0221
## diff -e /n/emeliedump/2001/1117/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0221/sys/src/9/ip/ipifc.c
909d
902,907c
			nifc = 0;
			for(link = p->link; link; link = link->selflink)
				nifc++;
			routetype(p->type, state);
			m += snprint(cp + m, n - m, stformat, p->a, nifc, state);
			if(off > 0){
				off -= m;
				m = 0;
.
898a
	off = offset;
.
893c
	int i, m, nifc, off;
.
885,888d
## diffname ip/ipifc.c 2002/0507
## diff -e /n/emeliedump/2002/0221/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0507/sys/src/9/ip/ipifc.c
1293a

	if(found==0) {
		if(routerlt <= 0)
			return nil;
		else if((force) && (j<0)) {
			j = f->v6p->cdrouter;
			f->v6p->cdrouter = -1;
		}
	}

	// assert((found && (j>=0))||(!found && routerlt>0));
	if(routerlt > 0) {
		memset(&r[j], 0, sizeof(v6router));
		r[j].inuse = 1;
		r[j].ifc = ifc;
		r[j].ifcid = ifc->ifcid;
		ipmove(r[j].routeraddr, routeraddr);
		r[j].ltorigin = msec / 10^3;
		r[j].rp.mflag = (mflag!=0);
		r[j].rp.oflag = (oflag!=0);
		r[j].rp.rxmitra = rxmitra;
		r[j].rp.reachtime = reachtime;
		r[j].rp.routerlt = routerlt;
		r[j].rp.ttl = ttl;

		if((f->v6p->cdrouter < 0) || (force==1)) {
			f->v6p->cdrouter = j;
			adddefroute6(f, routeraddr, force);
		}
	}
	else if(j >= 0) {		// remove router
		r[j].inuse = 0;
		if(f->v6p->cdrouter==j) {
			f->v6p->cdrouter = -1;
			v6delroute(f, v6Unspecified, v6Unspecified, 1);
			for(i=0; i<Ngates; i++) {
				if(r[i].inuse) {
					f->v6p->cdrouter = i;
					adddefroute6(f, r[i].routeraddr, 1);
					break;
				}
			}
		}
	}
	return nil;
}

char*
ipifcaddpref6(Ipifc *ifc, char**argv, int argc)
{
	uchar	onlink = 1;
	uchar	autoflag = 1;
	long 	validlt = 0xffffffff;
	long 	preflt = 0xffffffff;
	long	origint = msec / 10^3;
	uchar	prefix[IPaddrlen];
	int	plen = 64;
	Iplifc	*lifc;
	char	addr[40];
	char	*params[3];

	switch(argc) {
	case 7:
		preflt = atoi(argv[6]);
		/* fall through */
	case 6:
		validlt = atoi(argv[5]);
		/* fall through */
	case 5:
		autoflag =  atoi(argv[4]);
		/* fall through */
	case 4:
		onlink = atoi(argv[3]);
		/* fall through */
	case 3:
		plen = atoi(argv[2]);
	case 2:
		break;
	default:
		return Ebadarg;
	}

	if((parseip(prefix, argv[1])!=6) ||
	 	(validlt < preflt) ||
		(plen > 64) ||
		(islinklocal(prefix))
	)
		return Ebadarg;

	lifc = smalloc(sizeof(Iplifc));
	lifc->onlink = (onlink!=0);
	lifc->autoflag = (autoflag!=0);
	lifc->validlt = validlt;
	lifc->preflt = preflt;
	lifc->origint = origint;

	if(ifc->m->pref2addr!=nil) 
		ifc->m->pref2addr(prefix, ifc->mac);
	else
		return Ebadarg;
	
	sprint(addr, "%I", prefix);
	params[0] = "add";
	params[1] = addr;
	params[2] = "/64";

	return ipifcadd(ifc, params, 3, 0, lifc);
}

static char *gateformat = "%-1.1s %-40.40I %20ld %10d %-40.40s\n";
enum
{
	Ngateformat= 116,
};

static char *rtrstat[] =
{
[0]	"*",
[1]	"-",
};

/* line corresponding to current default router, if in f->v6p->v6rlist, 
   starts with a "*", others with a "-". */

long
ipgateread6(Fs *f, char *cp, ulong offset, int n)
{
	v6router	*r = f->v6p->v6rlist;
	int	i, j, k, l;
	long	m;


	if(offset % Ngateformat)
		return 0;

	offset = offset/Ngateformat;
	n = n/Ngateformat;

	i = f->v6p->cdrouter;
	k = i;
	if((i<0)||(i>2))
		i = 0;
	m = 0;
	for(j = 0; (n > 0) && (j < Ngates) ; j++){
		if(offset > 0){
			offset--;
			i = (i+1) % Ngates;
			continue;
		}
		n--;
		if(r[i].inuse) {
			l = (i==k) ? 0 : 1;				
			m += sprint(cp + m, gateformat, 
				rtrstat[l], r[i].routeraddr, r[i].ltorigin,  
				r[i].rp.routerlt, r[i].ifc->dev);
		}
		i = (i+1) % Ngates;
	}
	return m;
.
1292c
		else {
			j = i;
		}
.
1285,1288c
		return;
	}
	else { // V4
		for(cp = f->ipifc->conv; cp < e; cp++){
			if(*cp == nil)
				continue;
			nifc = (Ipifc*)(*cp)->ptcl;
			if(nifc == ifc)
				continue;
	
			rlock(nifc);
			m = nifc->m;
			if(m == nil || m->areg == nil){
				runlock(nifc);
				continue;
			}
			for(lifc = nifc->lifc; lifc; lifc = lifc->next){
				maskip(ip, lifc->mask, net);
				if(ipcmp(net, lifc->remote) == 0){
					(*m->areg)(nifc, ip);
					break;
				}
			}
			runlock(nifc);
		}
	}
}


// added for new v6 mesg types
static void
adddefroute6(Fs *f, uchar *gate, int force)
{
	Route *r;

	r = v6lookup(f, v6Unspecified);
	if(r!=nil) 
	if(!(force) && (strcmp(r->tag,"ra")!=0))	// route entries generated
		return;			// by all other means take
					// precedence over router annc

	v6delroute(f, v6Unspecified, v6Unspecified, 1);
	v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
}

enum
{
	Ngates = 3,
};

char*
ipifcaddgate6(Fs *f, Ipifc *ifc, char**argv, int argc)
{
	v6router	*r = f->v6p->v6rlist;
	uchar	routeraddr[IPaddrlen];
	int	mflag = f->v6p->rp.mflag;
	int	oflag = f->v6p->rp.oflag;
	int	reachtime = f->v6p->rp.reachtime;
	int	rxmitra = f->v6p->rp.rxmitra;
	int	ttl = MAXTTL;
	int	routerlt = f->v6p->rp.routerlt;
	int	force;		// force == 1 forces argv[1] to
				// be the default router.
	int	i, j;
	int	found = 0;

	if((argc<3)||(argc>9)) 
		return Ebadarg;
	if( (parseip(routeraddr, argv[1])!=6) || !(islinklocal(routeraddr)) ) 
		return Ebadarg;

	force = (atoi(argv[2])!=0);

	switch(argc){
	case 9:
		rxmitra = atoi(argv[8]);
		/* fall through */
	case 8:
		reachtime = atoi(argv[7]);
		/* fall through */
	case 7:
		routerlt =  atoi(argv[6]);
		/* fall through */
	case 6:
		oflag = atoi(argv[5]);
		/* fall through */
	case 5:
		mflag = atoi(argv[4]);
		/* fall through */
	case 4:
		ttl = atoi(argv[3]);
		/* fall through */
	}

	if((force) && (routerlt < 0))
		return Ebadarg;
	if((ttl < 0) || (255 < ttl))
		return Ebadarg;

	j = -1;
	for(i=0; i<Ngates; i++) {
		if(r[i].inuse) {
			if((ipcmp(routeraddr, r[i].routeraddr)==0) &&
			(r[i].ifc==ifc)) {
				j = i;
				found = 1;
.
1283d
1279,1281c
	if(!isv4(ip)) { // V6
		for(cp = f->ipifc->conv; cp < e; cp++){
			if(*cp == nil)
				continue;
			nifc = (Ipifc*)(*cp)->ptcl;
			if(nifc == ifc)
				continue;
	
			rlock(nifc);
			m = nifc->m;
			if(m == nil || m->addmulti == nil) {
				runlock(nifc);
				continue;
			}
			for(lifc = nifc->lifc; lifc; lifc = lifc->next){
				maskip(ip, lifc->mask, net);
				if(ipcmp(net, lifc->remote) == 0) { /* add solicited-node multicast address */
					ipv62smcast(net, ip);
					addselfcache(f, nifc, lifc, net, Rmulti);
					arpenter(f, V6, ip, nifc->mac, 6, 0);
					//(*m->addmulti)(nifc, net, ip);
					break;
				}
			}
.
1272,1277d
1075a
		if(!isv4(lifc->local) && !(lifc->tentative)){
			ipmove(addr, lifc->local);
			return 1;
		}
	}
	return 0;
}

int
ipv6anylocal(Ipifc *ifc, uchar *addr)
{
	Iplifc *lifc;

	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
.
1045a

.
1044c
	if(version == 4)
		findprimaryip(f, local);
	else
		findprimaryip6(f, local);
.
1041a
		else {
			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
				atypel = v6addrtype(lifc->local);
				maskip(gate, lifc->mask, gnet);
				if(ipcmp(gnet, lifc->net) == 0)
				if(atypel > atype)
				if(v6addrcurr(lifc)) {
					ipmove(local, lifc->local);
					atype = atypel;
					if(atype == globalv6)
						break;
				}
			}
			if(atype > unspecifiedv6)
				goto out;
		}
.
1035,1039c
		if(version == 4) {
			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
				maskip(gate, lifc->mask, gnet);
				if(ipcmp(gnet, lifc->net) == 0){
					ipmove(local, lifc->local);
					goto out;
				}
.
1032a
			ipmove(local, v6Unspecified);
		}
.
1031c
		else {
.
1025a
 	version = (memcmp(remote, v4prefix, IPv4off) == 0) ? 4 : 6;
.
1023a
	USED(atype);
	USED(atypel);
.
1022a
	int version;
	int atype = unspecifiedv6, atypel = unknownv6;
.
989c
 *  returns first ip address configured 
.
987a
enum {
	unknownv6,
	multicastv6,
	unspecifiedv6,
	linklocalv6,
	sitelocalv6,
	globalv6,
};

int
v6addrtype(uchar *addr)
{
	if(isv6global(addr))
		return globalv6;
	if(islinklocal(addr))
		return linklocalv6;
	if(isv6mcast(addr))
		return multicastv6;
	if(issitelocal(addr))
		return sitelocalv6;
	return unknownv6;
}

#define v6addrcurr(lifc) (( (lifc)->origint + (lifc)->preflt >= (msec/10^3) ) || ( (lifc)->preflt == 0xffffffff ))

void
findprimaryip6(Fs *f, uchar *local)
{
	Conv **cp, **e;
	Ipifc *ifc;
	Iplifc *lifc;
	int atype, atypel;

	ipmove(local, v6Unspecified);
	atype = unspecifiedv6;

	/* find "best" (global > sitelocal > link local > unspecified)
	 * local address; address must be current */

	e = &f->ipifc->conv[f->ipifc->nc];
	for(cp = f->ipifc->conv; cp < e; cp++){
		if(*cp == 0)
			continue;
		ifc = (Ipifc*)(*cp)->ptcl;
		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
			atypel = v6addrtype(lifc->local);
			if(atypel > atype) 
			if(v6addrcurr(lifc)) {
				ipmove(local, lifc->local);
				atype = atypel;
				if(atype == globalv6)
					return;
			}
		}
	}
}

.
960a

.
959a

.
953c
	x = nil; memset(xmask, 0, IPaddrlen);
.
914a
	p = f->self->hash[hashipa(addr)];
	for(; p; p = p->next){
		if(ipcmp(addr, p->a) == 0) {
			return p->link->lifc->tentative;
		}
	}
	return 0;
}

.
913a
int
iptentative(Fs *f, uchar *addr) 
{
 	Ipself *p;
.
884a
enum
{
	Nstformat= 41,
};
.
650a
	else if(strcmp(argv[0], "gate6") == 0)
		return ipifcaddgate6(c->p->f, ifc, argv, argc);
	else if(strcmp(argv[0], "addpref6") == 0)
		return ipifcaddpref6(ifc, argv, argc);
	else if(strcmp(argv[0], "setpar6") == 0)
		return ipifcsetpar6(ifc, argv, argc);
	else if(strcmp(argv[0], "sendra6") == 0) 
		return ipifcsendra6(ifc, argv, argc);
	else if(strcmp(argv[0], "recvra6") == 0)
		return ipifcrecvra6(ifc, argv, argc);
.
644c
	}
	else if(strcmp(argv[0], "iprouting") == 0){
.
630c
		return ipifcadd(ifc, argv, argc, 0, nil);
	else if(strcmp(argv[0], "try") == 0)
		return ipifcadd(ifc, argv, argc, 1, nil);
.
617a
char*
ipifcsetpar6(Ipifc *ifc, char **argv, int argc)
{
	int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;

	argsleft = argc - 1;
	i = 1;

	if(argsleft % 2 != 0)
		return Ebadarg;

	while (argsleft > 1) {
		if(strcmp(argv[i],"recvra")==0) 
			ifc->recvra6 = (atoi(argv[i+1]) != 0);
		else if(strcmp(argv[i],"sendra")==0) 
			ifc->sendra6 = (atoi(argv[i+1]) != 0);
		else if(strcmp(argv[i],"mflag")==0) 
			ifc->rp.mflag = (atoi(argv[i+1]) != 0);
		else if(strcmp(argv[i],"oflag")==0) 
			ifc->rp.oflag = (atoi(argv[i+1]) != 0);
		else if(strcmp(argv[i],"maxraint")==0)
			ifc->rp.maxraint = atoi(argv[i+1]);
		else if(strcmp(argv[i],"minraint")==0)
			ifc->rp.minraint = atoi(argv[i+1]);
		else if(strcmp(argv[i],"linkmtu")==0) 
			ifc->rp.linkmtu = atoi(argv[i+1]);
		else if(strcmp(argv[i],"reachtime")==0) 
			ifc->rp.reachtime = atoi(argv[i+1]);
		else if(strcmp(argv[i],"rxmitra")==0) 
			ifc->rp.rxmitra = atoi(argv[i+1]);
		else if(strcmp(argv[i],"ttl")==0) 
			ifc->rp.ttl = atoi(argv[i+1]);
		else if(strcmp(argv[i],"routerlt")==0) 
			ifc->rp.routerlt = atoi(argv[i+1]);
		else 
			return Ebadarg;	

		argsleft -= 2;
		i += 2;
	}

	// consistency check
	if(ifc->rp.maxraint < ifc->rp.minraint) {
		ifc->rp.maxraint = vmax;
		ifc->rp.minraint = vmin;
		return Ebadarg;
	}

	return nil;
}

char*
ipifcsendra6(Ipifc *ifc, char **argv, int argc)
{
	int i;
	
	i = 0;
	if(argc > 1)
		i = atoi(argv[1]);
	ifc->sendra6 = (i!=0);
	return nil;
}

char*
ipifcrecvra6(Ipifc *ifc, char **argv, int argc)
{
	int i;
	
	i = 0;
	if(argc > 1) 
		i = atoi(argv[1]);
	ifc->recvra6 = (i!=0);	
	return nil;
}

.
609c
	err = ipifcadd(ifc, argv, argc, 0, nil);
.
528c
 * distribute routes to active interfaces like the
.
518a
		if(ipcmp(ip, v6loopback) == 0)
			/* remove route for all node multicast */
			v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
		else if(memcmp(ip, v6linklocal, v6linklocalprefix) == 0)
			/* remove route for all link multicast */
			v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
	}
.
517c
	else {
.
508,509d
450a
	if(tentative && sendnbrdisc) 
		icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
.
446c
	if(isv4(ip) && ifc->m->areg != nil)
.
444a
		else if(memcmp(ip, v6linklocal, v6linklocalprefix) == 0) {
			/* add link-local mcast address */
			addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
			
			/* add route for all link multicast */
			v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL, Rmulti);
			
			/* add solicited-node multicast address */
			ipv62smcast(bcast, ip);
			addselfcache(f, ifc, lifc, bcast, Rmulti);
		}

		sendnbrdisc = 1;
	}

.
443c
			/* add route for all node multicast */
			v6addroute(f, tifc, v6allnodesN, v6allnodesNmask, v6allnodesN, Rmulti);
		}
.
437,441c
		/* add network directed network address to the self cache */
		memmove(mask, defmask(ip), IPaddrlen);
		for(i = 0; i < IPaddrlen; i++)
			bcast[i] = (ip[i] & mask[i]) & mask[i];
		addselfcache(f, ifc, lifc, bcast, Rbcast);
		
		addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
	} 
	else {
		if(ipcmp(ip, v6loopback) == 0) {
			/* add node-local mcast address */
			addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
.
431,435c
		/* add network directed broadcast address to the self cache */
		memmove(mask, defmask(ip), IPaddrlen);
		for(i = 0; i < IPaddrlen; i++)
			bcast[i] = (ip[i] & mask[i]) | ~mask[i];
		addselfcache(f, ifc, lifc, bcast, Rbcast);
.
426,429c
		/* add subnet directed network address to the self cache */
		for(i = 0; i < IPaddrlen; i++)
			bcast[i] = (ip[i] & mask[i]) & mask[i];
		addselfcache(f, ifc, lifc, bcast, Rbcast);
.
421,424c
	if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
		/* add subnet directed broadcast address to the self cache */
		for(i = 0; i < IPaddrlen; i++)
			bcast[i] = (ip[i] & mask[i]) | ~mask[i];
		addselfcache(f, ifc, lifc, bcast, Rbcast);
.
408a

	/* add local routes */
.
402c
	/* check for point-to-point interface */
	if(ipcmp(ip, v6loopback))  /* skip v6 loopback, it's a special address */
.
397a

.
396a
	lifc->tentative = tentative;
	if(lifcp != nil) {
		lifc->onlink = lifcp->onlink;
		lifc->autoflag = lifcp->autoflag;
		lifc->validlt = lifcp->validlt;
		lifc->preflt = lifcp->preflt;
		lifc->origint = lifcp->origint;
	}
	else {		// default values
		lifc->onlink = 1;
		lifc->autoflag = 1;
		lifc->validlt = 0xffffffff;
		lifc->preflt = 0xffffffff;
		lifc->origint = msec / 10^3;
	}
.
389a
		}
	}
.
387,388c
	for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
		if(ipcmp(lifc->local, ip) == 0) {
			if(lifc->tentative != tentative) 
				lifc->tentative = tentative;
			if(lifcp != nil) {
				lifc->onlink = lifcp->onlink;
				lifc->autoflag = lifcp->autoflag;
				lifc->validlt = lifcp->validlt;
				lifc->preflt = lifcp->preflt;
				lifc->origint = lifcp->origint;
			}
.
383c
	if(isv4(ip))
		tentative = 0;
.
340a
	int sendnbrdisc = 0;
.
334c
ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
.
241c
			m += snprint(state+m, n - m, " %-40.40I", link->self->a);
.
239c
		m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
.
215,218c
		m += snprint(state+m, n - m, slineformat,
			lifc->local, lifc->mask, lifc->remote,
			lifc->validlt, lifc->preflt);
.
211c
	m = snprint(state, n, sfixedformat, 
		ifc->dev, ifc->maxmtu, ifc->sendra6, ifc->recvra6,
		ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
		ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
		ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
		ifc->in, ifc->out, ifc->inerr, ifc->outerr);
.
201a


char *sfixedformat = "device %-12s maxmtu %-5d sendra %-1d recvra %-1d mflag %-1d oflag %-1d maxraint %-10d minraint %-10d linkmtu %-10d reachtime %-10d rxmitra %-10d ttl %-10d routerlt %-10d pktin %-7lud pktout %-7lud errin %-7lud errout %-7lud\n";

char *slineformat = "	%-40.40I %-10.10M %-40.40I %-12lud %-12lud\n";


.
140a

	ifc->rp.mflag	= 0;		// default not managed
	ifc->rp.oflag	= 0;
	ifc->rp.maxraint	= 600000;	// millisecs
	ifc->rp.minraint	= 200000;
	ifc->rp.linkmtu	= 0;		// no mtu sent
	ifc->rp.reachtime	= 0;
	ifc->rp.rxmitra	= 0;
	ifc->rp.ttl	= MAXTTL;
	ifc->rp.routerlt	= 3*(ifc->rp.maxraint);	

.
8a
#include "ipv6.h"
.
## diffname ip/ipifc.c 2002/0517
## diff -e /n/emeliedump/2002/0507/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0517/sys/src/9/ip/ipifc.c
218c
char slineformat[] = "	%-40.40I %-10.10M %-40.40I %-12lud %-12lud\n";
.
216c
char sfixedformat[] = "device %s maxmtu %d sendra %d recvra %d mflag %d oflag %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt %d pktin %lud pktout %lud errin %lud errout %lud\n";
.
## diffname ip/ipifc.c 2002/0601
## diff -e /n/emeliedump/2002/0517/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0601/sys/src/9/ip/ipifc.c
1324c
		break;
	default:
		panic("findlocalip2: version %d", version);
	}
.
1322c
		break;
	case V6:
.
1320c
	switch(version){
	case V4:
.
1316a
			break;
		default:
			panic("findlocalip: version %d", version);
.
1301,1302c
			break;
		case V6:
.
1293c
		switch(version) {
		case V4:
.
1281c
 	version = (memcmp(remote, v4prefix, IPv4off) == 0) ? V4 : V6;
.
## diffname ip/ipifc.c 2002/0615
## diff -e /n/emeliedump/2002/0601/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0615/sys/src/9/ip/ipifc.c
586a
		print("ipifcrem: wrong address\n");
.
576,577c
		if (memcmp(ip, addr, IPaddrlen) == 0
		&& memcmp(mask, lifc->mask, IPaddrlen) == 0) {
.
205c
		if (err = ipifcrem(ifc, av, 3, 0))
			print("ipifcunbind, addr %s, mask %s: %s\n", ip, mask, err);
.
170a
	char *err;
.
## diffname ip/ipifc.c 2002/0710
## diff -e /n/emeliedump/2002/0615/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0710/sys/src/9/ip/ipifc.c
1772c
	long	origint = NOW / 10^3;
.
1735c
		r[j].ltorigin = NOW / 10^3;
.
1208c
#define v6addrcurr(lifc) (( (lifc)->origint + (lifc)->preflt >= (NOW/10^3) ) || ( (lifc)->preflt == 0xffffffff ))
.
962c
	ulong now = NOW;
.
943c
	ulong now = NOW;
.
448c
		lifc->origint = NOW / 10^3;
.
## diffname ip/ipifc.c 2002/0712
## diff -e /n/emeliedump/2002/0710/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0712/sys/src/9/ip/ipifc.c
844d
287a
	Conv *c = x;
.
286c
ipifckick(void *x)
.
## diffname ip/ipifc.c 2002/0717
## diff -e /n/emeliedump/2002/0712/sys/src/9/ip/ipifc.c /n/emeliedump/2002/0717/sys/src/9/ip/ipifc.c
313c
	c->wq = qopen(QMAX, Qkick, ipifckick, c);
.
## diffname ip/ipifc.c 2002/1110
## diff -e /n/emeliedump/2002/0717/sys/src/9/ip/ipifc.c /n/emeliedump/2002/1110/sys/src/9/ip/ipifc.c
312a
	c->sq = qopen(2*QMAX, 0, 0, 0);
.
304,305c
 *  called when a new ipifc structure is created
.
191,193c
	/* close queues to stop queuing of packets */
	qclose(ifc->conv->rq);
	qclose(ifc->conv->wq);
	qclose(ifc->conv->sq);
.
154a
	/* reopen all the queues closed by a previous unbind */
	qreopen(c->rq);
	qreopen(c->eq);
	qreopen(c->sq);

.
152a
	/* any ancillary structures (like routes) no longer pertain */
.
151c
	ifc->rp.routerlt	= 3*(ifc->rp.maxraint);
.
142d
136a

	/* set up parameters */
.
131a

	/* set the bound device name */
.
130a
	/* do medium specific binding */
.
## diffname ip/ipifc.c 2002/1112
## diff -e /n/emeliedump/2002/1110/sys/src/9/ip/ipifc.c /n/emeliedump/2002/1112/sys/src/9/ip/ipifc.c
582c
	 *  for pt to pt we actually specify the remote address as the
.
## diffname ip/ipifc.c 2003/0209
## diff -e /n/emeliedump/2002/1112/sys/src/9/ip/ipifc.c /n/emeliedump/2003/0209/sys/src/9/ip/ipifc.c
396,397c
		if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
			ifc->maxtu = mtu;
.
363c
	ifc->maxtu = mtu;
.
361c
	if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
.
244c
		ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
.
229c
char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt %d pktin %lud pktout %lud errin %lud errout %lud\n";
.
143,144c
	ifc->mintu = ifc->m->mintu;
	ifc->maxtu = ifc->m->maxtu;
.
## diffname ip/ipifc.c 2003/0308
## diff -e /n/emeliedump/2003/0209/sys/src/9/ip/ipifc.c /n/emeliedump/2003/0308/sys/src/9/ip/ipifc.c
1651c
	r = v6lookup(f, v6Unspecified, nil);
.
1427c
	r = v6lookup(f, ip, nil);
.
1294c
	r = v6lookup(f, remote, nil);
.
## diffname ip/ipifc.c 2003/0318
## diff -e /n/emeliedump/2003/0308/sys/src/9/ip/ipifc.c /n/emeliedump/2003/0318/sys/src/9/ip/ipifc.c
311a
	runlock(ifc);
.
307a
	if(!canrlock(ifc)){
		freeb(bp);
		return;
	}
	if(waserror()){
		runlock(ifc);
		nexterror();
	}
.
## diffname ip/ipifc.c 2003/0322
## diff -e /n/emeliedump/2003/0318/sys/src/9/ip/ipifc.c /n/emeliedump/2003/0322/sys/src/9/ip/ipifc.c
320a
	poperror();
.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.