plan 9 kernel history: overview | file list | diff list

1998/0630/ip/tripmedium.c (diff list | history)

ip/tripmedium.c on 1998/0630
1998/0630    
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
#include "../port/error.h" 
 
#include "ip.h" 
#include "trip.h" 
#include "kernel.h" 
 
static void	tripread(void *a); 
static void	tripbind(Ipifc *ifc, int argc, char **argv); 
static void	tripunbind(Ipifc *ifc); 
static void	tripbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip); 
static void	tripaddmulti(Ipifc *ifc, uchar*, uchar*); 
static void	tripremmulti(Ipifc *ifc, uchar*, uchar*); 
static void	tripaddroute(Ipifc *ifc, int, uchar*, uchar*, uchar*, int); 
static void	tripremroute(Ipifc *ifc, int, uchar*, uchar*); 
static void	tripares(Fs*, int, uchar*, uchar*, int, int); 
 
Medium tripmedium = 
{ 
	"trip", 
	0,			/* Header size */ 
 
	20,			/* Min TU */ 
	64*1024,		/* Max TU */ 
 
	LCIMACSIZE,		/* Maximum MAC address length */ 
 
	tripbind, 
	tripunbind, 
	tripbwrite, 
	tripaddmulti, 
	tripremmulti, 
	nil,			/* pktin */ 
	tripaddroute, 
	tripremroute, 
	nil,			/* flushroutes */ 
	nil,			/* joinmulti */ 
	nil,			/* leavemulti */ 
	tripares,		/* address cache enter */ 
 
	0 
}; 
 
typedef struct	Tripinfo Tripinfo; 
struct Tripinfo 
{ 
	Fs*	fs;		/* my instance of the IP stack */ 
	Ipifc*	ifc;		/* IP interface */ 
	Card*	dev; 
	Proc*	readp;		/* reading process */ 
	Chan*	mchan;		/* Data channel */ 
}; 
 
/* 
 *  called to bind an IP ifc to an ethernet device 
 *  called with ifc qlock'd 
 */ 
static void 
tripbind(Ipifc *ifc, int argc, char **argv) 
{ 
	int fd; 
	Chan *mchan; 
	Tripinfo *er; 
 
	if(argc < 2) 
		error(Ebadarg); 
 
	fd = kopen(argv[2], ORDWR); 
	if(fd < 0) 
		error("trip open failed"); 
 
	mchan = fdtochan(up->env->fgrp, fd, ORDWR, 0, 1); 
	kclose(fd); 
 
	if(devtab[mchan->type]->dc != 'T') { 
		cclose(mchan); 
		error(Enoport); 
	} 
 
	er = smalloc(sizeof(*er)); 
	er->mchan = mchan; 
	er->ifc = ifc; 
	er->dev = tripsetifc(mchan, ifc); 
	er->fs = ifc->conv->p->f; 
 
	ifc->arg = er; 
 
	kproc("tripread", tripread, ifc); 
} 
 
/* 
 *  called with ifc qlock'd 
 */ 
static void 
tripunbind(Ipifc *ifc) 
{ 
	Tripinfo *er = ifc->arg; 
/* 
	if(er->readp) 
		postnote(er->readp, 1, "unbind", 0); 
*/ 
	tsleep(&up->sleep, return0, 0, 300); 
 
	if(er->mchan != nil) 
		cclose(er->mchan); 
 
	free(er); 
} 
 
/* 
 *  called by ipoput with a single block to write 
 */ 
static void 
tripbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip) 
{ 
	Tripinfo *er = ifc->arg; 
 
	/* 
	 * Packet is rerouted at linecard 
	 * so the gateway is ignored 
	 */ 
	USED(ip); 
	USED(version); 
 
	if(waserror()) { 
		print("tripwrite failed\n"); 
		return; 
	} 
 
	devtab[er->mchan->type]->bwrite(er->mchan, bp, 0); 
	poperror(); 
	ifc->out++; 
} 
 
/* 
 *  process to read from the trip interface 
 */ 
