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

1999/0930/port/devbridge.c (diff list | history)

1999/0316/sys/src/9/port/devbridge.c:513,5181999/0625/sys/src/9/port/devbridge.c:513,520 (short | long)
1999/0316    
		devtab[ctl->type]->write(ctl, buf, strlen(buf), 0); 
		snprint(buf, sizeof(buf), "promiscuous"); 
		devtab[ctl->type]->write(ctl, buf, strlen(buf), 0); 
1999/0625    
		snprint(buf, sizeof(buf), "bridge"); 
		devtab[ctl->type]->write(ctl, buf, strlen(buf), 0); 
1999/0316    
 
		// open data port 
		port->data[0] = namec(path, Aopen, ORDWR, 0); 
1999/0625/sys/src/9/port/devbridge.c:179,1861999/0630/sys/src/9/port/devbridge.c:179,184 (short | long)
1999/0316    
static int 
bridgewalk(Chan *c, char *name) 
{ 
	Path *op; 
                 
	if(strcmp(name, "..") == 0){ 
		switch(TYPE(c->qid)){ 
		case Qtopdir: 
1999/0625/sys/src/9/port/devbridge.c:193,2011999/0630/sys/src/9/port/devbridge.c:191,196
1999/0316    
		default: 
			panic("bridgewalk %lux", c->qid.path); 
		} 
		op = c->path; 
		c->path = ptenter(&syspt, op, name); 
		decref(op); 
		return 1; 
	} 
 
1999/0630/sys/src/9/port/devbridge.c:266,2721999/0731/sys/src/9/port/devbridge.c:266,272 (short | long)
1999/0316    
	char buf[256]; 
	Bridge *b = bridgetab + c->dev; 
	Port *port; 
	int i; 
1999/0731    
	int i, ingood, outgood; 
1999/0316    
 
	USED(off); 
	switch(TYPE(c->qid)) { 
1999/0630/sys/src/9/port/devbridge.c:294,3021999/0731/sys/src/9/port/devbridge.c:294,304
1999/0316    
				i += snprint(buf+i, sizeof(buf)-i, "tunnel %I: ", port->addr); 
				break; 
			} 
			i += snprint(buf+i, sizeof(buf)-i, "in=%d/%d/%d out=%d/%d/%d\n", 
				port->in, port->inmulti, port->inunknown, 
				port->out, port->outmulti, port->outunknown); 
1999/0731    
			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)\n", 
				port->in, ingood, port->inmulti, port->inunknown, 
				port->out, outgood, port->outmulti, port->outunknown); 
1999/0316    
			USED(i); 
		} 
		n = readstr(off, a, n, buf); 
1999/0630/sys/src/9/port/devbridge.c:317,3231999/0731/sys/src/9/port/devbridge.c:319,324
1999/0316    
	char *p; 
	 
	USED(off); 
                 
	switch(TYPE(c->qid)) { 
	default: 
		error(Eperm); 
1999/0630/sys/src/9/port/devbridge.c:482,4881999/0731/sys/src/9/port/devbridge.c:483,488
1999/0316    
		portfree(port); 
		nexterror(); 
	} 
                 
	port->type = type; 
	memmove(port->addr, addr, Addrlen); 
	switch(port->type) { 
1999/0630/sys/src/9/port/devbridge.c:822,8281999/0731/sys/src/9/port/devbridge.c:822,827
1999/0316    
		if(waserror()) { 
			if(bp) 
				freeb(bp); 
print("devbridge: etherread: %r\n"); 
			continue; 
		} 
		if(blocklen(bp) < ETHERMINTU) 
1999/0731/sys/src/9/port/devbridge.c:799,8051999/0803/sys/src/9/port/devbridge.c:799,805 (short | long)
1999/0316    
	Block *bp, *bp2; 
	Etherpkt *ep; 
	Centry *ce; 
                 
1999/0803    
static uchar tribble[Eaddrlen] = {0x00, 0xd1, 0x80, 0xaa, 0xbb, 0x07}; 
1999/0316    
	 
	qlock(b); 
	port->readp = up;	/* hide identity under a rock for unbind */ 
1999/0731/sys/src/9/port/devbridge.c:841,8481999/0803/sys/src/9/port/devbridge.c:841,850
1999/0316    
			if(ce == nil) { 
				b->miss++; 
				port->inunknown++; 
				bp2 = bp; bp = nil; 
				ethermultiwrite(b, bp2, port); 
1999/0803    
				if(port->type != Tether || memcmp(ep->s, tribble, Eaddrlen) == 0) { 
					bp2 = bp; bp = nil; 
					ethermultiwrite(b, bp2, port); 
				}	 
1999/0316    
			} else if (ce->port != port->id) { 
				b->hit++; 
				bp2 = bp; bp = nil; 
1999/0803/sys/src/9/port/devbridge.c:59,651999/0807/sys/src/9/port/devbridge.c:59,65 (short | long)
1999/0316    
enum 
{ 
	Tether, 
	Ttunnel, 
1999/0807    
	Ttun, 
1999/0316    
}; 
 
static Logflag logflags[] = 
1999/0803/sys/src/9/port/devbridge.c:290,2961999/0807/sys/src/9/port/devbridge.c:290,296
1999/0316    
			case Tether: 
				i += snprint(buf+i, sizeof(buf)-i, "ether %E: ", port->addr); 
				break; 
			case Ttunnel: 
1999/0807    
			case Ttun: 
1999/0316    
				i += snprint(buf+i, sizeof(buf)-i, "tunnel %I: ", port->addr); 
				break; 
			} 
1999/0803/sys/src/9/port/devbridge.c:455,4611999/0807/sys/src/9/port/devbridge.c:455,461
1999/0316    
	} else if(strcmp(argv[0], "tunnel") == 0) { 
		if(argc != 5) 
			error(usage); 
		type = Ttunnel; 
1999/0807    
		type = Ttun; 
1999/0316    
		parseip(addr, argv[1]); 
		dev2 = argv[4]; 
	} else 
1999/0803/sys/src/9/port/devbridge.c:521,5271999/0807/sys/src/9/port/devbridge.c:521,527
1999/0316    
		cclose(ctl);		 
 
		break; 
	case Ttunnel: 
1999/0807    
	case Ttun: 
1999/0316    
		port->data[0] = namec(dev, Aopen, OREAD, 0); 
		port->data[1] = namec(dev2, Aopen, OWRITE, 0); 
		break; 
1999/0803/sys/src/9/port/devbridge.c:557,5631999/0807/sys/src/9/port/devbridge.c:557,563
1999/0316    
		type = Tether; 
		parseaddr(addr, argv[1], Eaddrlen); 
	} else if(strcmp(argv[0], "tunnel") == 0) { 
		type = Ttunnel; 
1999/0807    
		type = Ttun; 
1999/0316    
		parseip(addr, argv[1]); 
	} else 
		error(usage); 
