~kris/9p

9hist

5fedb308c4245212bdd50684ace680f8c32c7f0d — David du Colombier 26 years ago 13d9cfb
Plan 9 from Bell Labs 2000-04-04
1 files changed, 118 insertions(+), 4 deletions(-)

M port/devbridge.c
M port/devbridge.c => port/devbridge.c +118 -4
@@ 135,12 135,16 @@ struct 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


@@ 187,6 191,7 @@ 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 void
bridgeinit(void)


@@ 326,9 331,9 @@ bridgeread(Chan *c, void *a, long n, vlong off)
			}
			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",
			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->out, outgood, port->outmulti, port->outunknown, port->outfrag);
			USED(i);
		}
		n = readstr(off, a, n, buf);


@@ 887,7 892,7 @@ tcpmsshack(Etherpkt *epkt, int n)
		return;
	iphdr = (Iphdr*)(epkt->data);
	n -= ETHERHDRSIZE;
	if(n < sizeof(Iphdr))
	if(n < IPHDR)
		return;

	// check it is ok IP packet


@@ 1032,11 1037,120 @@ if(0)print("devbridge: etherread: blocklen = %d\n", blocklen(bp));
	pexit("hangup", 1);
}

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;
}


static void
etherwrite(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++;
	devtab[port->data[1]->type]->bwrite(port->data[1], bp, 0);
	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 lock