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

📄 devbridge.c

📁 著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是bell实验室开发的Unix后继者。
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/netif.h"#include "../port/error.h"typedef struct Bridge 	Bridge;typedef struct Port 	Port;typedef struct Centry	Centry;typedef struct Iphdr	Iphdr;typedef struct Tcphdr	Tcphdr;enum{	Qtopdir=	1,		/* top level directory */	Qbridgedir,			/* bridge* directory */	Qbctl,	Qstats,	Qcache,	Qlog,	Qportdir,			/* directory for a protocol */	Qpctl,	Qlocal,	Qstatus,	MaxQ,	Maxbridge=	4,	Maxport=	64,		// power of 2	CacheHash=	257,		// prime	CacheLook=	5,		// how many cache entries to examine	CacheSize=	(CacheHash+CacheLook-1),	CacheTimeout=	5*60,		// timeout for cache entry in seconds	TcpMssMax = 1300,			// max desirable Tcp MSS value	TunnelMtu = 1400,};static Dirtab bridgedirtab[]={	"ctl",		{Qbctl},	0,	0666,	"stats",	{Qstats},	0,	0444,	"cache",	{Qcache},	0,	0444,	"log",		{Qlog},		0,	0666,};static Dirtab portdirtab[]={	"ctl",		{Qpctl},	0,	0666,	"local",	{Qlocal},	0,	0444,	"status",	{Qstatus},	0,	0444,};enum {	Logcache=	(1<<0),	Logmcast=	(1<<1),};// types of interfacesenum{	Tether,	Ttun,};static Logflag logflags[] ={	{ "cache",	Logcache, },	{ "multicast",	Logmcast, },	{ nil,		0, },};static Dirtab	*dirtab[MaxQ];#define TYPE(x) 	((x).path & 0xff)#define PORT(x) 	(((x).path >> 8)&(Maxport-1))#define QID(x, y) 	(((x)<<8) | (y))struct Centry{	uchar	d[Eaddrlen];	int	port;	long	expire;		// entry expires this number of seconds after bootime	long	src;	long	dst;};struct Bridge{	QLock;	int	nport;	Port	*port[Maxport];	Centry	cache[CacheSize];	ulong	hit;	ulong	miss;	ulong	copy;	long	delay0;		// constant microsecond delay per packet	long	delayn;		// microsecond delay per byte	int tcpmss;		// modify tcpmss value	Log;};struct Port{	int	id;	Bridge	*bridge;	int	ref;	int	closed;	Chan	*data[2];	// channel to data	int	mcast;		// send multi cast packets	Proc	*readp;		// read proc		// the following uniquely identifies the port	int	type;	char	name[NAMELEN];		// owner hash - avoids bind/unbind races	ulong	ownhash;	// various stats	int	in;		// number of packets read	int	inmulti;	// multicast or broadcast	int	inunknown;	// unknown address	int	out;		// number of packets read	int	outmulti;	// multicast or broadcast	int	outunknown;	// unknown address	int outfrag;	// fragmented the packet	int	nentry;		// number of cache entries for this port};enum {	IP_VER		= 0x40,		/* Using IP version 4 */	IP_HLEN		= 0x05,		/* Header length in characters */	IP_DF		= 0x4000,	/* Don't fragment */	IP_MF		= 0x2000,	/* More fragments */	IP_MAX		= (32*1024),	/* Maximum Internet packet size */	IP_TCPPROTO = 6,	EOLOPT		= 0,	NOOPOPT		= 1,	MSSOPT		= 2,	MSS_LENGTH	= 4,		/* Mean segment size */	SYN		= 0x02,		/* Pkt. is synchronise */	IPHDR		= 20,		/* sizeof(Iphdr) */};struct Iphdr{	uchar	vihl;		/* Version and header length */	uchar	tos;		/* Type of service */	uchar	length[2];	/* packet length */	uchar	id[2];		/* ip->identification */	uchar	frag[2];	/* Fragment information */	uchar	ttl;		/* Time to live */	uchar	proto;		/* Protocol */	uchar	cksum[2];	/* Header checksum */	uchar	src[4];		/* IP source */	uchar	dst[4];		/* IP destination */};struct Tcphdr{	uchar	sport[2];	uchar	dport[2];	uchar	seq[4];	uchar	ack[4];	uchar	flag[2];	uchar	win[2];	uchar	cksum[2];	uchar	urg[2];};static Bridge bridgetab[Maxbridge];static int m2p[] = {	[OREAD]		4,	[OWRITE]	2,	[ORDWR]		6};static int	bridgegen(Chan *c, Dirtab*, int, int s, Dir *dp);static void	portbind(Bridge *b, int argc, char *argv[]);static void	portunbind(Bridge *b, int argc, char *argv[]);static void	etherread(void *a);static char	*cachedump(Bridge *b);static void	portfree(Port *port);static void	cacheflushport(Bridge *b, int port);static void	etherwrite(Port *port, Block *bp);extern ulong	parseip(uchar*, char*);extern ushort	ipcsum(uchar *addr);static voidbridgeinit(void){	int i;	Dirtab *dt;	// setup dirtab with non directory entries	for(i=0; i<nelem(bridgedirtab); i++) {		dt = bridgedirtab + i;		dirtab[TYPE(dt->qid)] = dt;	}	for(i=0; i<nelem(portdirtab); i++) {		dt = portdirtab + i;		dirtab[TYPE(dt->qid)] = dt;	}}static Chan*bridgeattach(char* spec){	Chan *c;	int dev;	dev = atoi(spec);	if(dev<0 || dev >= Maxbridge)		error("bad specification");	c = devattach('B', spec);	c->qid = (Qid){QID(0, Qtopdir)|CHDIR, 0};	c->dev = dev;	return c;}static intbridgewalk(Chan *c, char *name){	return devwalk(c, name, 0, 0, bridgegen);}static voidbridgestat(Chan* c, char* db){	devstat(c, db, nil, 0, bridgegen);}static Chan*bridgeopen(Chan* c, int omode){	int perm;	Bridge *b;	omode &= 3;	perm = m2p[omode];	USED(perm);	b = bridgetab + c->dev;	USED(b);	switch(TYPE(c->qid)) {	default:		break;	case Qlog:		logopen(b);		break;	case Qcache:		c->aux = cachedump(b);		break;	}	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	return c;}static voidbridgeclose(Chan* c){	Bridge *b  = bridgetab + c->dev;	switch(TYPE(c->qid)) {	case Qcache:		if(c->flag & COPEN)			free(c->aux);		break;	case Qlog:		if(c->flag & COPEN)			logclose(b);		break;	}}static longbridgeread(Chan *c, void *a, long n, vlong off){	char buf[256];	Bridge *b = bridgetab + c->dev;	Port *port;	int i, ingood, outgood;	USED(off);	switch(TYPE(c->qid)) {	default:		error(Eperm);	case Qtopdir:	case Qbridgedir:	case Qportdir:		return devdirread(c, a, n, 0, 0, bridgegen);	case Qlog:		return logread(b, a, off, n);	case Qstatus:		qlock(b);		port = b->port[PORT(c->qid)];		if(port == 0)			strcpy(buf, "unbound\n");		else {			i = 0;			switch(port->type) {			default: panic("bridgeread: unknown port type: %d", port->type);			case Tether:				i += snprint(buf+i, sizeof(buf)-i, "ether %s: ", port->name);				break;			case Ttun:				i += snprint(buf+i, sizeof(buf)-i, "tunnel %s: ", port->name);				break;			}			ingood = port->in-port->inmulti-port->inunknown;			outgood = port->out-port->outmulti-port->outunknown;			i += snprint(buf+i, sizeof(buf)-i, "in=%d(%d:%d:%d) out=%d(%d:%d:%d:%d)\n",				port->in, ingood, port->inmulti, port->inunknown,				port->out, outgood, port->outmulti, port->outunknown, port->outfrag);			USED(i);		}		n = readstr(off, a, n, buf);		qunlock(b);		return n;	case Qbctl:		snprint(buf, sizeof(buf), "%s tcpmss\ndelay %ld %ld\n", b->tcpmss ? "set" : "clear",			b->delay0, b->delayn);		n = readstr(off, a, n, buf);		return n;	case Qcache:		n = readstr(off, a, n, c->aux);		return n;	case Qstats:		snprint(buf, sizeof(buf), "hit=%uld miss=%uld copy=%uld\n",			b->hit, b->miss, b->copy);		n = readstr(off, a, n, buf);		return n;	}}static voidbridgeoption(Bridge *b, char *option, int value){	if(strcmp(option, "tcpmss") == 0)		b->tcpmss = value;	else		error("unknown bridge option");}static longbridgewrite(Chan *c, void *a, long n, vlong off){	Bridge *b = bridgetab + c->dev;	Cmdbuf *cb;	char *arg0;	char *p;		USED(off);	switch(TYPE(c->qid)) {	default:		error(Eperm);	case Qbctl:		cb = parsecmd(a, n);		qlock(b);		if(waserror()) {			qunlock(b);			free(cb);			nexterror();		}		if(cb->nf == 0)			error("short write");		arg0 = cb->f[0];		if(strcmp(arg0, "bind") == 0) {			portbind(b, cb->nf-1, cb->f+1);		} else if(strcmp(arg0, "unbind") == 0) {			portunbind(b, cb->nf-1, cb->f+1);		} else if(strcmp(arg0, "cacheflush") == 0) {			log(b, Logcache, "cache flush\n");			memset(b->cache, 0, CacheSize*sizeof(Centry));		} else if(strcmp(arg0, "set") == 0) {			if(cb->nf != 2)				error("usage: set option");			bridgeoption(b, cb->f[1], 1);		} else if(strcmp(arg0, "clear") == 0) {			if(cb->nf != 2)				error("usage: clear option");			bridgeoption(b, cb->f[1], 0);		} else if(strcmp(arg0, "delay") == 0) {			if(cb->nf != 3)				error("usage: delay delay0 delayn");			b->delay0 = strtol(cb->f[1], nil, 10);			b->delayn = strtol(cb->f[2], nil, 10);		} else			error("unknown control request");		poperror();		qunlock(b);		free(cb);		return n;	case Qlog:		cb = parsecmd(a, n);		p = logctl(b, cb->nf, cb->f, logflags);		free(cb);		if(p != nil)			error(p);		return n;	}}static intbridgegen(Chan *c, Dirtab*, int, int s, Dir *dp){	Bridge *b = bridgetab + c->dev;	int type = TYPE(c->qid);	char buf[32];	Dirtab *dt;	Qid qid;	if(s  == DEVDOTDOT){		switch(TYPE(c->qid)){		case Qtopdir:		case Qbridgedir:			snprint(buf, sizeof(buf), "#B%ld", c->dev);			devdir(c, (Qid){CHDIR|Qtopdir, 0}, buf, 0, eve, 0555, dp);			break;		case Qportdir:			sprint(buf, "bridge%ld", c->dev);			devdir(c, (Qid){CHDIR|Qbridgedir, 0}, buf, 0, eve, 0555, dp);			break;		default:			panic("bridgewalk %lux", c->qid.path);		}		return 1;	}	switch(type) {	default:		// non directory entries end up here		if(c->qid.path & CHDIR)			panic("bridgegen: unexpected directory");			if(s != 0)			return -1;		dt = dirtab[TYPE(c->qid)];		if(dt == nil)			panic("bridgegen: unknown type: %d", TYPE(c->qid));		devdir(c, c->qid, dt->name, dt->length, eve, dt->perm, dp);		return 1;	case Qtopdir:		if(s != 0)			return -1;		sprint(buf, "bridge%ld", c->dev);		devdir(c, (Qid){QID(0,Qbridgedir)|CHDIR,0}, buf, 0, eve, 0555, dp);		return 1;	case Qbridgedir:		if(s<nelem(bridgedirtab)) {			dt = bridgedirtab+s;			devdir(c, dt->qid, dt->name, dt->length, eve, dt->perm, dp);			return 1;		}		s -= nelem(bridgedirtab);		if(s >= b->nport)			return -1;		qid = (Qid){QID(s,Qportdir)|CHDIR, 0};		snprint(buf, sizeof(buf), "%d", s);		devdir(c, qid, buf, 0, eve, 0555, dp);		return 1;	case Qportdir:		if(s>=nelem(portdirtab))			return -1;		dt = portdirtab+s;		qid = (Qid){QID(PORT(c->qid),TYPE(dt->qid)),0};		devdir(c, qid, dt->name, dt->length, eve, dt->perm, dp);		return 1;	}}// also in netif.cstatic intparseaddr(uchar *to, char *from, int alen){	char nip[4];	char *p;	int i;	p = from;	for(i = 0; i < alen; i++){		if(*p == 0)			return -1;		nip[0] = *p++;		if(*p == 0)			return -1;		nip[1] = *p++;		nip[2] = 0;		to[i] = strtoul(nip, 0, 16);		if(*p == ':')			p++;	}	return 0;}// assumes b is lockedstatic voidportbind(Bridge *b, int argc, char *argv[]){	Port *port;	char path[8*NAMELEN];	char buf[100];	char *dev, *dev2=nil, *p;	Chan *ctl;	int type=0, i, n;	char *usage = "usage: bind ether|tunnel name ownhash dev [dev2]";	char name[NAMELEN];	ulong ownhash;	memset(name, 0, NAMELEN);	if(argc < 4)		error(usage);	if(strcmp(argv[0], "ether") == 0) {		if(argc != 4)			error(usage);		type = Tether;		strncpy(name, argv[1], NAMELEN);		name[NAMELEN-1] = 0;//		parseaddr(addr, argv[1], Eaddrlen);	} else if(strcmp(argv[0], "tunnel") == 0) {		if(argc != 5)			error(usage);		type = Ttun;		strncpy(name, argv[1], NAMELEN);		name[NAMELEN-1] = 0;//		parseip(addr, argv[1]);		dev2 = argv[4];	} else		error(usage);	ownhash = atoi(argv[2]);	dev = argv[3];	for(i=0; i<b->nport; i++) {		port = b->port[i];		if(port != nil)		if(port->type == type)		if(memcmp(port->name, name, NAMELEN) == 0)			error("port in use");	}	for(i=0; i<Maxport; i++)		if(b->port[i] == nil)			break;	if(i == Maxport)		error("no more ports");	port = smalloc(sizeof(Port));	port->ref = 1;	port->id = i;	port->ownhash = ownhash;	if(waserror()) {		portfree(port);		nexterror();	}	port->type = type;	memmove(port->name, name, NAMELEN);	switch(port->type) {	default: panic("portbind: unknown port type: %d", type);	case Tether:		snprint(path, sizeof(path), "%s/clone", dev);		ctl = namec(path, Aopen, ORDWR, 0);		if(waserror()) {			cclose(ctl);			nexterror();		}		// check addr?		// get directory name		n = devtab[ctl->type]->read(ctl, buf, sizeof(buf), 0);		buf[n] = 0;		for(p = buf; *p == ' '; p++)			;		snprint(path, sizeof(path), "%s/%lud/data", dev, strtoul(p, 0, 0));		// setup connection to be promiscuous		snprint(buf, sizeof(buf), "connect -1");		devtab[ctl->type]->write(ctl, buf, strlen(buf), 0);		snprint(buf, sizeof(buf), "promiscuous");		devtab[ctl->type]->write(ctl, buf, strlen(buf), 0);		snprint(buf, sizeof(buf), "bridge");		devtab[ctl->type]->write(ctl, buf, strlen(buf), 0);		// open data port		port->data[0] = namec(path, Aopen, ORDWR, 0);		// dup it		incref(port->data[0]);		port->data[1] = port->data[0];		poperror();		cclose(ctl);				break;

⌨️ 快捷键说明

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