1999/0803/sys/src/9/port/devbridge.c:841,8471999/0807/sys/src/9/port/devbridge.c:841,847
1999/0316    
			if(ce == nil) { 
				b->miss++; 
				port->inunknown++; 
1999/0803    
				if(port->type != Tether || memcmp(ep->s, tribble, Eaddrlen) == 0) { 
1999/0807    
				if(1 || port->type != Tether || memcmp(ep->s, tribble, Eaddrlen) == 0) { 
1999/0803    
					bp2 = bp; bp = nil; 
					ethermultiwrite(b, bp2, port); 
				}	 
1999/0807/sys/src/9/port/devbridge.c:37,431999/0824/sys/src/9/port/devbridge.c:37,43 (short | long)
1999/0316    
	Addrlen=	16,		// must be long enough of IP addr and ether addr 
}; 
 
Dirtab bridgedirtab[]={ 
1999/0824    
static Dirtab bridgedirtab[]={ 
1999/0316    
	"ctl",		{Qbctl},	0,	0666, 
	"stats",	{Qstats},	0,	0444, 
	"cache",	{Qcache},	0,	0444, 
1999/0807/sys/src/9/port/devbridge.c:44,501999/0824/sys/src/9/port/devbridge.c:44,50
1999/0316    
	"log",		{Qlog},		0,	0666, 
}; 
 
Dirtab portdirtab[]={ 
1999/0824    
static Dirtab portdirtab[]={ 
1999/0316    
	"ctl",		{Qpctl},	0,	0666, 
	"local",	{Qlocal},	0,	0444, 
	"status",	{Qstatus},	0,	0444, 
1999/0824/sys/src/9/port/devbridge.c:9,141999/0826/sys/src/9/port/devbridge.c:9,16 (short | long)
1999/0316    
typedef struct Bridge 	Bridge; 
typedef struct Port 	Port; 
typedef struct Centry	Centry; 
1999/0826    
typedef struct Iphdr	Iphdr; 
typedef struct Tcphdr	Tcphdr; 
1999/0316    
 
enum 
{ 
1999/0824/sys/src/9/port/devbridge.c:34,391999/0826/sys/src/9/port/devbridge.c:36,43
1999/0316    
	CacheSize=	(CacheHash+CacheLook-1), 
	CacheTimeout=	5*60,		// timeout for cache entry in seconds 
 
1999/0826    
	TcpMssMax = 1400,			// max desirable Tcp MSS value 
 
1999/0316    
	Addrlen=	16,		// must be long enough of IP addr and ether addr 
}; 
 
1999/0824/sys/src/9/port/devbridge.c:92,971999/0826/sys/src/9/port/devbridge.c:96,102
1999/0316    
	Centry	cache[CacheSize]; 
	int	hit; 
	int	miss; 
1999/0826    
	int tcpmss;		// modify tcpmss value 
1999/0316    
 
	Log; 
}; 
1999/0824/sys/src/9/port/devbridge.c:106,1111999/0826/sys/src/9/port/devbridge.c:111,117
1999/0316    
	Chan	*data[2];	// channel to data 
 
	int	mcast;		// send multi cast packets 
1999/0826    
 
1999/0316    
	Proc	*readp;		// read proc 
	 
	// the following uniquely identifies the port 
1999/0824/sys/src/9/port/devbridge.c:125,1301999/0826/sys/src/9/port/devbridge.c:131,173
1999/0316    
	int	nentry;		// number of cache entries for this port 
}; 
 
1999/0826    
enum { 
	IP_VER		= 0x40,		/* Using IP version 4 */ 
	IP_HLEN		= 0x05,		/* Header length in characters */ 
	IP_TCPPROTO = 6, 
	MSSOPT		= 2, 
	MSS_LENGTH	= 4,		/* Mean segment size */ 
}; 
 
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]; 
	/* Options segment */ 
	uchar	opt[2]; 
	uchar	mss[2]; 
}; 
 
1999/0316    
static Bridge bridgetab[Maxbridge]; 
 
static int m2p[] = { 
1999/0824/sys/src/9/port/devbridge.c:310,3151999/0826/sys/src/9/port/devbridge.c:353,368
1999/0316    
	} 
} 
 
1999/0826    
static void 
bridgeoption(Bridge *b, char *option, int value) 
{ 
	if(strcmp(option, "tcpmss") == 0) 
		b->tcpmss = value; 
	else 
		error("unknown bridge option"); 
} 
 
 
1999/0316    
static long 
bridgewrite(Chan *c, void *a, long n, vlong off) 
{ 
1999/0824/sys/src/9/port/devbridge.c:333,3451999/0826/sys/src/9/port/devbridge.c:386,406
1999/0316    
		if(cb->nf == 0) 
			error("short write"); 
		arg0 = cb->f[0]; 
		if(strcmp(arg0, "bind") == 0) 
1999/0826    
		if(strcmp(arg0, "bind") == 0) { 
1999/0316    
			portbind(b, cb->nf-1, cb->f+1); 
		else if(strcmp(arg0, "unbind") == 0) 
1999/0826    
		} else if(strcmp(arg0, "unbind") == 0) { 
1999/0316    
			portunbind(b, cb->nf-1, cb->f+1); 
		else if(strcmp(arg0, "cacheflush") == 0) { 
1999/0826    
		} else if(strcmp(arg0, "cacheflush") == 0) { 
1999/0316    
			log(b, Logcache, "cache flush\n"); 
			memset(b->cache, 0, CacheSize*sizeof(Centry)); 
1999/0826    
		} 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); 
1999/0316    
		} else 
			error("unknown control request"); 
		poperror(); 
1999/0824/sys/src/9/port/devbridge.c:788,7931999/0826/sys/src/9/port/devbridge.c:849,904
1999/0316    
	poperror(); 
} 
 
1999/0826    
static void 
tcpmsshack(Block *bp) 
{ 
	int n = BLEN(bp); 
	int hl; 
	Etherpkt *epkt; 
	Iphdr *iphdr; 
	Tcphdr *tcphdr; 
 
	epkt = (Etherpkt*)bp->rp; 
	// check it is an ip packet 
	if(nhgets(epkt->type) != 0x800) 
		return; 
print("tcpmsshack is IP\n"); 
	iphdr = (Iphdr*)(bp->rp + ETHERHDRSIZE); 
	n -= ETHERHDRSIZE; 
	if(n < sizeof(Iphdr)) 
		return; 
 
	// check it is ok IP packet 
	if(iphdr->vihl != (IP_VER|IP_HLEN)) { 
		hl = (iphdr->vihl&0xF)<<2; 
		if((iphdr->vihl&0xF0) != IP_VER || hl < (IP_HLEN<<2)) 
			return; 
	} else { 
		hl = IP_HLEN<<2; 
	} 
print("tcpmsshack is ok IP\n"); 
 
	// check TCP 
	if(iphdr->proto != IP_TCPPROTO) 
		return; 
print("tcpmsshack is TCP\n"); 
	tcphdr = (Tcphdr*)((uchar*)(iphdr) + hl); 
	n -= hl; 
	if(n < sizeof(Tcphdr)) 
		return; 
	hl = (tcphdr->flag[0] & 0xf0)>>2; 
	if(hl < sizeof(Tcphdr)) 
		return; 
print("tcpmsshack is big enough\n"); 
	// check for MSS option 
	// for the momment, assume MSS is the first option 
	// we could do better, but since options are not aligned, 
	// this would make the checksum correction code tougher 
	if(tcphdr->opt[0] != MSSOPT || tcphdr->opt[1] != MSS_LENGTH) 
			return; 
print("got mss = %d\n", nhgets(tcphdr->mss)); 
} 
 
1999/0316    
/* 
 *  process to read from the ethernet 
 */ 
1999/0824/sys/src/9/port/devbridge.c:799,8051999/0826/sys/src/9/port/devbridge.c:910,915
1999/0316    
	Block *bp, *bp2; 
	Etherpkt *ep; 
	Centry *ce; 
1999/0803    
static uchar tribble[Eaddrlen] = {0x00, 0xd1, 0x80, 0xaa, 0xbb, 0x07}; 
1999/0316    
	 
	qlock(b); 
	port->readp = up;	/* hide identity under a rock for unbind */ 
1999/0824/sys/src/9/port/devbridge.c:811,8191999/0826/sys/src/9/port/devbridge.c:921,929
1999/0316    
			qlock(b); 
			break; 
		} 
//print("devbridge: etherread: reading\n"); 
1999/0826    
if(0)print("devbridge: etherread: reading\n"); 
1999/0316    
		bp = devtab[port->data[0]->type]->bread(port->data[0], ETHERMAXTU, 0); 
//print("devbridge: etherread: blocklen = %d\n", blocklen(bp)); 
1999/0826    
if(0)print("devbridge: etherread: blocklen = %d\n", blocklen(bp)); 
1999/0316    
		poperror(); 
		qlock(b); 
 
1999/0824/sys/src/9/port/devbridge.c:841,8521999/0826/sys/src/9/port/devbridge.c:951,964
1999/0316    
			if(ce == nil) { 
				b->miss++; 
				port->inunknown++; 
1999/0807    
				if(1 || port->type != Tether || memcmp(ep->s, tribble, Eaddrlen) == 0) { 
1999/0803    
					bp2 = bp; bp = nil; 
					ethermultiwrite(b, bp2, port); 
				}	 
1999/0826    
				if(b->tcpmss) 
					tcpmsshack(bp); 
				bp2 = bp; bp = nil; 
				ethermultiwrite(b, bp2, port); 
1999/0316    
			} else if (ce->port != port->id) { 
				b->hit++; 
1999/0826    
				if(b->tcpmss) 
					tcpmsshack(bp); 
1999/0316    
				bp2 = bp; bp = nil; 
				oport = b->port[ce->port]; 
				oport->out++; 
1999/0826/sys/src/9/port/devbridge.c:135,1421999/0827/sys/src/9/port/devbridge.c:135,145 (short | long)
1999/0826    
	IP_VER		= 0x40,		/* Using IP version 4 */ 
	IP_HLEN		= 0x05,		/* Header length in characters */ 
	IP_TCPPROTO = 6, 
1999/0827    
	EOLOPT		= 0, 
	NOOPOPT		= 1, 
1999/0826    
	MSSOPT		= 2, 
	MSS_LENGTH	= 4,		/* Mean segment size */ 
1999/0827    
	SYN		= 0x02,		/* Pkt. is synchronise */ 
1999/0826    
}; 
 
struct Iphdr 
1999/0826/sys/src/9/port/devbridge.c:163,1711999/0827/sys/src/9/port/devbridge.c:166,171
1999/0826    
	uchar	win[2]; 
	uchar	cksum[2]; 
	uchar	urg[2]; 
	/* Options segment */ 
	uchar	opt[2]; 
	uchar	mss[2]; 
}; 
 
1999/0316    
static Bridge bridgetab[Maxbridge]; 
1999/0826/sys/src/9/port/devbridge.c:850,8691999/0827/sys/src/9/port/devbridge.c:850,869
1999/0316    
} 
 
1999/0826    
static void 
tcpmsshack(Block *bp) 
1999/0827    
tcpmsshack(Etherpkt *epkt, int n) 
1999/0826    
{ 
	int n = BLEN(bp); 
	int hl; 
	Etherpkt *epkt; 
	Iphdr *iphdr; 
	Tcphdr *tcphdr; 
1999/0827    
	ulong mss; 
	ulong cksum; 
	int optlen; 
	uchar *optr; 
1999/0826    
 
	epkt = (Etherpkt*)bp->rp; 
	// check it is an ip packet 
	if(nhgets(epkt->type) != 0x800) 
		return; 
print("tcpmsshack is IP\n"); 
	iphdr = (Iphdr*)(bp->rp + ETHERHDRSIZE); 
1999/0827    
	iphdr = (Iphdr*)(epkt->data); 
1999/0826    
	n -= ETHERHDRSIZE; 
	if(n < sizeof(Iphdr)) 
		return; 
1999/0826/sys/src/9/port/devbridge.c:873,9021999/0827/sys/src/9/port/devbridge.c:873,937
1999/0826    
		hl = (iphdr->vihl&0xF)<<2; 
		if((iphdr->vihl&0xF0) != IP_VER || hl < (IP_HLEN<<2)) 
			return; 
	} else { 
1999/0827    
	} else 
1999/0826    
		hl = IP_HLEN<<2; 
	} 
print("tcpmsshack is ok IP\n"); 
 
	// check TCP 
	if(iphdr->proto != IP_TCPPROTO) 
		return; 
print("tcpmsshack is TCP\n"); 
	tcphdr = (Tcphdr*)((uchar*)(iphdr) + hl); 
	n -= hl; 
	if(n < sizeof(Tcphdr)) 
		return; 
1999/0827    
	tcphdr = (Tcphdr*)((uchar*)(iphdr) + hl); 
	// MSS can only appear in SYN packet 
	if(!(tcphdr->flag[1] & SYN)) 
		return; 
1999/0826    
	hl = (tcphdr->flag[0] & 0xf0)>>2; 
	if(hl < sizeof(Tcphdr)) 
1999/0827    
	if(n < hl) 
1999/0826    
		return; 
print("tcpmsshack is big enough\n"); 
1999/0827    
 
1999/0826    
	// check for MSS option 
	// for the momment, assume MSS is the first option 
	// we could do better, but since options are not aligned, 
	// this would make the checksum correction code tougher 
	if(tcphdr->opt[0] != MSSOPT || tcphdr->opt[1] != MSS_LENGTH) 
1999/0827    
	optr = (uchar*)(tcphdr) + sizeof(Tcphdr); 
	n = hl - sizeof(Tcphdr); 
	for(;;) { 
		if(n <= 0 || *optr == EOLOPT) 
1999/0826    
			return; 
print("got mss = %d\n", nhgets(tcphdr->mss)); 
1999/0827    
		if(*optr == NOOPOPT) { 
			n--; 
			optr++; 
			continue; 
		} 
		optlen = optr[1]; 
		if(optlen < 2 || optlen > n) 
			return; 
		if(*optr == MSSOPT && optlen == MSS_LENGTH) 
			break; 
		n -= optlen; 
		optr += optlen; 
	} 
 
	mss = nhgets(optr+2); 
	if(mss <= TcpMssMax) 
		return; 
	// fit checksum 
	cksum = nhgets(tcphdr->cksum); 
	if(optr-(uchar*)tcphdr & 1) { 
print("tcpmsshack: odd alignment!\n"); 
		// odd alignments are a pain 
		cksum += nhgets(optr+1); 
		cksum -= (optr[1]<<8)|(TcpMssMax>>8); 
		cksum += (cksum>>16); 
		cksum &= 0xffff; 
		cksum += nhgets(optr+3); 
		cksum -= ((TcpMssMax&0xff)<<8)|optr[4]; 
		cksum += (cksum>>16); 
	} else { 
		cksum += mss; 
		cksum -= TcpMssMax; 
		cksum += (cksum>>16); 
	} 
	hnputs(tcphdr->cksum, cksum); 
	hnputs(optr+2, TcpMssMax); 
1999/0826    
} 
 
1999/0316    
/* 
1999/0826/sys/src/9/port/devbridge.c:937,9441999/0827/sys/src/9/port/devbridge.c:972,982
1999/0316    
		if(blocklen(bp) < ETHERMINTU) 
			error("short packet"); 
		port->in++; 
1999/0827    
 
1999/0316    
		ep = (Etherpkt*)bp->rp; 
		cacheupdate(b, ep->s, port->id); 
1999/0827    
		if(b->tcpmss) 
			tcpmsshack(ep, BLEN(bp)); 
1999/0316    
 
		if(ep->d[0] & 1) { 
			log(b, Logmcast, "mulitcast: port=%d src=%E dst=%E type=%#.4ux\n", 
1999/0826/sys/src/9/port/devbridge.c:951,9641999/0827/sys/src/9/port/devbridge.c:989,998
1999/0316    
			if(ce == nil) { 
				b->miss++; 
				port->inunknown++; 
1999/0826    
				if(b->tcpmss) 
					tcpmsshack(bp); 
				bp2 = bp; bp = nil; 
				ethermultiwrite(b, bp2, port); 
1999/0316    
			} else if (ce->port != port->id) { 
				b->hit++; 
1999/0826    
				if(b->tcpmss) 
					tcpmsshack(bp); 
1999/0316    
				bp2 = bp; bp = nil; 
				oport = b->port[ce->port]; 
				oport->out++; 
1999/0827/sys/src/9/port/devbridge.c:94,1011999/0901/sys/src/9/port/devbridge.c:94,102 (short | long)
1999/0316    
	int	nport; 
	Port	*port[Maxport]; 
	Centry	cache[CacheSize]; 
	int	hit; 
	int	miss; 
1999/0901    
	ulong	hit; 
	ulong	miss; 
	ulong copy; 
1999/0826    
	int tcpmss;		// modify tcpmss value 
1999/0316    
 
	Log; 
1999/0827/sys/src/9/port/devbridge.c:350,3551999/0901/sys/src/9/port/devbridge.c:351,361
1999/0316    
	case Qcache: 
		n = readstr(off, a, n, c->aux); 
		return n; 
1999/0901    
	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; 
1999/0316    
	} 
} 
 
1999/0827/sys/src/9/port/devbridge.c:832,8381999/0901/sys/src/9/port/devbridge.c:838,844
1999/0316    
 
		// delay one so that the last write does not copy 
		if(c != nil) { 
			// can not use write since it changes scr addr 
1999/0901    
			b->copy++; 
1999/0316    
			bp2 = copyblock(bp, blocklen(bp)); 
			devtab[c->type]->bwrite(c, bp2, 0); 
		} 
1999/0901/sys/src/9/port/devbridge.c:38,441999/0914/sys/src/9/port/devbridge.c:38,43 (short | long)
1999/0316    
 
1999/0826    
	TcpMssMax = 1400,			// max desirable Tcp MSS value 
 
1999/0316    
	Addrlen=	16,		// must be long enough of IP addr and ether addr 
}; 
 
1999/0824    
static Dirtab bridgedirtab[]={ 
1999/0901/sys/src/9/port/devbridge.c:117,1231999/0914/sys/src/9/port/devbridge.c:116,122
1999/0316    
	 
	// the following uniquely identifies the port 
	int	type; 
	uchar	addr[Addrlen]; 
1999/0914    
	char	name[NAMELEN]; 
1999/0316    
	 
	// owner hash - avoids bind/unbind races 
	ulong	ownhash; 
1999/0901/sys/src/9/port/devbridge.c:332,3411999/0914/sys/src/9/port/devbridge.c:331,340
1999/0316    
			switch(port->type) { 
			default: panic("bridgeread: unknown port type: %d", port->type); 
			case Tether: 
				i += snprint(buf+i, sizeof(buf)-i, "ether %E: ", port->addr); 
1999/0914    
				i += snprint(buf+i, sizeof(buf)-i, "ether %s: ", port->name); 
1999/0316    
				break; 
1999/0807    
			case Ttun: 
1999/0316    
				i += snprint(buf+i, sizeof(buf)-i, "tunnel %I: ", port->addr); 
1999/0914    
				i += snprint(buf+i, sizeof(buf)-i, "tunnel %s: ", port->name); 
1999/0316    
				break; 
			} 
1999/0731    
			ingood = port->in-port->inmulti-port->inunknown; 
1999/0901/sys/src/9/port/devbridge.c:507,5171999/0914/sys/src/9/port/devbridge.c:506,516
1999/0316    
	char *dev, *dev2=nil, *p; 
	Chan *ctl; 
	int type=0, i, n; 
	char *usage = "usage: bind ether|tunnel addr ownhash dev [dev2]"; 
	uchar addr[Addrlen]; 
1999/0914    
	char *usage = "usage: bind ether|tunnel name ownhash dev [dev2]"; 
	char name[NAMELEN]; 
1999/0316    
	ulong ownhash; 
 
	memset(addr, 0, Addrlen); 
1999/0914    
	memset(name, 0, NAMELEN); 
1999/0316    
	if(argc < 4) 
		error(usage); 
	if(strcmp(argv[0], "ether") == 0) { 
1999/0901/sys/src/9/port/devbridge.c:518,5291999/0914/sys/src/9/port/devbridge.c:517,532
1999/0316    
		if(argc != 4) 
			error(usage); 
		type = Tether; 
		parseaddr(addr, argv[1], Eaddrlen); 
1999/0914    
		strncpy(name, argv[1], NAMELEN); 
		name[NAMELEN-1] = 0; 
//		parseaddr(addr, argv[1], Eaddrlen); 
1999/0316    
	} else if(strcmp(argv[0], "tunnel") == 0) { 
		if(argc != 5) 
			error(usage); 
1999/0807    
		type = Ttun; 
1999/0316    
		parseip(addr, argv[1]); 
1999/0914    
		strncpy(name, argv[1], NAMELEN); 
		name[NAMELEN-1] = 0; 
//		parseip(addr, argv[1]); 
1999/0316    
		dev2 = argv[4]; 
	} else 
		error(usage); 
1999/0901/sys/src/9/port/devbridge.c:533,5391999/0914/sys/src/9/port/devbridge.c:536,542
1999/0316    
		port = b->port[i]; 
		if(port != nil) 
		if(port->type == type) 
		if(memcmp(port->addr, addr, Addrlen) == 0) 
1999/0914    
		if(memcmp(port->name, name, NAMELEN) == 0) 
1999/0316    
			error("port in use"); 
	} 
	for(i=0; i<Maxport; i++) 
1999/0901/sys/src/9/port/devbridge.c:551,5571999/0914/sys/src/9/port/devbridge.c:554,560
1999/0316    
		nexterror(); 
	} 
	port->type = type; 
	memmove(port->addr, addr, Addrlen); 
1999/0914    
	memmove(port->name, name, NAMELEN); 
1999/0316    
	switch(port->type) { 
	default: panic("portbind: unknown port type: %d", type); 
	case Tether: 
1999/0901/sys/src/9/port/devbridge.c:614,6311999/0914/sys/src/9/port/devbridge.c:617,638
1999/0316    
	Port *port=nil; 
	int type=0, i; 
	char *usage = "usage: unbind ether|tunnel addr [ownhash]"; 
	uchar addr[Addrlen]; 
1999/0914    
	char name[NAMELEN]; 
1999/0316    
	ulong ownhash; 
 
	memset(addr, 0, Addrlen); 
1999/0914    
	memset(name, 0, NAMELEN); 
1999/0316    
	if(argc < 2 || argc > 3) 
		error(usage); 
	if(strcmp(argv[0], "ether") == 0) { 
		type = Tether; 
		parseaddr(addr, argv[1], Eaddrlen); 
1999/0914    
		strncpy(name, argv[1], NAMELEN); 
		name[NAMELEN-1] = 0; 
//		parseaddr(addr, argv[1], Eaddrlen); 
1999/0316    
	} else if(strcmp(argv[0], "tunnel") == 0) { 
1999/0807    
		type = Ttun; 
1999/0316    
		parseip(addr, argv[1]); 
1999/0914    
		strncpy(name, argv[1], NAMELEN); 
		name[NAMELEN-1] = 0; 
//		parseip(addr, argv[1]); 
1999/0316    
	} else 
		error(usage); 
	if(argc == 3) 
1999/0901/sys/src/9/port/devbridge.c:636,6421999/0914/sys/src/9/port/devbridge.c:643,649
1999/0316    
		port = b->port[i]; 
		if(port != nil) 
		if(port->type == type) 
		if(memcmp(port->addr, addr, Addrlen) == 0) 
1999/0914    
		if(memcmp(port->name, name, NAMELEN) == 0) 
1999/0316    
			break; 
	} 
	if(i == b->nport) 
1999/0914/sys/src/9/port/devbridge.c:606,6131999/0915/sys/src/9/port/devbridge.c:606,613 (short | long)
1999/0316    
		b->nport = port->id+1; 
 
	// assumes kproc always succeeds 
	port->ref++; 
	kproc("etherread", etherread, port);	// poperror must be next 
1999/0915    
	port->ref++; 
1999/0316    
} 
 
// assumes b is locked 
1999/0914/sys/src/9/port/devbridge.c:847,8531999/0915/sys/src/9/port/devbridge.c:847,856
1999/0316    
		if(c != nil) { 
1999/0901    
			b->copy++; 
1999/0316    
			bp2 = copyblock(bp, blocklen(bp)); 
			devtab[c->type]->bwrite(c, bp2, 0); 
1999/0915    
			if(!waserror()) { 
				devtab[c->type]->bwrite(c, bp2, 0); 
				poperror(); 
			} 
1999/0316    
		} 
		c = b->port[i]->data[1]; 
	} 
1999/0914/sys/src/9/port/devbridge.c:855,8611999/0915/sys/src/9/port/devbridge.c:858,867
1999/0316    
	// last write free block 
	if(c) { 
		bp2 = bp; bp = nil; USED(bp); 
		devtab[c->type]->bwrite(c, bp2, 0); 
1999/0915    
		if(!waserror()) { 
			devtab[c->type]->bwrite(c, bp2, 0); 
			poperror(); 
		} 
1999/0316    
	} else 
		freeb(bp); 
 
1999/0914/sys/src/9/port/devbridge.c:966,9711999/0915/sys/src/9/port/devbridge.c:972,978
1999/0316    
		// release lock to read - error means it is time to quit 
		qunlock(b); 
		if(waserror()) { 
1999/0915    
print("etherread read error\n"); 
1999/0316    
			qlock(b); 
			break; 
		} 
1999/0914/sys/src/9/port/devbridge.c:978,9831999/0915/sys/src/9/port/devbridge.c:985,991
1999/0316    
		if(port->closed) 
			break; 
		if(waserror()) { 
1999/0915    
print("etherread bridge error\n"); 
1999/0316    
			if(bp) 
				freeb(bp); 
			continue; 
1999/0915/sys/src/9/port/devbridge.c:981,9881999/0930/sys/src/9/port/devbridge.c:981,987 (short | long)
1999/0826    
if(0)print("devbridge: etherread: blocklen = %d\n", blocklen(bp)); 
1999/0316    
		poperror(); 
		qlock(b); 
                 
		if(port->closed) 
1999/0930    
		if(bp == nil || port->closed) 
1999/0316    
			break; 
		if(waserror()) { 
1999/0915    
print("etherread bridge error\n"); 
1999/0930/sys/src/9/port/devbridge.c:222,2421999/1230/sys/src/9/port/devbridge.c:222,227 (short | long)
1999/0316    
static int 
bridgewalk(Chan *c, char *name) 
{ 
	if(strcmp(name, "..") == 0){ 
		switch(TYPE(c->qid)){ 
		case Qtopdir: 
		case Qbridgedir: 
			c->qid = (Qid){CHDIR|Qtopdir, 0}; 
			break; 
		case Qportdir: 
			c->qid = (Qid){CHDIR|Qbridgedir, 0}; 
			break; 
		default: 
			panic("bridgewalk %lux", c->qid.path); 
		} 
		return 1; 
	} 
                 
	return devwalk(c, name, 0, 0, bridgegen); 
} 
 
1999/0930/sys/src/9/port/devbridge.c:430,4351999/1230/sys/src/9/port/devbridge.c:415,437
1999/0316    
	char buf[32]; 
	Dirtab *dt; 
	Qid qid; 
1999/1230    
 
	if(s  == DEVDOTDOT){ 
		switch(TYPE(c->qid)){ 
		case Qtopdir: 
		case Qbridgedir: 
			snprint(buf, "#B%d", 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; 
	} 
1999/0316    
 
	switch(type) { 
	default: 
1999/1230/sys/src/9/port/devbridge.c:420,4262000/0108/sys/src/9/port/devbridge.c:420,426 (short | long)
1999/1230    
		switch(TYPE(c->qid)){ 
		case Qtopdir: 
		case Qbridgedir: 
			snprint(buf, "#B%d", c->dev); 
2000/0108    
			snprint(buf, sizeof(buf), "#B%ld", c->dev); 
1999/1230    
			devdir(c, (Qid){CHDIR|Qtopdir, 0}, buf, 0, eve, 0555, dp); 
			break; 
		case Qportdir: 
2000/0108/sys/src/9/port/devbridge.c:36,422000/0205/sys/src/9/port/devbridge.c:36,42 (short | long)
1999/0316    
	CacheSize=	(CacheHash+CacheLook-1), 
	CacheTimeout=	5*60,		// timeout for cache entry in seconds 
 
1999/0826    
	TcpMssMax = 1400,			// max desirable Tcp MSS value 
2000/0205    
	TcpMssMax = 1360,			// max desirable Tcp MSS value 
1999/0826    
 
1999/0316    
}; 
 
2000/0205/sys/src/9/port/devbridge.c:986,9922000/0211/sys/src/9/port/devbridge.c:986,992 (short | long)
1999/0930    
		if(bp == nil || port->closed) 
1999/0316    
			break; 
		if(waserror()) { 
1999/0915    
print("etherread bridge error\n"); 
2000/0211    
//print("etherread bridge error\n"); 
1999/0316    
			if(bp) 
				freeb(bp); 
			continue; 
2000/0205/sys/src/9/port/devbridge.c:1026,10322000/0211/sys/src/9/port/devbridge.c:1026,1032
1999/0316    
		if(bp) 
			freeb(bp); 
	} 
print("etherread: trying to exit\n"); 
2000/0211    
//print("etherread: trying to exit\n"); 
1999/0316    
	port->readp = nil; 
	portfree(port); 
	qunlock(b); 
2000/0211/sys/src/9/port/devbridge.c:30,362000/0227/sys/src/9/port/devbridge.c:30,36 (short | long)
1999/0316    
	MaxQ, 
 
	Maxbridge=	4, 
	Maxport=	16,		// power of 2 
2000/0227    
	Maxport=	32,		// power of 2 
1999/0316    
	CacheHash=	257,		// prime 
	CacheLook=	5,		// how many cache entries to examine 
	CacheSize=	(CacheHash+CacheLook-1), 
2000/0227/sys/src/9/port/devbridge.c:36,432000/0331/sys/src/9/port/devbridge.c:36,43 (short | long)
1999/0316    
	CacheSize=	(CacheHash+CacheLook-1), 
	CacheTimeout=	5*60,		// timeout for cache entry in seconds 
 
2000/0205    
	TcpMssMax = 1360,			// max desirable Tcp MSS value 
1999/0826    
                 
2000/0331    
	TcpMssMax = 1300,			// max desirable Tcp MSS value 
	TunnelMtu = 1400, 
1999/0316    
}; 
 
1999/0824    
static Dirtab bridgedirtab[]={ 
2000/0227/sys/src/9/port/devbridge.c:128,1332000/0331/sys/src/9/port/devbridge.c:128,134
1999/0316    
	int	out;		// number of packets read 
	int	outmulti;	// multicast or broadcast 
	int	outunknown;	// unknown address 
2000/0331    
	int outfrag;	// fragmented the packet 
1999/0316    
	int	nentry;		// number of cache entries for this port 
}; 
 
2000/0227/sys/src/9/port/devbridge.c:183,1882000/0331/sys/src/9/port/devbridge.c:184,190
1999/0316    
static char	*cachedump(Bridge *b); 
static void	portfree(Port *port); 
static void	cacheflushport(Bridge *b, int port); 
2000/0331    
static void etherwrite(Port *port, Block *bp); 
1999/0316    
 
extern ulong	parseip(uchar*, char*); 
 
2000/0227/sys/src/9/port/devbridge.c:814,8202000/0331/sys/src/9/port/devbridge.c:816,822
1999/0316    
static void 
ethermultiwrite(Bridge *b, Block *bp, Port *port) 
{ 
	Chan *c; 
2000/0331    
	Port *oport; 
1999/0316    
	Block *bp2; 
	Etherpkt *ep; 
	int i, mcast, bcast; 
2000/0227/sys/src/9/port/devbridge.c:833,8452000/0331/sys/src/9/port/devbridge.c:835,846
1999/0316    
	else 
		bcast = 0; 
 
	c = nil; 
2000/0331    
	oport = nil; 
1999/0316    
	for(i=0; i<b->nport; i++) { 
		if(i == port->id || b->port[i] == nil) 
			continue; 
		if(mcast && !bcast && !b->port[i]->mcast) 
			continue; 
		b->port[i]->out++; 
		if(mcast) 
			b->port[i]->outmulti++; 
		else 
2000/0227/sys/src/9/port/devbridge.c:846,8672000/0331/sys/src/9/port/devbridge.c:847,868
1999/0316    
			b->port[i]->outunknown++; 
 
		// delay one so that the last write does not copy 
		if(c != nil) { 
2000/0331    
		if(oport != nil) { 
1999/0901    
			b->copy++; 
1999/0316    
			bp2 = copyblock(bp, blocklen(bp)); 
1999/0915    
			if(!waserror()) { 
				devtab[c->type]->bwrite(c, bp2, 0); 
2000/0331    
				etherwrite(oport, bp2); 
1999/0915    
				poperror(); 
			} 
1999/0316    
		} 
		c = b->port[i]->data[1]; 
2000/0331    
		oport = b->port[i]; 
1999/0316    
	} 
 
	// last write free block 
	if(c) { 
2000/0331    
	if(oport) { 
1999/0316    
		bp2 = bp; bp = nil; USED(bp); 
1999/0915    
		if(!waserror()) { 
			devtab[c->type]->bwrite(c, bp2, 0); 
2000/0331    
			etherwrite(oport, bp2); 
1999/0915    
			poperror(); 
		} 
1999/0316    
	} else 
2000/0227/sys/src/9/port/devbridge.c:961,9672000/0331/sys/src/9/port/devbridge.c:962,968
1999/0316    
static void 
etherread(void *a) 
{ 
	Port *port = a, *oport; 
2000/0331    
	Port *port = a; 
1999/0316    
	Bridge *b = port->bridge; 
	Block *bp, *bp2; 
	Etherpkt *ep; 
2000/0227/sys/src/9/port/devbridge.c:1016,10242000/0331/sys/src/9/port/devbridge.c:1017,1023
1999/0316    
			} else if (ce->port != port->id) { 
				b->hit++; 
				bp2 = bp; bp = nil; 
				oport = b->port[ce->port]; 
				oport->out++; 
				devtab[oport->data[1]->type]->bwrite(oport->data[1], bp2, 0); 
2000/0331    
				etherwrite(b->port[ce->port], bp2); 
1999/0316    
			} 
		} 
 
2000/0227/sys/src/9/port/devbridge.c:1031,10362000/0331/sys/src/9/port/devbridge.c:1030,1042
1999/0316    
	portfree(port); 
	qunlock(b); 
	pexit("hangup", 1); 
2000/0331    
} 
 
static void 
etherwrite(Port *port, Block *bp) 
{ 
	port->out++; 
	devtab[port->data[1]->type]->bwrite(port->data[1], bp, 0); 
1999/0316    
} 
 
// hold b lock 
2000/0331/sys/src/9/port/devbridge.c:135,1402000/0404/sys/src/9/port/devbridge.c:135,143 (short | long)
1999/0826    
enum { 
	IP_VER		= 0x40,		/* Using IP version 4 */ 
	IP_HLEN		= 0x05,		/* Header length in characters */ 
2000/0404    
	IP_DF		= 0x4000,	/* Don't fragment */ 
	IP_MF		= 0x2000,	/* More fragments */ 
	IP_MAX		= (32*1024),	/* Maximum Internet packet size */ 
1999/0826    
	IP_TCPPROTO = 6, 
1999/0827    
	EOLOPT		= 0, 
	NOOPOPT		= 1, 
2000/0331/sys/src/9/port/devbridge.c:141,1462000/0404/sys/src/9/port/devbridge.c:144,150
1999/0826    
	MSSOPT		= 2, 
	MSS_LENGTH	= 4,		/* Mean segment size */ 
1999/0827    
	SYN		= 0x02,		/* Pkt. is synchronise */ 
2000/0404    
	IPHDR		= 20,		/* sizeof(Iphdr) */ 
1999/0826    
}; 
 
struct Iphdr 
2000/0331/sys/src/9/port/devbridge.c:187,1922000/0404/sys/src/9/port/devbridge.c:191,197
2000/0331    
static void etherwrite(Port *port, Block *bp); 
1999/0316    
 
extern ulong	parseip(uchar*, char*); 
2000/0404    
extern ushort	ipcsum(uchar *addr); 
1999/0316    
 
static void 
bridgeinit(void) 
2000/0331/sys/src/9/port/devbridge.c:326,3342000/0404/sys/src/9/port/devbridge.c:331,339
1999/0316    
			} 
1999/0731    
			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)\n", 
2000/0404    
			i += snprint(buf+i, sizeof(buf)-i, "in=%d(%d:%d:%d) out=%d(%d:%d:%d:%d)\n", 
1999/0731    
				port->in, ingood, port->inmulti, port->inunknown, 
				port->out, outgood, port->outmulti, port->outunknown); 
2000/0404    
				port->out, outgood, port->outmulti, port->outunknown, port->outfrag); 
1999/0316    
			USED(i); 
		} 
		n = readstr(off, a, n, buf); 
2000/0331/sys/src/9/port/devbridge.c:887,8932000/0404/sys/src/9/port/devbridge.c:892,898
1999/0826    
		return; 
1999/0827    
	iphdr = (Iphdr*)(epkt->data); 
1999/0826    
	n -= ETHERHDRSIZE; 
	if(n < sizeof(Iphdr)) 
2000/0404    
	if(n < IPHDR) 
1999/0826    
		return; 
 
	// check it is ok IP packet 
2000/0331/sys/src/9/port/devbridge.c:1032,10422000/0404/sys/src/9/port/devbridge.c:1037,1156
1999/0316    
	pexit("hangup", 1); 
2000/0331    
} 
 
2000/0404    
static int 
fragment(Etherpkt *epkt, int n) 
{ 
	Iphdr *iphdr; 
 
	if(n <= TunnelMtu) 
		return 0; 
 
	// check it is an ip packet 
	if(nhgets(epkt->type) != 0x800) 
		return 0; 
	iphdr = (Iphdr*)(epkt->data); 
	n -= ETHERHDRSIZE; 
	if(n < IPHDR) 
		return 0; 
 
	// check it is ok IP packet - I don't handle IP options for the momment 
	if(iphdr->vihl != (IP_VER|IP_HLEN)) 
		return 0; 
 
	// check for don't fragment 
	if(iphdr->frag[0] & (IP_DF>>8)) 
		return 0; 
 
	// check for short block 
	if(nhgets(iphdr->length) > n) 
		return 0; 
 
	return 1; 
} 
 
 
2000/0331    
static void 
etherwrite(Port *port, Block *bp) 
{ 
2000/0404    
	Iphdr *eh, *feh; 
	Etherpkt *epkt; 
	int n, lid, len, seglen, chunk, dlen, blklen, offset, mf; 
	Block *xp, *nb; 
	ushort fragoff, frag; 
 
2000/0331    
	port->out++; 
	devtab[port->data[1]->type]->bwrite(port->data[1], bp, 0); 
2000/0404    
	epkt = (Etherpkt*)bp->rp; 
	n = blocklen(bp); 
	if(port->type != Ttun || !fragment(epkt, n)) { 
		devtab[port->data[1]->type]->bwrite(port->data[1], bp, 0); 
		return; 
	} 
	port->outfrag++; 
	if(waserror()){ 
		freeblist(bp);	 
		nexterror(); 
	} 
 
	seglen = (TunnelMtu - ETHERHDRSIZE - IPHDR) & ~7; 
	eh = (Iphdr*)(epkt->data); 
	len = nhgets(eh->length); 
	frag = nhgets(eh->frag); 
	mf = frag & IP_MF; 
	frag <<= 3; 
	dlen = len - IPHDR; 
	xp = bp; 
	lid = nhgets(eh->id); 
	offset = ETHERHDRSIZE+IPHDR; 
	while(xp != nil && offset && offset >= BLEN(xp)) { 
		offset -= BLEN(xp); 
		xp = xp->next; 
	} 
	xp->rp += offset; 
	 
if(0) print("seglen=%d, dlen=%d, mf=%x, frag=%d\n", seglen, dlen, mf, frag); 
	for(fragoff = 0; fragoff < dlen; fragoff += seglen) { 
		nb = allocb(ETHERHDRSIZE+IPHDR+seglen); 
		 
		feh = (Iphdr*)(nb->wp+ETHERHDRSIZE); 
 
		memmove(nb->wp, epkt, ETHERHDRSIZE+IPHDR); 
		nb->wp += ETHERHDRSIZE+IPHDR; 
 
		if((fragoff + seglen) >= dlen) { 
			seglen = dlen - fragoff; 
			hnputs(feh->frag, (frag+fragoff)>>3 | mf); 
		} 
		else	 
			hnputs(feh->frag, (frag+fragoff>>3) | IP_MF); 
 
		hnputs(feh->length, seglen + IPHDR); 
		hnputs(feh->id, lid); 
 
		/* Copy up the data area */ 
		chunk = seglen; 
		while(chunk) { 
			blklen = chunk; 
			if(BLEN(xp) < chunk) 
				blklen = BLEN(xp); 
			memmove(nb->wp, xp->rp, blklen); 
			nb->wp += blklen; 
			xp->rp += blklen; 
			chunk -= blklen; 
			if(xp->rp == xp->wp) 
				xp = xp->next; 
		}  
 
		feh->cksum[0] = 0; 
		feh->cksum[1] = 0; 
		hnputs(feh->cksum, ipcsum(&feh->vihl)); 
	 
		// don't generate small packets 
		if(BLEN(nb) < ETHERMINTU) 
			nb->wp = nb->rp + ETHERMINTU; 
		devtab[port->data[1]->type]->bwrite(port->data[1], nb, 0); 
	} 
	poperror(); 
	freeblist(bp);	 
1999/0316    
} 
 
// hold b lock 
2000/0404/sys/src/9/port/devbridge.c:30,362000/0526/sys/src/9/port/devbridge.c:30,36 (short | long)
1999/0316    
	MaxQ, 
 
	Maxbridge=	4, 
2000/0227    
	Maxport=	32,		// power of 2 
2000/0526    
	Maxport=	64,		// power of 2 
1999/0316    
	CacheHash=	257,		// prime 
	CacheLook=	5,		// how many cache entries to examine 
	CacheSize=	(CacheHash+CacheLook-1), 
2000/0526/sys/src/9/port/devbridge.c:95,1012000/0527/sys/src/9/port/devbridge.c:95,103 (short | long)
1999/0316    
	Centry	cache[CacheSize]; 
1999/0901    
	ulong	hit; 
	ulong	miss; 
	ulong copy; 
2000/0527    
	ulong	copy; 
	long	delay0;		// constant microsecond delay per packet 
	long	delayn;		// microsecond delay per byte 
1999/0826    
	int tcpmss;		// modify tcpmss value 
1999/0316    
 
	Log; 
2000/0526/sys/src/9/port/devbridge.c:188,1942000/0527/sys/src/9/port/devbridge.c:190,196
1999/0316    
static char	*cachedump(Bridge *b); 
static void	portfree(Port *port); 
static void	cacheflushport(Bridge *b, int port); 
2000/0331    
static void etherwrite(Port *port, Block *bp); 
2000/0527    
static void	etherwrite(Port *port, Block *bp); 
1999/0316    
 
extern ulong	parseip(uchar*, char*); 
2000/0404    
extern ushort	ipcsum(uchar *addr); 
2000/0526/sys/src/9/port/devbridge.c:398,4032000/0527/sys/src/9/port/devbridge.c:400,410
1999/0826    
			if(cb->nf != 2) 
				error("usage: clear option"); 
			bridgeoption(b, cb->f[1], 0); 
2000/0527    
		} 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); 
1999/0316    
		} else 
			error("unknown control request"); 
		poperror(); 
2000/0526/sys/src/9/port/devbridge.c:972,9772000/0527/sys/src/9/port/devbridge.c:979,985
1999/0316    
	Block *bp, *bp2; 
	Etherpkt *ep; 
	Centry *ce; 
2000/0527    
	long md; 
1999/0316    
	 
	qlock(b); 
	port->readp = up;	/* hide identity under a rock for unbind */ 
2000/0526/sys/src/9/port/devbridge.c:1005,10102000/0527/sys/src/9/port/devbridge.c:1013,1027
1999/0316    
		cacheupdate(b, ep->s, port->id); 
1999/0827    
		if(b->tcpmss) 
			tcpmsshack(ep, BLEN(bp)); 
2000/0527    
 
		/* 
		 * delay packets to simulate a slow link 
		 */ 
		if(b->delay0 || b->delayn){ 
			md = b->delay0 + b->delayn * BLEN(bp); 
			if(md > 0) 
				microdelay(md); 
		} 
1999/0316    
 
		if(ep->d[0] & 1) { 
			log(b, Logmcast, "mulitcast: port=%d src=%E dst=%E type=%#.4ux\n", 
2000/0527/sys/src/9/port/devbridge.c:256,2762000/0606/sys/src/9/port/devbridge.c:256,265 (short | long)
1999/0316    
	switch(TYPE(c->qid)) { 
	default: 
		break; 
	case Qtopdir: 
	case Qbridgedir: 
	case Qportdir: 
	case Qstatus: 
	case Qlocal: 
	case Qstats: 
		if(omode != OREAD) 
			error(Eperm); 
		break; 
	case Qlog: 
		logopen(b); 
		break; 
	case Qcache: 
		if(omode != OREAD) 
			error(Eperm); 
		c->aux = cachedump(b); 
		break; 
	} 
2000/0527/sys/src/9/port/devbridge.c:340,3452000/0606/sys/src/9/port/devbridge.c:329,339
1999/0316    
		} 
		n = readstr(off, a, n, buf); 
		qunlock(b); 
2000/0606    
		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); 
1999/0316    
		return n; 
	case Qcache: 
		n = readstr(off, a, n, c->aux); 
2000/0606/sys/src/9/port/devbridge.c:30,362001/0918/sys/src/9/port/devbridge.c:30,36 (short | long)
1999/0316    
	MaxQ, 
 
	Maxbridge=	4, 
2000/0526    
	Maxport=	64,		// power of 2 
2001/0918    
	Maxport=	128,		// power of 2 
1999/0316    
	CacheHash=	257,		// prime 
	CacheLook=	5,		// how many cache entries to examine 
	CacheSize=	(CacheHash+CacheLook-1), 
2000/0606/sys/src/9/port/devbridge.c:74,812001/0918/sys/src/9/port/devbridge.c:74,81
1999/0316    
 
static Dirtab	*dirtab[MaxQ]; 
 
#define TYPE(x) 	((x).path & 0xff) 
#define PORT(x) 	(((x).path >> 8)&(Maxport-1)) 
2001/0918    
#define TYPE(x) 	(((ulong)(x).path) & 0xff) 
#define PORT(x) 	((((ulong)(x).path) >> 8)&(Maxport-1)) 
1999/0316    
#define QID(x, y) 	(((x)<<8) | (y)) 
 
struct Centry 
2000/0606/sys/src/9/port/devbridge.c:118,1242001/0918/sys/src/9/port/devbridge.c:118,124
1999/0316    
	 
	// the following uniquely identifies the port 
	int	type; 
1999/0914    
	char	name[NAMELEN]; 
2001/0918    
	char	name[KNAMELEN]; 
1999/0316    
	 
	// owner hash - avoids bind/unbind races 
	ulong	ownhash; 
2000/0606/sys/src/9/port/devbridge.c:183,1892001/0918/sys/src/9/port/devbridge.c:183,189
1999/0316    
	[ORDWR]		6 
}; 
 
static int	bridgegen(Chan *c, Dirtab*, int, int s, Dir *dp); 
2001/0918    
static int	bridgegen(Chan *c, char*, Dirtab*, int, int s, Dir *dp); 
1999/0316    
static void	portbind(Bridge *b, int argc, char *argv[]); 
static void	portunbind(Bridge *b, int argc, char *argv[]); 
static void	etherread(void *a); 
2000/0606/sys/src/9/port/devbridge.c:222,2432001/0918/sys/src/9/port/devbridge.c:222,243
1999/0316    
		error("bad specification"); 
 
	c = devattach('B', spec); 
	c->qid = (Qid){QID(0, Qtopdir)|CHDIR, 0}; 
2001/0918    
	mkqid(&c->qid, QID(0, Qtopdir), 0, QTDIR); 
1999/0316    
	c->dev = dev; 
 
	return c; 
} 
 
static int 
bridgewalk(Chan *c, char *name) 
2001/0918    
static Walkqid* 
bridgewalk(Chan *c, Chan *nc, char **name, int nname) 
1999/0316    
{ 
	return devwalk(c, name, 0, 0, bridgegen); 
2001/0918    
	return devwalk(c, nc, name, nname, (Dirtab*)0, 0, bridgegen); 
1999/0316    
} 
 
static void 
bridgestat(Chan* c, char* db) 
2001/0918    
static int 
bridgestat(Chan* c, uchar* db, int n) 
1999/0316    
{ 
	devstat(c, db, nil, 0, bridgegen); 
2001/0918    
	return devstat(c, db, n, (Dirtab *)0, 0L, bridgegen); 
1999/0316    
} 
 
static Chan* 
2000/0606/sys/src/9/port/devbridge.c:416,4262001/0918/sys/src/9/port/devbridge.c:416,425
1999/0316    
} 
 