static void 
tripread(void *a) 
{ 
	Ipifc *ifc; 
	Block *bp; 
	Tripinfo *er; 
 
	ifc = a; 
	er = ifc->arg; 
	er->readp = up;	/* hide identity under a rock for unbind */ 
 
	for(;;) { 
		bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxmtu, 0); 
		ifc->in++; 
		ipiput(er->fs, ifc->lifc->local, bp); 
	} 
 
	pexit("hangup", 1); 
} 
 
static void 
tripaddroute(Ipifc *ifc, int v, uchar *addr, uchar *mask, uchar *gate, int t) 
{ 
	int alen; 
	MTroute mtr; 
	Tripinfo *tinfo; 
 
	tinfo = ifc->arg; 
	if(!tinfo->dev->routing) 
		return; 
 
	/* 
	 * Multicast addresses are handled on the linecard by 
	 * the multicast port driver, so the route load is dumped. 
	 *	loaded by addmulti/remmulti for SBC routes 
	 *		  joinmulti/leavemulti for inter LC 
	 */ 
	if(ipismulticast(addr)) 
		return; 
 
	mtr.type = T_ROUTEADMIN; 
	if(v & Rv4) { 
		mtr.op = RTADD4; 
		alen = IPv4addrlen; 
	} 
	else { 
		mtr.op = RTADD6; 
		alen = IPaddrlen; 
	} 
	mtr.rtype = t; 
	memmove(mtr.addr, addr, alen); 
	memmove(mtr.mask, mask, alen); 
	memmove(mtr.gate, gate, alen); 
 
	i2osend(tinfo->dev, &mtr, sizeof(mtr)); 
} 
 
static void 
tripremroute(Ipifc *ifc, int v, uchar *addr, uchar *mask) 
{ 
	int alen; 
	MTroute mtr; 
	Tripinfo *tinfo; 
 
	tinfo = ifc->arg; 
	if(!tinfo->dev->routing) 
		return; 
 
	if(ipismulticast(addr)) 
		return; 
 
	mtr.type = T_ROUTEADMIN; 
	if(v & Rv4) { 
		mtr.op = RTDEL4; 
		alen = IPv4addrlen; 
	} 
	else { 
		mtr.op = RTDEL6; 
		alen = IPaddrlen; 
	} 
	memmove(mtr.addr, addr, alen); 
	memmove(mtr.mask, mask, alen); 
 
	i2osend(tinfo->dev, &mtr, sizeof(mtr)); 
} 
 
static void 
tripxmitroute(Route *r, Routewalk *rw) 
{ 
	int nifc; 
	char t[5]; 
	uchar a[IPaddrlen], m[IPaddrlen], g[IPaddrlen]; 
 
	convroute(r, a, m, g, t, &nifc); 
	if(!(r->type & Rv4)) { 
		tripaddroute(rw->state, 0, a, m, g, r->type); 
		return; 
	} 
 
	tripaddroute(rw->state, Rv4, a+IPv4off, m+IPv4off, g+IPv4off, r->type); 
} 
 
static void 
sendifcinfo(Ipifc *dest) 
{ 
	Conv **cp, **e; 
	Iplifc *l; 
	Ipifc *ifc; 
	MTifctl mtc; 
	Tripinfo *tinfo, *oinfo; 
	Proto *p; 
 
	tinfo = dest->arg; 
 
	/* Install interfaces */ 
	p = tinfo->fs->ipifc; 
	e = &p->conv[p->nc]; 
	for(cp = p->conv; cp < e; cp++) { 
 
		if(*cp == nil) 
			continue; 
 
		ifc = (Ipifc*)(*cp)->ptcl; 
		if(dest == ifc) 
			continue; 
 
		mtc.type = T_CTLIFADMIN; 
		mtc.maxtu = ifc->maxmtu; 
		mtc.mintu = ifc->minmtu; 
 
		mtc.port = 0; 
		if(ifc->m == &tripmedium) { 
			oinfo = ifc->arg; 
			mtc.port = oinfo->dev->bar[0].bar; 
		} 
 
		for(l = ifc->lifc; l != nil; l = l->next) { 
			if(isv4(l->local)) { 
				mtc.op = IFADD4; 
				memmove(mtc.addr, l->local+IPv4off, IPv4addrlen); 
				memmove(mtc.mask, l->mask+IPv4off, IPv4addrlen); 
			} 
			else { 
				mtc.op = IFADD6; 
				memmove(mtc.addr, l->local, sizeof(mtc.addr)); 
				memmove(mtc.mask, l->mask, sizeof(mtc.mask)); 
			} 
 
			i2osend(tinfo->dev, &mtc, sizeof(mtc)); 
		} 
	} 
} 
 
void 
tripsync(Ipifc *ifc) 
{ 
	Routewalk rw; 
 
	if(ifc == nil) { 
		print("tripsync: interface not bound\n"); 
		return; 
	} 
 
	/* Mirror the route table into the lincard */ 
	rw.o = 0; 
	rw.n = (1<<22); 
	rw.state = ifc; 
	rw.walk = tripxmitroute; 
 
	ipwalkroutes(ifc->conv->p->f, &rw); 
 
	/* 
	 * Tell the linecard about interfaces that already 
	 * exist elsewhere 
	 */ 
	sendifcinfo(ifc); 
} 
 
/* Tell a line card the SBC is interested in listening 
 * to a multicast address 
 */ 
static void 
tripaddmulti(Ipifc *ifc, uchar *addr, uchar *ifca) 
{ 
	MTmultiears mt; 
	Tripinfo *tinfo; 
 
	/* print("tripaddmulti %I %I\n", addr, ifca); /**/ 
 
	tinfo = ifc->arg; 
	if(!tinfo->dev->routing) 
		return; 
 
	mt.type = T_MULTIEAR; 
	mt.op = ADDMULTI; 
	memmove(mt.addr, addr, sizeof(mt.addr)); 
	memmove(mt.ifca, ifca, sizeof(mt.ifca)); 
 
	i2osend(tinfo->dev, &mt, sizeof(mt)); 
} 
 
/* Tell a line card the SBC is no longer interested in listening 
 * to a multicast address 
 */ 
static void 
tripremmulti(Ipifc *ifc, uchar *addr, uchar *ifca) 
{ 
	MTmultiears mt; 
	Tripinfo *tinfo; 
 
	tinfo = ifc->arg; 
	if(!tinfo->dev->routing) 
		return; 
 
	mt.type = T_MULTIEAR; 
	mt.op = REMMULTI; 
	memmove(mt.addr, addr, sizeof(mt.addr)); 
	memmove(mt.ifca, ifca, sizeof(mt.ifca)); 
 
	i2osend(tinfo->dev, &mt, sizeof(mt)); 
} 
 
static void 
tripares(Fs *fs, int vers, uchar *ip, uchar *mac, int l, int) 
{ 
	Route *r; 
	Ipifc *ifc; 
	MTaresenter ta; 
	Tripinfo *tinfo; 
	uchar v6ip[IPaddrlen]; 
 
	if(vers == V4) { 
		r = v4lookup(fs, ip); 
		v4tov6(v6ip, ip); 
		ip = v6ip; 
	} 
	else 
		r = v6lookup(fs, ip); 
 
	if(r == nil) { 
		print("tripares: no route for entry\n"); 
		return; 
	} 
 
	ifc = r->ifc; 
 
	tinfo = ifc->arg; 
	if(!tinfo->dev->routing) 
		return; 
 
	if(vers == V4) { 
		v4tov6(v6ip, ip); 
		ip = v6ip; 
	} 
 
	ta.type = T_ARESENTER; 
	ta.maclen = l; 
	memmove(ta.addr, ip, IPaddrlen); 
	memmove(ta.amac, mac, l); 
 
	i2osend(tinfo->dev, &ta, sizeof(ta)); 
} 
 
void 
tripmediumlink(void) 
{ 
	addipmedium(&tripmedium); 
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)