398 lines · 7.0 KB · C
RawDownload
#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" 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 ={.name=		"trip",.mintu=	20,.maxtu=	64*1024,.maclen=	LCIMACSIZE,.bind=		tripbind,.unbind=	tripunbind,.bwrite=	tripbwrite,.addmulti=	tripaddmulti,.remmulti=	tripremmulti,.addroute=	tripaddroute,.remroute=	tripremroute,.ares=		tripares,}; 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 voidtripbind(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 voidtripunbind(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 voidtripbwrite(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 voidtripread(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->maxtu, 0);		ifc->in++;		ipiput4(er->fs, ifc, bp);	} 	pexit("hangup", 1);} static voidtripaddroute(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 voidtripremroute(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 voidtripxmitroute(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 voidsendifcinfo(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->maxtu;		mtc.mintu = ifc->mintu; 		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));		}	}} voidtripsync(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 voidtripaddmulti(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 voidtripremmulti(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 voidtripares(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));} voidtripmediumlink(void){	addipmedium(&tripmedium);}