static int 
bridgegen(Chan *c, Dirtab*, int, int s, Dir *dp) 
2001/0918    
bridgegen(Chan *c, char *, Dirtab*, int, int s, Dir *dp) 
1999/0316    
{ 
	Bridge *b = bridgetab + c->dev; 
	int type = TYPE(c->qid); 
	char buf[32]; 
	Dirtab *dt; 
	Qid qid; 
1999/1230    
 
2000/0606/sys/src/9/port/devbridge.c:428,4392001/0918/sys/src/9/port/devbridge.c:427,440
1999/1230    
		switch(TYPE(c->qid)){ 
		case Qtopdir: 
		case Qbridgedir: 
2000/0108    
			snprint(buf, sizeof(buf), "#B%ld", c->dev); 
1999/1230    
			devdir(c, (Qid){CHDIR|Qtopdir, 0}, buf, 0, eve, 0555, dp); 
2001/0918    
			snprint(up->genbuf, sizeof(up->genbuf), "#B%ld", c->dev); 
			mkqid(&qid, Qtopdir, 0, QTDIR); 
			devdir(c, qid, up->genbuf, 0, eve, 0555, dp); 
1999/1230    
			break; 
		case Qportdir: 
			sprint(buf, "bridge%ld", c->dev); 
			devdir(c, (Qid){CHDIR|Qbridgedir, 0}, buf, 0, eve, 0555, dp); 
2001/0918    
			snprint(up->genbuf, sizeof(up->genbuf), "bridge%ld", c->dev); 
			mkqid(&qid, Qbridgedir, 0, QTDIR); 
			devdir(c, qid, up->genbuf, 0, eve, 0555, dp); 
1999/1230    
			break; 
		default: 
			panic("bridgewalk %lux", c->qid.path); 
2000/0606/sys/src/9/port/devbridge.c:444,4502001/0918/sys/src/9/port/devbridge.c:445,451
1999/0316    
	switch(type) { 
	default: 
		// non directory entries end up here 
		if(c->qid.path & CHDIR) 
2001/0918    
		if(c->qid.type & QTDIR) 
1999/0316    
			panic("bridgegen: unexpected directory");	 
		if(s != 0) 
			return -1; 
2000/0606/sys/src/9/port/devbridge.c:456,4632001/0918/sys/src/9/port/devbridge.c:457,465
1999/0316    
	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); 
2001/0918    
		snprint(up->genbuf, sizeof(up->genbuf), "bridge%ld", c->dev); 
		mkqid(&qid, QID(0, Qbridgedir), 0, QTDIR); 
		devdir(c, qid, up->genbuf, 0, eve, 0555, dp); 
1999/0316    
		return 1; 
	case Qbridgedir: 
		if(s<nelem(bridgedirtab)) { 
2000/0606/sys/src/9/port/devbridge.c:468,4822001/0918/sys/src/9/port/devbridge.c:470,484
1999/0316    
		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); 
2001/0918    
		mkqid(&qid, QID(s, Qportdir), 0, QTDIR); 
		snprint(up->genbuf, sizeof(up->genbuf), "%d", s); 
		devdir(c, qid, up->genbuf, 0, eve, 0555, dp); 
1999/0316    
		return 1; 
	case Qportdir: 
		if(s>=nelem(portdirtab)) 
			return -1; 
		dt = portdirtab+s; 
		qid = (Qid){QID(PORT(c->qid),TYPE(dt->qid)),0}; 
2001/0918    
		mkqid(&qid, QID(PORT(c->qid),TYPE(dt->qid)), 0, QTFILE); 
1999/0316    
		devdir(c, qid, dt->name, dt->length, eve, dt->perm, dp); 
		return 1; 
	} 
2000/0606/sys/src/9/port/devbridge.c:511,5262001/0918/sys/src/9/port/devbridge.c:513,528
1999/0316    
portbind(Bridge *b, int argc, char *argv[]) 
{ 
	Port *port; 
	char path[8*NAMELEN]; 
2001/0918    
	char path[8*KNAMELEN]; 
1999/0316    
	char buf[100]; 
	char *dev, *dev2=nil, *p; 
	Chan *ctl; 
	int type=0, i, n; 
1999/0914    
	char *usage = "usage: bind ether|tunnel name ownhash dev [dev2]"; 
	char name[NAMELEN]; 
2001/0918    
	char name[KNAMELEN]; 
1999/0316    
	ulong ownhash; 
 
1999/0914    
	memset(name, 0, NAMELEN); 
2001/0918    
	memset(name, 0, KNAMELEN); 
1999/0316    
	if(argc < 4) 
		error(usage); 
	if(strcmp(argv[0], "ether") == 0) { 
2000/0606/sys/src/9/port/devbridge.c:527,5412001/0918/sys/src/9/port/devbridge.c:529,543
1999/0316    
		if(argc != 4) 
			error(usage); 
		type = Tether; 
1999/0914    
		strncpy(name, argv[1], NAMELEN); 
		name[NAMELEN-1] = 0; 
2001/0918    
		strncpy(name, argv[1], KNAMELEN); 
		name[KNAMELEN-1] = 0; 
1999/0914    
//		parseaddr(addr, argv[1], Eaddrlen); 
1999/0316    
	} else if(strcmp(argv[0], "tunnel") == 0) { 
		if(argc != 5) 
			error(usage); 
1999/0807    
		type = Ttun; 
1999/0914    
		strncpy(name, argv[1], NAMELEN); 
		name[NAMELEN-1] = 0; 
2001/0918    
		strncpy(name, argv[1], KNAMELEN); 
		name[KNAMELEN-1] = 0; 
1999/0914    
//		parseip(addr, argv[1]); 
1999/0316    
		dev2 = argv[4]; 
	} else 
2000/0606/sys/src/9/port/devbridge.c:546,5522001/0918/sys/src/9/port/devbridge.c:548,554
1999/0316    
		port = b->port[i]; 
		if(port != nil) 
		if(port->type == type) 
1999/0914    
		if(memcmp(port->name, name, NAMELEN) == 0) 
2001/0918    
		if(memcmp(port->name, name, KNAMELEN) == 0) 
1999/0316    
			error("port in use"); 
	} 
	for(i=0; i<Maxport; i++) 
2000/0606/sys/src/9/port/devbridge.c:564,5702001/0918/sys/src/9/port/devbridge.c:566,572
1999/0316    
		nexterror(); 
	} 
	port->type = type; 
1999/0914    
	memmove(port->name, name, NAMELEN); 
2001/0918    
	memmove(port->name, name, KNAMELEN); 
1999/0316    
	switch(port->type) { 
	default: panic("portbind: unknown port type: %d", type); 
	case Tether: 
2000/0606/sys/src/9/port/devbridge.c:627,6472001/0918/sys/src/9/port/devbridge.c:629,649
1999/0316    
	Port *port=nil; 
	int type=0, i; 
	char *usage = "usage: unbind ether|tunnel addr [ownhash]"; 
1999/0914    
	char name[NAMELEN]; 
2001/0918    
	char name[KNAMELEN]; 
1999/0316    
	ulong ownhash; 
 
1999/0914    
	memset(name, 0, NAMELEN); 
2001/0918    
	memset(name, 0, KNAMELEN); 
1999/0316    
	if(argc < 2 || argc > 3) 
		error(usage); 
	if(strcmp(argv[0], "ether") == 0) { 
		type = Tether; 
1999/0914    
		strncpy(name, argv[1], NAMELEN); 
		name[NAMELEN-1] = 0; 
2001/0918    
		strncpy(name, argv[1], KNAMELEN); 
		name[KNAMELEN-1] = 0; 
1999/0914    
//		parseaddr(addr, argv[1], Eaddrlen); 
1999/0316    
	} else if(strcmp(argv[0], "tunnel") == 0) { 
1999/0807    
		type = Ttun; 
1999/0914    
		strncpy(name, argv[1], NAMELEN); 
		name[NAMELEN-1] = 0; 
2001/0918    
		strncpy(name, argv[1], KNAMELEN); 
		name[KNAMELEN-1] = 0; 
1999/0914    
//		parseip(addr, argv[1]); 
1999/0316    
	} else 
		error(usage); 
2000/0606/sys/src/9/port/devbridge.c:653,6592001/0918/sys/src/9/port/devbridge.c:655,661
1999/0316    
		port = b->port[i]; 
		if(port != nil) 
		if(port->type == type) 
1999/0914    
		if(memcmp(port->name, name, NAMELEN) == 0) 
2001/0918    
		if(memcmp(port->name, name, KNAMELEN) == 0) 
1999/0316    
			break; 
	} 
	if(i == b->nport) 
2000/0606/sys/src/9/port/devbridge.c:1189,11952001/0918/sys/src/9/port/devbridge.c:1191,1196
1999/0316    
	devreset, 
	bridgeinit, 
	bridgeattach, 
	devclone, 
	bridgewalk, 
	bridgestat, 
	bridgeopen, 
2001/0918/sys/src/9/port/devbridge.c:1190,11952002/0109/sys/src/9/port/devbridge.c:1190,1196 (short | long)
Add devshutdown.
rsc Fri Mar 4 12:44:25 2005
1999/0316    
 
	devreset, 
	bridgeinit, 
2002/0109    
	devshutdown, 
1999/0316    
	bridgeattach, 
	bridgewalk, 
	bridgestat, 
2002/0109/sys/src/9/port/devbridge.c:437,4432002/0125/sys/src/9/port/devbridge.c:437,443 (short | long)
Bug fix: print format (serious).
rsc Fri Mar 4 12:44:25 2005
2001/0918    
			devdir(c, qid, up->genbuf, 0, eve, 0555, dp); 
1999/1230    
			break; 
		default: 
			panic("bridgewalk %lux", c->qid.path); 
2002/0125    
			panic("bridgewalk %llux", c->qid.path); 
1999/1230    
		} 
		return 1; 
	} 
2002/0109/sys/src/9/port/devbridge.c:451,4572002/0125/sys/src/9/port/devbridge.c:451,457
1999/0316    
			return -1; 
		dt = dirtab[TYPE(c->qid)]; 
		if(dt == nil) 
			panic("bridgegen: unknown type: %d", TYPE(c->qid)); 
2002/0125    
			panic("bridgegen: unknown type: %lud", TYPE(c->qid)); 
1999/0316    
		devdir(c, c->qid, dt->name, dt->length, eve, dt->perm, dp); 
		return 1; 
	case Qtopdir: 
Too many diffs (26 > 25). Stopping.


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