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

📄 devbridge.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
		break;	case Ttun:		port->data[0] = namec(dev, Aopen, OREAD, 0);		port->data[1] = namec(dev2, Aopen, OWRITE, 0);		break;	}	poperror();	// commited to binding port	b->port[port->id] = port;	port->bridge = b;	if(b->nport <= port->id)		b->nport = port->id+1;	// assumes kproc always succeeds	kproc("etherread", etherread, port);	// poperror must be next	port->ref++;}// assumes b is lockedstatic voidportunbind(Bridge *b, int argc, char *argv[]){	Port *port=nil;	int type=0, i;	char *usage = "usage: unbind ether|tunnel addr [ownhash]";	char name[KNAMELEN];	ulong ownhash;	memset(name, 0, KNAMELEN);	if(argc < 2 || argc > 3)		error(usage);	if(strcmp(argv[0], "ether") == 0) {		type = Tether;		strncpy(name, argv[1], KNAMELEN);		name[KNAMELEN-1] = 0;//		parseaddr(addr, argv[1], Eaddrlen);	} else if(strcmp(argv[0], "tunnel") == 0) {		type = Ttun;		strncpy(name, argv[1], KNAMELEN);		name[KNAMELEN-1] = 0;//		parseip(addr, argv[1]);	} else		error(usage);	if(argc == 3)		ownhash = atoi(argv[2]);	else		ownhash = 0;	for(i=0; i<b->nport; i++) {		port = b->port[i];		if(port != nil)		if(port->type == type)		if(memcmp(port->name, name, KNAMELEN) == 0)			break;	}	if(i == b->nport)		error("port not found");	if(ownhash != 0 && port->ownhash != 0 && ownhash != port->ownhash)		error("bad owner hash");	port->closed = 1;	b->port[i] = nil;	// port is now unbound	cacheflushport(b, i);	// try and stop reader	if(port->readp)		postnote(port->readp, 1, "unbind", 0);	portfree(port);}// assumes b is lockedstatic Centry *cachelookup(Bridge *b, uchar d[Eaddrlen]){	int i;	uint h;	Centry *p;	long sec;	// dont cache multicast or broadcast	if(d[0] & 1)		return 0;	h = 0;	for(i=0; i<Eaddrlen; i++) {		h *= 7;		h += d[i];	}	h %= CacheHash;	p = b->cache + h;	sec = TK2SEC(m->ticks);	for(i=0; i<CacheLook; i++,p++) {		if(memcmp(d, p->d, Eaddrlen) == 0) {			p->dst++;			if(sec >= p->expire) {				log(b, Logcache, "expired cache entry: %E %d\n",					d, p->port);				return nil;			}			p->expire = sec + CacheTimeout;			return p;		}	}	log(b, Logcache, "cache miss: %E\n", d);	return nil;}// assumes b is lockedstatic voidcacheupdate(Bridge *b, uchar d[Eaddrlen], int port){	int i;	uint h;	Centry *p, *pp;	long sec;	// dont cache multicast or broadcast	if(d[0] & 1) {		log(b, Logcache, "bad source address: %E\n", d);		return;	}		h = 0;	for(i=0; i<Eaddrlen; i++) {		h *= 7;		h += d[i];	}	h %= CacheHash;	p = b->cache + h;	pp = p;	sec = p->expire;	// look for oldest entry	for(i=0; i<CacheLook; i++,p++) {		if(memcmp(p->d, d, Eaddrlen) == 0) {			p->expire = TK2SEC(m->ticks) + CacheTimeout;			if(p->port != port) {				log(b, Logcache, "NIC changed port %d->%d: %E\n",					p->port, port, d);				p->port = port;			}			p->src++;			return;		}		if(p->expire < sec) {			sec = p->expire;			pp = p;		}	}	if(pp->expire != 0)		log(b, Logcache, "bumping from cache: %E %d\n", pp->d, pp->port);	pp->expire = TK2SEC(m->ticks) + CacheTimeout;	memmove(pp->d, d, Eaddrlen);	pp->port = port;	pp->src = 1;	pp->dst = 0;	log(b, Logcache, "adding to cache: %E %d\n", pp->d, pp->port);}// assumes b is lockedstatic voidcacheflushport(Bridge *b, int port){	Centry *ce;	int i;	ce = b->cache;	for(i=0; i<CacheSize; i++,ce++) {		if(ce->port != port)			continue;		memset(ce, 0, sizeof(Centry));	}}static char *cachedump(Bridge *b){	int i, n;	long sec, off;	char *buf, *p, *ep;	Centry *ce;	char c;	qlock(b);	if(waserror()) {		qunlock(b);		nexterror();	}	sec = TK2SEC(m->ticks);	n = 0;	for(i=0; i<CacheSize; i++)		if(b->cache[i].expire != 0)			n++;		n *= 51;	// change if print format is changed	n += 10;	// some slop at the end	buf = malloc(n);	p = buf;	ep = buf + n;	ce = b->cache;	off = seconds() - sec;	for(i=0; i<CacheSize; i++,ce++) {		if(ce->expire == 0)			continue;			c = (sec < ce->expire)?'v':'e';		p += snprint(p, ep-p, "%E %2d %10ld %10ld %10ld %c\n", ce->d,			ce->port, ce->src, ce->dst, ce->expire+off, c);	}	*p = 0;	poperror();	qunlock(b);	return buf;}// assumes b is lockedstatic voidethermultiwrite(Bridge *b, Block *bp, Port *port){	Port *oport;	Block *bp2;	Etherpkt *ep;	int i, mcast, bcast;	static uchar bcastaddr[Eaddrlen] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};	if(waserror()) {		if(bp)			freeb(bp);		nexterror();	}		ep = (Etherpkt*)bp->rp;	mcast = ep->d[0] & 1;	if(mcast)		bcast = memcmp(ep->d, bcastaddr, Eaddrlen) == 0;	else		bcast = 0;	oport = nil;	for(i=0; i<b->nport; i++) {		if(i == port->id || b->port[i] == nil)			continue;		if(mcast && !bcast && !b->port[i]->mcast)			continue;		if(mcast)			b->port[i]->outmulti++;		else			b->port[i]->outunknown++;		// delay one so that the last write does not copy		if(oport != nil) {			b->copy++;			bp2 = copyblock(bp, blocklen(bp));			if(!waserror()) {				etherwrite(oport, bp2);				poperror();			}		}		oport = b->port[i];	}	// last write free block	if(oport) {		bp2 = bp; bp = nil; USED(bp);		if(!waserror()) {			etherwrite(oport, bp2);			poperror();		}	} else		freeb(bp);	poperror();}static voidtcpmsshack(Etherpkt *epkt, int n){	int hl;	Iphdr *iphdr;	Tcphdr *tcphdr;	ulong mss;	ulong cksum;	int optlen;	uchar *optr;	// check it is an ip packet	if(nhgets(epkt->type) != 0x800)		return;	iphdr = (Iphdr*)(epkt->data);	n -= ETHERHDRSIZE;	if(n < 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;	// check TCP	if(iphdr->proto != IP_TCPPROTO)		return;	n -= hl;	if(n < sizeof(Tcphdr))		return;	tcphdr = (Tcphdr*)((uchar*)(iphdr) + hl);	// MSS can only appear in SYN packet	if(!(tcphdr->flag[1] & SYN))		return;	hl = (tcphdr->flag[0] & 0xf0)>>2;	if(n < hl)		return;	// check for MSS option	optr = (uchar*)(tcphdr) + sizeof(Tcphdr);	n = hl - sizeof(Tcphdr);	for(;;) {		if(n <= 0 || *optr == EOLOPT)			return;		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);}/* *  process to read from the ethernet */static voidetherread(void *a){	Port *port = a;	Bridge *b = port->bridge;	Block *bp, *bp2;	Etherpkt *ep;	Centry *ce;	long md;		qlock(b);	port->readp = up;	/* hide identity under a rock for unbind */	while(!port->closed){		// release lock to read - error means it is time to quit		qunlock(b);		if(waserror()) {print("etherread read error: %s\n", up->errstr);			qlock(b);			break;		}if(0)print("devbridge: etherread: reading\n");		bp = devtab[port->data[0]->type]->bread(port->data[0], ETHERMAXTU, 0);if(0)print("devbridge: etherread: blocklen = %d\n", blocklen(bp));		poperror();		qlock(b);		if(bp == nil || port->closed)			break;		if(waserror()) {//print("etherread bridge error\n");			if(bp)				freeb(bp);			continue;		}		if(blocklen(bp) < ETHERMINTU)			error("short packet");		port->in++;		ep = (Etherpkt*)bp->rp;		cacheupdate(b, ep->s, port->id);		if(b->tcpmss)			tcpmsshack(ep, BLEN(bp));		/*		 * delay packets to simulate a slow link		 */		if(b->delay0 || b->delayn){			md = b->delay0 + b->delayn * BLEN(bp);			if(md > 0)				microdelay(md);		}		if(ep->d[0] & 1) {			log(b, Logmcast, "mulitcast: port=%d src=%E dst=%E type=%#.4ux\n",				port->id, ep->s, ep->d, (ep->type[0]<<8)|ep->type[1] );			port->inmulti++;			bp2 = bp; bp = nil;			ethermultiwrite(b, bp2, port);		} else {			ce = cachelookup(b, ep->d);			if(ce == nil) {				b->miss++;				port->inunknown++;				bp2 = bp; bp = nil;				ethermultiwrite(b, bp2, port);			}else if(ce->port != port->id){				b->hit++;				bp2 = bp; bp = nil;				etherwrite(b->port[ce->port], bp2);			}		}		poperror();		if(bp)			freeb(bp);	}//print("etherread: trying to exit\n");	port->readp = nil;	portfree(port);	qunlock(b);	pexit("hangup", 1);}static intfragment(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;}static voidetherwrite(Port *port, Block *bp){	Iphdr *eh, *feh;	Etherpkt *epkt;	int n, lid, len, seglen, chunk, dlen, blklen, offset, mf;	Block *xp, *nb;	ushort fragoff, frag;	port->out++;	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);	}// hold b lockstatic voidportfree(Port *port){	port->ref--;	if(port->ref < 0)		panic("portfree: bad ref");	if(port->ref > 0)		return;	if(port->data[0])		cclose(port->data[0]);	if(port->data[1])		cclose(port->data[1]);	memset(port, 0, sizeof(Port));	free(port);}Dev bridgedevtab = {	'B',	"bridge",	devreset,	bridgeinit,	devshutdown,	bridgeattach,	bridgewalk,	bridgestat,	bridgeopen,	devcreate,	bridgeclose,	bridgeread,	devbread,	bridgewrite,	devbwrite,	devremove,	devwstat,};

⌨️ 快捷键说明

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