⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipifc.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h"#include "ip.h"#include "ipv6.h"#define DPRINT if(0)printenum {	Maxmedia	= 32,	Nself		= Maxmedia*5,	NHASH		= (1<<6),	NCACHE		= 256,	QMAX		= 64*1024-1,};Medium *media[Maxmedia] ={	0};/* *  cache of local addresses (addresses we answer to) */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 */};struct Ipselftab{	QLock;	int	inited;	int	acceptall;	/* true if an interface has the null address */	Ipself	*hash[NHASH];	/* hash chains */};/* *  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(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);static void	remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);static char*	ipifcjoinmulti(Ipifc *ifc, char **argv, int argc);static char*	ipifcleavemulti(Ipifc *ifc, char **argv, int argc);static void	ipifcregisterproxy(Fs*, Ipifc*, uchar*);static char*	ipifcremlifc(Ipifc*, Iplifc*);/* *  link in a new medium */voidaddipmedium(Medium *med){	int i;	for(i = 0; i < nelem(media)-1; i++)		if(media[i] == nil){			media[i] = med;			break;		}}/* *  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 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();	}	/* do medium specific binding */	(*m->bind)(ifc, argc, argv);	/* set the bound device name */	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;	/* set up parameters */	ifc->m = m;	ifc->mintu = ifc->m->mintu;	ifc->maxtu = ifc->m->maxtu;	if(ifc->m->unbindonclose == 0)		ifc->conv->inuse++;	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);	/* any ancillary structures (like routes) no longer pertain */	ifc->ifcid++;	/* reopen all the queues closed by a previous unbind */	qreopen(c->rq);	qreopen(c->eq);	qreopen(c->sq);	wunlock(ifc);	poperror();	return nil;}/* *  detach a device from an interface, close the interface *  called with ifc->conv closed */static char*ipifcunbind(Ipifc *ifc){	char *err;	if(waserror()){		wunlock(ifc);		nexterror();	}	wlock(ifc);	/* dissociate routes */	if(ifc->m != nil && ifc->m->unbindonclose == 0)		ifc->conv->inuse--;	ifc->ifcid++;	/* disassociate device */	if(ifc->m != nil && ifc->m->unbind)		(*ifc->m->unbind)(ifc);	memset(ifc->dev, 0, sizeof(ifc->dev));	ifc->arg = nil;	ifc->reassemble = 0;	/* close queues to stop queuing of packets */	qclose(ifc->conv->rq);	qclose(ifc->conv->wq);	qclose(ifc->conv->sq);	/* disassociate logical interfaces */	while(ifc->lifc){		err = ipifcremlifc(ifc, ifc->lifc);		if(err)			error(err);	}	ifc->m = nil;	wunlock(ifc);	poperror();	return nil;}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";char slineformat[] = "	%-40I %-10M %-40I %-12lud %-12lud\n";static intipifcstate(Conv *c, char *state, int n){	Ipifc *ifc;	Iplifc *lifc;	int m;	ifc = (Ipifc*)c->ptcl;	m = snprint(state, n, sfixedformat,		ifc->dev, ifc->maxtu, 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);	rlock(ifc);	for(lifc = ifc->lifc; lifc && n > m; lifc = lifc->next)		m += snprint(state+m, n - m, slineformat,			lifc->local, lifc->mask, lifc->remote,			lifc->validlt, lifc->preflt);	if(ifc->lifc == nil)		m += snprint(state+m, n - m, "\n");	runlock(ifc);	return m;}static intipifclocal(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, "%-40.40I ->", lifc->local);		for(link = lifc->link; link; link = link->lifclink)			m += snprint(state+m, n - m, " %-40.40I", link->self->a);		m += snprint(state+m, n - m, "\n");	}	runlock(ifc);	return m;}static intipifcinuse(Conv *c){	Ipifc *ifc;	ifc = (Ipifc*)c->ptcl;	return ifc->m != nil;}/* *  called when a process writes to an interface's 'data' */static voidipifckick(void *x){	Conv *c = x;	Block *bp;	Ipifc *ifc;	bp = qget(c->wq);	if(bp == nil)		return;	ifc = (Ipifc*)c->ptcl;	if(!canrlock(ifc)){		freeb(bp);		return;	}	if(waserror()){		runlock(ifc);		nexterror();	}	if(ifc->m == nil || ifc->m->pktin == nil)		freeb(bp);	else		(*ifc->m->pktin)(c->p->f, ifc, bp);	runlock(ifc);	poperror();}/* *  called when a new ipifc structure is created */static voidipifccreate(Conv *c){	Ipifc *ifc;	c->rq = qopen(QMAX, 0, 0, 0);	c->sq = qopen(2*QMAX, 0, 0, 0);	c->wq = qopen(QMAX, Qkick, ipifckick, c);	ifc = (Ipifc*)c->ptcl;	ifc->conv = c;	ifc->unbinding = 0;	ifc->m = nil;	ifc->reassemble = 0;}/* *  called after last close of ipifc data or ctl *  called with c locked, we must unlock */static voidipifcclose(Conv *c){	Ipifc *ifc;	Medium *m;	ifc = (Ipifc*)c->ptcl;	m = ifc->m;	if(m != nil && m->unbindonclose)		ipifcunbind(ifc);}/* *  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->mintu || mtu > ifc->m->maxtu)		return Ebadarg;	ifc->maxtu = mtu;	return nil;}/* *  add an address to an interface. */char*ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp){	uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];	uchar bcast[IPaddrlen], net[IPaddrlen];	Iplifc *lifc, **l;	int i, type, mtu;	Fs *f;	int sendnbrdisc = 0;	if(ifc->m == nil)		return "ipifc not yet bound to device";	f = ifc->conv->p->f;	type = Rifc;	memset(ip, 0, IPaddrlen);	memset(mask, 0, IPaddrlen);	memset(rem, 0, IPaddrlen);	switch(argc){	case 6:		if(strcmp(argv[5], "proxy") == 0)			type |= Rproxy;		/* fall through */	case 5:		mtu = strtoul(argv[4], 0, 0);		if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)			ifc->maxtu = 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(isv4(ip))		tentative = 0;	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) {			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;			}			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->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 = NOW / 10^3;	}	lifc->next = nil;	for(l = &ifc->lifc; *l; l = &(*l)->next)		;	*l = lifc;	/* check for point-to-point interface */	if(ipcmp(ip, v6loopback))	/* skip v6 loopback, it's a special address */	if(ipcmp(mask, IPallbits) == 0)		type |= Rptpt;	/* add local routes */	if(isv4(ip))		v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);	else		v6addroute(f, tifc, rem, mask, rem, type);	addselfcache(f, ifc, lifc, ip, Runi);	if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){		ipifcregisterproxy(f, ifc, rem);		goto out;	}	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);		/* 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);		/* 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);		/* 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);			/* add route for all node multicast */			v6addroute(f, tifc, v6allnodesN, v6allnodesNmask, v6allnodesN, Rmulti);		}		/* add all nodes multicast address */		addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);		/* add route for all nodes multicast */		v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL, Rmulti);		/* add solicited-node multicast address */		ipv62smcast(bcast, ip);		addselfcache(f, ifc, lifc, bcast, Rmulti);		sendnbrdisc = 1;	}	/* register the address on this network for address resolution */	if(isv4(ip) && ifc->m->areg != nil)		(*ifc->m->areg)(ifc, ip);out:	wunlock(ifc);	if(tentative && sendnbrdisc)		icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);	return nil;}/* *  remove a logical interface from an ifc *  always called with ifc wlock'd */static char*ipifcremlifc(Ipifc *ifc, Iplifc *lifc){	Iplifc **l;	Fs *f;	f = ifc->conv->p->f;	/*	 *  find address on this interface and remove from chain.	 *  for pt to pt we actually specify the remote address as the	 *  addresss to remove.	 */	for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next)		;	if(*l == nil)		return "address not on this interface";	*l = lifc->next;	/* disassociate any addresses */	while(lifc->link)		remselfcache(f, ifc, lifc, lifc->link->self->a);	/* remove the route for this logical interface */	if(isv4(lifc->local))		v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);	else {		v6delroute(f, lifc->remote, lifc->mask, 1);		if(ipcmp(lifc->local, v6loopback) == 0)			/* remove route for all node multicast */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -