Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/ip/ip.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname ip/ip.c 1997/0327
## diff -e /dev/null /n/emeliedump/1997/0327/sys/src/brazil/ip/ip.c
0a
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"

#include	"ip.h"

typedef struct Iphdr	Iphdr;
typedef struct Fragment	Fragment;
typedef struct Ipfrag	Ipfrag;

enum
{
	IPHDR		= 20,		/* sizeof(Iphdr) */
	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 */
};

struct Iphdr
{
	byte	vihl;		/* Version and header length */
	byte	tos;		/* Type of service */
	byte	length[2];	/* packet length */
	byte	id[2];		/* Identification */
	byte	frag[2];	/* Fragment information */
	byte	ttl;		/* Time to live */
	byte	proto;		/* Protocol */
	byte	cksum[2];	/* Header checksum */
	byte	src[4];		/* Ip source */
	byte	dst[4];		/* Ip destination */
};

struct Fragment
{
	QLock;
	Block*	blist;
	Fragment* next;
	Ipaddr 	src;
	Ipaddr 	dst;
	ushort	id;
	ulong 	age;
};

struct Ipfrag
{
	ushort	foff;
	ushort	flen;
};

Fragment*	flisthead;
Fragment*	fragfree;
QLock		fraglock;
ulong		Id;
int		iprouting;	/* true if we route like a gateway */
ulong		ipcsumerr;
ulong		ipin, ippin;		/* bytes, packets in */
ulong		ipout, ippout;		/* bytes, packets out */

#define BLKIP(xp)	((Iphdr*)((xp)->rp))
/*
 * This sleazy macro relies on the media header size being
 * larger than sizeof(Ipfrag). ipreassemble checks this is true
 */
#define BKFG(xp)	((Ipfrag*)((xp)->base))

ushort		ipcsum(byte*);
Block*		ipreassemble(int, Block*, Iphdr*);
void		ipfragfree(Fragment*, int);
Fragment*	ipfragallo(void);

void
ipoput(Block *bp, int gating, int ttl)
{
	Media *m;
	byte gate[4];
	ushort fragoff;
	Block *xp, *nb;
	Iphdr *eh, *feh;
	int lid, len, seglen, chunk, dlen, blklen, offset, medialen;

	/* Fill out the ip header */
	eh = (Iphdr *)(bp->rp);

	/* Number of bytes in data and ip header to write */
	len = blocklen(bp);
	ipout += len;
	ippout++;
	if(gating){
		chunk = nhgets(eh->length);
		if(chunk > len){
			netlog(Logip, "short gated packet\n");
			goto raise;
		}
		if(chunk < len)
			len = chunk;
	}
	if(len >= IP_MAX) {
		netlog(Logip, "exceeded ip max size %I\n", eh->dst);
		goto raise;
	}

	m = Mediaroute(eh->dst, gate);
	if(m == nil){
		netlog(Logip, "no interface %I\n", eh->dst);
		goto raise;
	}

	if(!gating){
		eh->vihl = IP_VER|IP_HLEN;
		eh->tos = 0;
		eh->ttl = ttl;
	}

	/* If we dont need to fragment just send it */
	medialen = m->maxmtu-m->hsize;
	if(len <= medialen) {
		if(!gating)
			hnputs(eh->id, Id++);
		hnputs(eh->length, len);
		eh->frag[0] = 0;
		eh->frag[1] = 0;
		eh->cksum[0] = 0;
		eh->cksum[1] = 0;
		hnputs(eh->cksum, ipcsum(&eh->vihl));

		Mediawrite(m, bp, gate);
		return;
	}

	if(eh->frag[0] & (IP_DF>>8)){
		netlog(Logip, "%I: eh->frag[0] & (IP_DF>>8)", eh->dst);
		goto raise;
	}

	seglen = (medialen - IPHDR) & ~7;
	if(seglen < 8){
		netlog(Logip, "%I seglen < 8\n", eh->dst);
		goto raise;
	}

	dlen = len - IPHDR;
	xp = bp;
	if(gating)
		lid = nhgets(eh->id);
	else
		lid = Id++;

	offset = IPHDR;
	while(xp != nil && offset && offset >= BLEN(xp)) {
		offset -= BLEN(xp);
		xp = xp->next;
	}
	xp->rp += offset;

	for(fragoff = 0; fragoff < dlen; fragoff += seglen) {
		nb = allocb(IPHDR+seglen);
		feh = (Iphdr*)(nb->rp);

		memmove(nb->wp, eh, IPHDR);
		nb->wp += IPHDR;

		if((fragoff + seglen) >= dlen) {
			seglen = dlen - fragoff;
			hnputs(feh->frag, fragoff>>3);
		}
		else	
			hnputs(feh->frag, (fragoff>>3)|IP_MF);

		hnputs(feh->length, seglen + IPHDR);
		hnputs(feh->id, lid);

		/* Copy up the data area */
		chunk = seglen;
		while(chunk) {
			if(!xp) {
				freeblist(nb);
				netlog(Logip, "!xp: chunk %d\n", chunk);
				goto raise;
			}
			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));
		Mediawrite(m, nb, gate);
	}

raise:
	freeblist(bp);	
}

void
initfrag(int size)
{
	Fragment *fq, *eq;

	fragfree = (Fragment*)malloc(sizeof(Fragment) * size);
	if(fragfree == nil)
		panic("initfrag");

	eq = &fragfree[size];
	for(fq = fragfree; fq < eq; fq++)
		fq->next = fq+1;

	fragfree[size-1].next = nil;
}

void (*ipextprotoiput)(Block*);

void
ipiput(Block *bp)
{
	Iphdr *h;
	Proto *p;
	ushort frag;
	int notforme;

/*	h = (Iphdr *)(bp->rp);
	netlog(Logip, "ipiput %I %I len %d proto %d\n", h->src, h->dst, BLEN(bp), h->proto);*/

	/* Ensure we have enough data to process */
	if(BLEN(bp) < IPHDR) {
		bp = pullupblock(bp, IPHDR);
		if(bp == nil)
			return;
	}
	h = (Iphdr *)(bp->rp);

	/* Look to see if its for me before we waste time checksumming it */
	notforme = Mediaforme(h->dst) == 0;
	if(notforme && !iprouting) {
		netlog(Logip, "ip: pkt not for me\n");
		freeblist(bp);
		return;
	}

	if(ipcsum(&h->vihl)) {
		ipcsumerr++;
		netlog(Logip, "ip: checksum error %I\n", h->src);
		freeblist(bp);
		return;
	}

	/* Check header length and version */
	if(h->vihl != (IP_VER|IP_HLEN)) {
		netlog(Logip, "ip: %I bad hivl %ux\n", h->src, h->vihl);
		freeblist(bp);
		return;
	}
	frag = nhgets(h->frag);
	if(frag) {
		h->tos = 0;
		if(frag & IP_MF)
			h->tos = 1;
		bp = ipreassemble(frag, bp, h);
		if(bp == nil)
			return;
		h = (Iphdr *)(bp->rp);
	}

	ipin += blocklen(bp);
	ippin++;

	if(iprouting) {
		/* gate */
		if(notforme){
			if(h->ttl == 0)
				freeblist(bp);
			else
				ipoput(bp, 1, h->ttl - 1);
			return;
		}
	}

	p = Fsrcvpcol(&fs, h->proto);
	if(p != nil && p->rcv != nil)
		(*p->rcv)(bp);
	else if(ipextprotoiput != nil)
		ipextprotoiput(bp);
	else
		freeblist(bp);
}

int
ipstats(char *buf, int len)
{
	int n;

	n = snprint(buf, len, "ip: csum %d inb %d outb %d inp %d outp %d\n",
		ipcsumerr, ipin, ipout, ippin, ippout);
	return n;
}

QLock iplock;

Block*
ipreassemble(int offset, Block *bp, Iphdr *ip)
{
	int fend;
	ushort id;
	Fragment *f, *fnext;
	Ipaddr src, dst;
	Block *bl, **l, *last, *prev;
	int ovlap, len, fragsize, pktposn;

	src = nhgetl(ip->src);
	dst = nhgetl(ip->dst);
	id = nhgets(ip->id);

	/*
	 *  block lists are too hard, pullupblock into a single block
	 */
	if(bp->next){
		bp = pullupblock(bp, blocklen(bp));
		ip = (Iphdr *)(bp->rp);
	}

	qlock(&iplock);

	/*
	 *  find a reassembly queue for this fragment
	 */
	qlock(&fraglock);
	for(f = flisthead; f; f = fnext){
		fnext = f->next;	/* because ipfragfree changes the list */
		if(f->src == src && f->dst == dst && f->id == id)
			break;
		if(f->age > msec && canqlock(f))
			ipfragfree(f, 0);
	}
	qunlock(&fraglock);

	/*
	 *  if this isn't a fragmented packet, accept it
	 *  and get rid of any fragments that might go
	 *  with it.
	 */
	if(!ip->tos && (offset & ~(IP_MF|IP_DF)) == 0) {
		if(f != nil) {
			qlock(f);
			ipfragfree(f, 1);
		}
		qunlock(&iplock);
		return bp;
	}

	if(bp->base+sizeof(Ipfrag) >= bp->rp)
		panic("ipreassemble");

	BKFG(bp)->foff = offset<<3;
	BKFG(bp)->flen = nhgets(ip->length)-IPHDR;

	/* First fragment allocates a reassembly queue */
	if(f == nil) {
		f = ipfragallo();
		qlock(f);
		f->id = id;
		f->src = src;
		f->dst = dst;

		f->blist = bp;

		qunlock(f);
		qunlock(&iplock);
		return nil;
	}
	qlock(f);

	/*
	 *  find the new fragment's position in the queue
	 */
	prev = nil;
	l = &f->blist;
	bl = f->blist;
	while(bl != nil && BKFG(bp)->foff > BKFG(bl)->foff) {
		prev = bl;
		l = &bl->next;
		bl = bl->next;
	}

	/* Check overlap of a previous fragment - trim away as necessary */
	if(prev) {
		ovlap = BKFG(prev)->foff + BKFG(prev)->flen - BKFG(bp)->foff;
		if(ovlap > 0) {
			if(ovlap >= BKFG(bp)->flen) {
				freeblist(bp);
				qunlock(f);
				qunlock(&iplock);
				return nil;
			}
			BKFG(prev)->flen -= ovlap;
		}
	}

	/* Link onto assembly queue */
	bp->next = *l;
	*l = bp;

	/* Check to see if succeeding segments overlap */
	if(bp->next) {
		l = &bp->next;
		fend = BKFG(bp)->foff + BKFG(bp)->flen;
		/* Take completely covered segments out */
		while(*l) {
			ovlap = fend - BKFG(*l)->foff;
			if(ovlap <= 0)
				break;
			if(ovlap < BKFG(*l)->flen) {
				BKFG(*l)->flen -= ovlap;
				BKFG(*l)->foff += ovlap;
				/* move up ip hdrs */
				memmove((*l)->rp + ovlap, (*l)->rp, IPHDR);
				(*l)->rp += ovlap;
				break;
			}
			last = (*l)->next;
			(*l)->next = nil;
			freeblist(*l);
			*l = last;
		}
	}

	/*
	 *  look for a complete packet.  if we get to a fragment
	 *  without IP_MF set, we're done.
	 */
	pktposn = 0;
	for(bl = f->blist; bl; bl = bl->next) {
		if(BKFG(bl)->foff != pktposn)
			break;
		if((BLKIP(bl)->frag[0]&(IP_MF>>8)) == 0) {
			bl = f->blist;
			len = nhgets(BLKIP(bl)->length);
			bl->wp = bl->rp + len;

			/* Pullup all the fragment headers and
			 * return a complete packet
			 */
			for(bl = bl->next; bl; bl = bl->next) {
				fragsize = BKFG(bl)->flen;
				len += fragsize;
				bl->rp += IPHDR;
				bl->wp = bl->rp + fragsize;
			}

			bl = f->blist;
			f->blist = nil;
			ipfragfree(f, 1);
			ip = BLKIP(bl);
			hnputs(ip->length, len);
			qunlock(&iplock);
			return bl;		
		}
		pktposn += BKFG(bl)->flen;
	}
	qunlock(f);
	qunlock(&iplock);
	return nil;
}

/*
 * ipfragfree - Free a list of fragments, fragment list must be locked
 */
void
ipfragfree(Fragment *frag, int lockq)
{
	Fragment *fl, **l;

	if(frag->blist)
		freeblist(frag->blist);

	frag->src = 0;
	frag->id = 0;
	frag->blist = nil;
	qunlock(frag);

	if(lockq)
		qlock(&fraglock);

	l = &flisthead;
	for(fl = *l; fl; fl = fl->next) {
		if(fl == frag) {
			*l = frag->next;
			break;
		}
		l = &fl->next;
	}

	frag->next = fragfree;
	fragfree = frag;

	if(lockq)
		qunlock(&fraglock);
}

/*
 * ipfragallo - allocate a reassembly queue
 */
Fragment *
ipfragallo(void)
{
	Fragment *f;

	qlock(&fraglock);
	while(fragfree == nil) {
		for(f = flisthead; f; f = f->next)
			if(canqlock(f)) {
				ipfragfree(f, 0);
				break;
			}
	}
	f = fragfree;
	fragfree = f->next;
	f->next = flisthead;
	flisthead = f;
	f->age = msec + 30000;

	qunlock(&fraglock);
	return f;
}

ushort
ipcsum(byte *addr)
{
	int len;
	ulong sum;

	sum = 0;
	len = (addr[0]&0xf)<<2;

	while(len > 0) {
		sum += addr[0]<<8 | addr[1] ;
		len -= 2;
		addr += 2;
	}

	sum = (sum & 0xffff) + (sum >> 16);
	sum = (sum & 0xffff) + (sum >> 16);

	return (sum^0xffff);
}
.
## diffname ip/ip.c 1997/0423
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/ip/ip.c /n/emeliedump/1997/0423/sys/src/brazil/ip/ip.c
291c
		(*p->rcv)(m, bp);
.
225c
ipiput(Media *m, Block *bp)
.
107c
	if(isbmcast(eh->dst)){
		m = Mediaroute(eh->src, nil);
		memmove(gate, eh->dst, Ipaddrlen);
	} else
		m = Mediaroute(eh->dst, gate);
.
## diffname ip/ip.c 1997/0504
## diff -e /n/emeliedump/1997/0423/sys/src/brazil/ip/ip.c /n/emeliedump/1997/0504/sys/src/brazil/ip/ip.c
365,366c
	if(bp->base+sizeof(Ipfrag) >= bp->rp){
		bp = padblock(bp, sizeof(Ipfrag));
		bp->rp += sizeof(Ipfrag);
	}
.
## diffname ip/ip.c 1997/0522
## diff -e /n/emeliedump/1997/0504/sys/src/brazil/ip/ip.c /n/emeliedump/1997/0522/sys/src/brazil/ip/ip.c
140c
		netlog(Logip, "%I: eh->frag[0] & (IP_DF>>8)\n", eh->dst);
.
## diffname ip/ip.c 1997/0529
## diff -e /n/emeliedump/1997/0522/sys/src/brazil/ip/ip.c /n/emeliedump/1997/0529/sys/src/brazil/ip/ip.c
538d
526,530c
		/* free last entry on fraglist */
		for(f = flisthead; f->next; f = f->next)
			;
		ipfragfree(f);
.
524d
517c
 * ipfragallo - allocate a reassembly queue - assume hold fraglock
.
512,513d
497,499d
495d
485c
ipfragfree(Fragment *frag)
.
482c
 * ipfragfree - Free a list of fragments - assume hold fraglock
.
476,477c
	qunlock(&fraglock);
.
471c
			qunlock(&fraglock);
.
468c
			ipfragfree(f);
.
407,408c
				qunlock(&fraglock);
.
387d
383,384c
		qunlock(&fraglock);
.
376d
357,361c
		if(f != nil)
			ipfragfree(f);
		qunlock(&fraglock);
.
349d
346,347c
		if(f->age < msec)
			ipfragfree(f);
.
341d
336c
	qlock(&fraglock);
.
312,313d
73c
void		ipfragfree(Fragment*);
.
57d
54a
QLock		fraglock;
.
40d
## diffname ip/ip.c 1997/0806
## diff -e /n/emeliedump/1997/0529/sys/src/brazil/ip/ip.c /n/emeliedump/1997/0806/sys/src/brazil/ip/ip.c
235,236c
//	h = (Iphdr *)(bp->rp);
//	DBG(nhgetl(h->src))(Logipmsg, "ipiput %I %I len %d proto %d\n", h->src, h->dst, BLEN(bp), h->proto);
.
226a
//#define DBG(x)	if((logmask & Logipmsg) && (iponly == 0 || x == iponly))netlog

.
## diffname ip/ip.c 1997/0808
## diff -e /n/emeliedump/1997/0806/sys/src/brazil/ip/ip.c /n/emeliedump/1997/0808/sys/src/brazil/ip/ip.c
308c
	n = snprint(buf, len, "ip: csum %lud inb %lud outb %lud inp %lud outp %lud\n",
.
## diffname ip/ip.c 1997/0815
## diff -e /n/emeliedump/1997/0808/sys/src/brazil/ip/ip.c /n/emeliedump/1997/0815/sys/src/brazil/ip/ip.c
108c
		memmove(gate, eh->dst, IPaddrlen);
.
## diffname ip/ip.c 1997/0916
## diff -e /n/emeliedump/1997/0815/sys/src/brazil/ip/ip.c /n/emeliedump/1997/0916/sys/src/brazil/ip/ip.c
345a
		}
.
344c
		if(f->age < msec){
			stats.droppedfrag++;
.
309a
	n += snprint(buf+n, len - n, "\tnoroute %lud droppedfrag %lud\n",
		stats.noroute, stats.droppedfrag);
.
111a
		stats.noroute++;
.
69a
static struct Stats
{
	ulong	noroute;
	ulong	droppedfrag;
} stats;

.
## diffname ip/ip.c 1997/1104
## diff -e /n/emeliedump/1997/0916/sys/src/brazil/ip/ip.c /n/emeliedump/1997/1104/sys/src/brazil/ip/ip.c
221c
	fragfree = malloc(sizeof(Fragment) * size);
.
## diffname ip/ip.c 1998/0217
## diff -e /n/emeliedump/1997/1104/sys/src/brazil/ip/ip.c /n/emeliedump/1998/0217/sys/src/brazil/ip/ip.c
21c
	IP_MAX		= (64*1024),	/* Maximum Internet packet size */
.
## diffname ip/ip.c 1998/0306
## diff -e /n/emeliedump/1998/0217/sys/src/brazil/ip/ip.c /n/emeliedump/1998/0306/sys/src/brazil/ip/ip.c
535c
ipcsum(uchar *addr)
.
328c
	ulong src, dst;
.
303c
		(*p->rcv)(ia, bp);
.
290,300d
269a
	/* route */
	v4tov6(v6dst, h->dst);
	notforme = ipforme(v6dst) == 0;
	if(notforme) {
		if(iprouting) {
			/* gate */
			if(h->ttl <= 1)
				freeblist(bp);
			else
				ipoput(bp, 1, h->ttl - 1);
		} else
			useriprouter(ia, bp);
		return;
	}

.
255,262c
	/* dump anything that whose header doesn't checksum */
.
242a
	uchar v6dst[IPaddrlen];
.
237c
ipiput(uchar *ia, Block *bp)
.
221c
	fragfree = (Fragment*)malloc(sizeof(Fragment) * size);
.
209c
		ifc->m->bwrite(ifc, nb, V4, gate);
.
152c
		netlog(Logip, "%V seglen < 8\n", eh->dst);
.
146c
		netlog(Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst);
.
141c
/*print("ipoput %V->%V via %V\n", eh->src, eh->dst, gate);*/
		ifc->m->bwrite(ifc, bp, V4, gate);
.
130c
	medialen = ifc->m->maxmtu - ifc->m->hsize;
.
127a
	ifc = r->ifc;
.
122c
	if(r->type & (Rifc|Runi|Rbcast|Rmulti))
		gate = eh->dst;
	else
		gate = r->v4.gate;
.
119c
		netlog(Logip, "no interface %V\n", eh->dst);
.
112,117c
	r = v4lookup(eh->dst);
	if(r == nil){
.
107,108c
	if(len >= IP_MAX){
		netlog(Logip, "exceeded ip max size %V\n", eh->dst);
.
94c
	/* Number of uchars in data and ip header to write */
.
89a
	Route *r;
.
84,85c
	Ipifc *ifc;
	uchar *gate;
.
76c
ushort		ipcsum(uchar*);
.
60,61c
ulong		ipin, ippin;		/* uchars, packets in */
ulong		ipout, ippout;		/* uchars, packets out */
.
42,43c
	ulong 	src;
	ulong 	dst;
.
26,35c
	uchar	vihl;		/* Version and header length */
	uchar	tos;		/* Type of service */
	uchar	length[2];	/* packet length */
	uchar	id[2];		/* 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 */
.
21c
	IP_MAX		= (32*1024),	/* Maximum Internet packet size */
.
## diffname ip/ip.c 1998/0307
## diff -e /n/emeliedump/1998/0306/sys/src/brazil/ip/ip.c /n/emeliedump/1998/0307/sys/src/brazil/ip/ip.c
214a
	runlock(ifc);
	poperror();
.
206c
		}
.
143a
		runlock(ifc);
		poperror();
.
129a
	if(waserror()){
		runlock(ifc);
		nexterror();
	}
	rlock(ifc);
	if(ifc->m == nil)
		goto raise;

.
## diffname ip/ip.c 1998/0308
## diff -e /n/emeliedump/1998/0307/sys/src/brazil/ip/ip.c /n/emeliedump/1998/0308/sys/src/brazil/ip/ip.c
226a
free:
.
117c
		goto free;
.
110c
		goto free;
.
103c
			goto free;
.
## diffname ip/ip.c 1998/0313
## diff -e /n/emeliedump/1998/0308/sys/src/brazil/ip/ip.c /n/emeliedump/1998/0313/sys/src/brazil/ip/ip.c
538,541c
	f = ip->fragfree;
	ip->fragfree = f->next;
	f->next = ip->flisthead;
	ip->flisthead = f;
.
536c
		ipfragfree(ip, f);
.
534c
		for(f = ip->flisthead; f->next; f = f->next)
.
532c
	while(ip->fragfree == nil) {
.
528c
ipfragallo(IP *ip)
.
519,520c
	frag->next = ip->fragfree;
	ip->fragfree = frag;
.
510c
	l = &ip->flisthead;
.
499c
ipfragfree(IP *ip, Fragment *frag)
.
491c
	qunlock(&ip->fraglock);
.
483,486c
			ipfragfree(ip, f);
			ih = BLKIP(bl);
			hnputs(ih->length, len);
			qunlock(&ip->fraglock);
			ip->istats.ipReasmOKs++;
.
446c
				/* move up ih hdrs */
.
423c
				qunlock(&ip->fraglock);
.
401c
		qunlock(&ip->fraglock);
		ip->istats.ipReasmReqds++;
.
394c
		f = ipfragallo(ip);
.
390c
	BKFG(bp)->flen = nhgets(ih->length)-IPHDR;
.
377,380c
	if(!ih->tos && (offset & ~(IP_MF|IP_DF)) == 0) {
		if(f != nil) {
			ipfragfree(ip, f);
			ip->istats.ipReasmFails++;
		}
		qunlock(&ip->fraglock);
.
367,368c
			ip->istats.ipReasmTimeout++;
			ipfragfree(ip, f);
.
362c
	for(f = ip->flisthead; f; f = fnext){
.
357c
	qlock(&ip->fraglock);
.
354c
		ih = (Iphdr *)(bp->rp);
.
345,347c
	src = nhgetl(ih->src);
	dst = nhgetl(ih->dst);
	id = nhgets(ih->id);
.
336c
ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih)
.
328,332c
	ip = f->ip;
	return snprint(buf, len, "%d %d %d %d %d %d %d %d %d %d "
				 "%d %d %d %d %d %d %d %d %d",
		ip->istats.ipForwarding, ip->istats.ipDefaultTTL,
		ip->istats.ipInReceives, ip->istats.ipInHdrErrors,
		ip->istats.ipInAddrErrors, ip->istats.ipForwDatagrams,
		ip->istats.ipInUnknownProtos, ip->istats.ipInDiscards,
		ip->istats.ipInDelivers, ip->istats.ipOutRequests,
		ip->istats.ipOutDiscards, ip->istats.ipOutNoRoutes,
		ip->istats.ipReasmTimeout, ip->istats.ipReasmReqds,
		ip->istats.ipReasmOKs, ip->istats.ipReasmFails,
		ip->istats.ipFragOKs, ip->istats.ipFragFails,
		ip->istats.ipFragCreates);
.
326c
	IP *ip;
.
324c
ipstats(Fs *f, char *buf, int len)
.
311,320c
	p = Fsrcvpcol(f, h->proto);
	if(p != nil && p->rcv != nil) {
		ip->istats.ipInDelivers++;
		(*p->rcv)(p, ia, bp);
		return;
	}
	ip->istats.ipInDiscards++;
	ip->istats.ipInUnknownProtos++;
	freeblist(bp);
.
305c
		bp = ipreassemble(ip, frag, bp, h);
.
294,299c


.
290c
			useriprouter(f, ia, bp);
.
287,288c
			else {
				ip->istats.ipForwDatagrams++;
				ipoput(f, bp, 1, h->ttl - 1);
			}
.
283c
		if(ip->iprouting) {
.
281c
	notforme = ipforme(f, v6dst) == 0;

	/* Check header length and version */
	if(h->vihl != (IP_VER|IP_HLEN)) {
		hl = (h->vihl&0xF)<<2;
		if((h->vihl&0xF0) != IP_VER || hl < (IP_HLEN<<2)) {
			ip->istats.ipInHdrErrors++;
			netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl);
			freeblist(bp);
			return;
		}
		/* If this is not routed strip off the options */
		if(notforme == 0) {
			dp = bp->rp + (hl - (IP_HLEN<<2));
			memmove(dp, h, IP_HLEN<<2);
			bp->rp = dp;
			h = (Iphdr *)(bp->rp);
			h->vihl = (IP_VER|IP_HLEN);
		}
	}

	/* route */
.
279d
273,274c
		ip->istats.ipInHdrErrors++;
		netlog(f, Logip, "ip: checksum error %I\n", h->src);
.
261c
//	DBG(nhgetl(h->src))(Logipmsg, "ipiput %V %V len %d proto %d\n",
//				h->src, h->dst, BLEN(bp), h->proto);
.
259a
	ip = f->ip;
	ip->istats.ipInReceives++;

.
258c
	uchar *dp, v6dst[IPaddrlen];
	IP *ip;
.
253a
	int hl;
.
252c
ipiput(Fs *f, uchar *ia, Block *bp)
.
249,250d
247c
#define DBG(x)	if((logmask & Logipmsg) && (iponly == 0 || x == iponly))netlog
.
244c
	ip->fragfree[size-1].next = nil;
.
240,241c
	eq = &ip->fragfree[size];
	for(fq = ip->fragfree; fq < eq; fq++)
.
236,237c
	ip->fragfree = (Fragment*)malloc(sizeof(Fragment) * size);
	if(ip->fragfree == nil)
.
232c
initfrag(IP *ip, int size)
.
223d
221a
		ip->istats.ipFragCreates++;
.
216c
		} 
.
204c
				netlog(f, Logip, "!xp: chunk %d\n", chunk);
.
202a
				ip->istats.ipOutDiscards++;
.
173c
		lid = ip->id++;
.
164c
		ip->istats.ipOutDiscards++;
		netlog(f, Logip, "%V seglen < 8\n", eh->dst);
.
158c
		ip->istats.ipOutDiscards++;
		netlog(f, Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst);
.
150c
/*		print("ipoput %V->%V via %V\n", eh->src, eh->dst, gate); /**/
.
142c
			hnputs(eh->id, ip->id++);
.
128d
122a

.
121a
	if(r->type & (Rbcast|Rmulti)) {
		gate = eh->dst;
		sr = v4lookup(f, eh->src);
		if(sr != nil && (sr->type & Runi))
			ifc = sr->ifc;
	}
	else
.
119c

	ifc = r->ifc;
	if(r->type & (Rifc|Runi))
.
115,116c
		ip->istats.ipOutNoRoutes++;
		netlog(f, Logip, "no interface %V\n", eh->dst);
.
113c
	r = v4lookup(f, eh->dst);
.
109c
		ip->istats.ipOutDiscards++;
		netlog(f, Logip, "exceeded ip max size %V\n", eh->dst);
.
102c
			ip->istats.ipOutDiscards++;
			netlog(f, Logip, "short gated packet\n");
.
97,98c

.
94a
	ip->istats.ipOutRequests++;

.
91a
	ip = f->ip;

.
90c
	Route *r, *sr;
	IP *ip;
.
82c
ipoput(Fs *f, Block *bp, int gating, int ttl)
.
76,79c
	ip = smalloc(sizeof(IP));
	initfrag(ip, 100);
	f->ip = ip;
}
.
72,74c
	IP *ip;
.
70c
ushort		ipcsum(uchar*);
Block*		ipreassemble(IP*, int, Block*, Iphdr*);
void		ipfragfree(IP*, Fragment*);
Fragment*	ipfragallo(IP*);

void
ip_init(Fs *f)
.
62a
/* an instance of IP */
struct IP
{
	Ipstats		istats;

	QLock		fraglock;
	Fragment*	flisthead;
	Fragment*	fragfree;

	ulong		id;
	int		iprouting;			/* true if we route like a gateway */
	void 		(*ipextprotoiput)(Block*);
};

.
54,61c
/* MIB II counters */
typedef struct Ipstats Ipstats;
struct Ipstats
{
	ulong	ipForwarding;
	ulong	ipDefaultTTL;
	ulong	ipInReceives;
	ulong	ipInHdrErrors;
	ulong	ipInAddrErrors;
	ulong	ipForwDatagrams;
	ulong	ipInUnknownProtos;
	ulong	ipInDiscards;
	ulong	ipInDelivers;
	ulong	ipOutRequests;
	ulong	ipOutDiscards;
	ulong	ipOutNoRoutes;
	ulong	ipReasmTimeout;
	ulong	ipReasmReqds;
	ulong	ipReasmOKs;
	ulong	ipReasmFails;
	ulong	ipFragOKs;
	ulong	ipFragFails;
	ulong	ipFragCreates;
};
.
34,35c
	uchar	src[4];		/* IP source */
	uchar	dst[4];		/* IP destination */
.
29c
	uchar	id[2];		/* ip->identification */
.
## diffname ip/ip.c 1998/0314
## diff -e /n/emeliedump/1998/0313/sys/src/brazil/ip/ip.c /n/emeliedump/1998/0314/sys/src/brazil/ip/ip.c
115a
iprouting(Fs *f, int on)
{
	f->ip->iprouting = on;
}

void
.
## diffname ip/ip.c 1998/0326
## diff -e /n/emeliedump/1998/0314/sys/src/brazil/ip/ip.c /n/emeliedump/1998/0326/sys/src/brazil/ip/ip.c
325,327c
	/*
	 *  Ensure we have allt he header info in the first
	 *  block.  Make life easier for other protocols by
	 *  collecting up to the first 64 bytes in the first block.
	 */
	if(BLEN(bp) < 64) {
		hl = blocklen(bp);
		if(hl < IPHDR)
			hl = IPHDR;
		if(hl > 64)
			hl = 64;
		bp = pullupblock(bp, hl);
.
## diffname ip/ip.c 1998/0331
## diff -e /n/emeliedump/1998/0326/sys/src/brazil/ip/ip.c /n/emeliedump/1998/0331/sys/src/brazil/ip/ip.c
326c
	 *  Ensure we have all the header info in the first
.
## diffname ip/ip.c 1998/0604
## diff -e /n/emeliedump/1998/0331/sys/src/brazil/ip/ip.c /n/emeliedump/1998/0604/sys/src/brazil/ip/ip.c
189d
184a
	rlock(ifc);
.
## diffname ip/ip.c 1998/0630
## diff -e /n/emeliedump/1998/0604/sys/src/brazil/ip/ip.c /n/emeliedump/1998/0630/sys/src/brazil/ip/ip.c
189a
	rlock(ifc);
.
185d
136c
	eh = (Iphdr*)(bp->rp);
.
## diffname ip/ip.c 1998/0813
## diff -e /n/emeliedump/1998/0630/sys/src/brazil/ip/ip.c /n/emeliedump/1998/0813/sys/src/brazil/ip/ip.c
416a
	ip->istats.ipDefaultTTL = MAXTTL;
.
378c
			} else {
.
376c
			if(h->ttl <= 1){
				ip->istats.ipInHdrErrors++;
				icmpttlexceeded(f, ia, bp);
.
118a
	if(f->ip->iprouting==0)
		f->ip->istats.ipForwarding = 2;
	else
		f->ip->istats.ipForwarding = 1;	
.
## diffname ip/ip.c 1998/0825
## diff -e /n/emeliedump/1998/0813/sys/src/brazil/ip/ip.c /n/emeliedump/1998/0825/sys/src/brazil/ip/ip.c
424,425c
	return snprint(buf, len, "%lud %lud %lud %lud %lud %lud %lud %lud %lud %lud "
				 "%lud %lud %lud %lud %lud %lud %lud %lud %lud",
.
## diffname ip/ip.c 1998/1208
## diff -e /n/emeliedump/1998/0825/sys/src/brazil/ip/ip.c /n/emeliedump/1998/1208/sys/src/brazil/ip/ip.c
349c
		netlog(f, Logip, "ip: checksum error %V\n", h->src);
.
## diffname ip/ip.c 1998/1209
## diff -e /n/emeliedump/1998/1208/sys/src/brazil/ip/ip.c /n/emeliedump/1998/1209/sys/src/brazil/ip/ip.c
389a
			return;
		}

		/* don't forward to source's network */
		sr = v4lookup(f, h->src);
		r = v4lookup(f, h->dst);
		if(r == nil || sr == r){
			ip->istats.ipOutDiscards++;
			freeblist(bp);
			return;
		}

		/* don't forward if packet has timed out */
		if(h->ttl <= 1){
			ip->istats.ipInHdrErrors++;
			icmpttlexceeded(f, ia, bp);
			freeblist(bp);
			return;
		}

		ip->istats.ipForwDatagrams++;
		ipoput(f, bp, 1, h->ttl - 1);

.
378,388c
		if(!ip->iprouting){
.
320a
	Route *r, *sr;
.
## diffname ip/ip.c 1999/0302
## diff -e /n/emeliedump/1998/1209/sys/src/brazil/ip/ip.c /n/emeliedump/1999/0302/sys/src/brazil/ip/ip.c
234c
		lid = incref(&ip->id);
.
201c
			hnputs(eh->id, incref(&ip->id));
.
193d
188a
	if(!canrlock(ifc))
		goto free;
.
88c
	Ref		id;
.
## diffname ip/ip.c 1999/0309
## diff -e /n/emeliedump/1999/0302/sys/src/brazil/ip/ip.c /n/emeliedump/1999/0309/sys/src/brazil/ip/ip.c
187a
	eh->ttl = ttl;
.
186d
## diffname ip/ip.c 1999/0817
## diff -e /n/emeliedump/1999/0309/sys/src/brazil/ip/ip.c /n/emeliedump/1999/0817/sys/src/brazil/ip/ip.c
403c
		ipoput(f, bp, 1, h->ttl - 1, h->tos);
.
187a
	eh->tos = tos;
.
126c
ipoput(Fs *f, Block *bp, int gating, int ttl, int tos)
.
## diffname ip/ip.c 1999/0917
## diff -e /n/emeliedump/1999/0817/sys/src/brazil/ip/ip.c /n/emeliedump/1999/0917/sys/src/brazil/ip/ip.c
187,188d
185c
		eh->ttl = ttl;
		eh->tos = tos;
.
## diffname ip/ip.c 1999/1003
## diff -e /n/emeliedump/1999/0917/sys/src/brazil/ip/ip.c /n/emeliedump/1999/1003/sys/src/brazil/ip/ip.c
183c
	if(gating){
		switch(eh->ttl){
		case 0:
		case 1:
			goto free;
		default:
			eh->ttl--;
			break;
		}
	} else {
.
## diffname ip/ip.c 1999/10041
## diff -e /n/emeliedump/1999/1003/sys/src/brazil/ip/ip.c /n/emeliedump/1999/10041/sys/src/brazil/ip/ip.c
194,196c
	eh->ttl = ttl;
	eh->tos = tos;
.
183,192c
	if(!gating)
.
## diffname ip/ip.c 2000/0220
## diff -e /n/emeliedump/1999/10041/sys/src/brazil/ip/ip.c /n/emeliedump/2000/0220/sys/src/9/ip/ip.c
380c
			freeb(bp);
.
285a
	ip->istats.ipFragOKs++;
.
264a
				ip->istats.ipFragFails++;
.
223a
		ip->istats.ipFragFails++;
.
216a
		ip->istats.ipFragFails++;
.
## diffname ip/ip.c 2000/0329
## diff -e /n/emeliedump/2000/0220/sys/src/9/ip/ip.c /n/emeliedump/2000/0329/sys/src/9/ip/ip.c
90d
## diffname ip/ip.c 2000/0706
## diff -e /n/emeliedump/2000/0329/sys/src/9/ip/ip.c /n/emeliedump/2000/0706/sys/src/9/ip/ip.c
610c
			ip->stats[ReasmOKs]++;
.
524c
		ip->stats[ReasmReqds]++;
.
500c
			ip->stats[ReasmFails]++;
.
487c
			ip->stats[ReasmTimeout]++;
.
440,452c
	ip->stats[DefaultTTL] = MAXTTL;

	p = buf;
	e = p+len;
	for(i = 0; i < Nstats; i++)
		p = seprint(p, e, "%s: %lud\n", statnames[i], ip->stats[i]);
	return p - buf;
.
437a
	char *p, *e;
	int i;
.
429,430c
	ip->stats[InDiscards]++;
	ip->stats[InUnknownProtos]++;
.
425c
		ip->stats[InDelivers]++;
.
404c
		ip->stats[ForwDatagrams]++;
.
398c
			ip->stats[InHdrErrors]++;
.
391c
			ip->stats[OutDiscards]++;
.
365c
			ip->stats[InHdrErrors]++;
.
352c
		ip->stats[InHdrErrors]++;
.
327c
	ip->stats[InReceives]++;
.
288c
	ip->stats[FragOKs]++;
.
286c
		ip->stats[FragCreates]++;
.
265,266c
				ip->stats[OutDiscards]++;
				ip->stats[FragFails]++;
.
224,225c
		ip->stats[FragFails]++;
		ip->stats[OutDiscards]++;
.
216,217c
		ip->stats[FragFails]++;
		ip->stats[OutDiscards]++;
.
164c
		ip->stats[OutNoRoutes]++;
.
157c
		ip->stats[OutDiscards]++;
.
149c
			ip->stats[OutDiscards]++;
.
141c
	ip->stats[OutRequests]++;
.
121c
		f->ip->stats[Forwarding] = 1;	
.
119c
		f->ip->stats[Forwarding] = 2;
.
82c
	ulong		stats[Nstats];
.
78a
static char *statnames[] =
{
[Forwarding]	"Forwarding",
[DefaultTTL]	"DefaultTTL",
[InReceives]	"InReceives",
[InHdrErrors]	"InHdrErrors",
[InAddrErrors]	"InAddrErrors",
[ForwDatagrams]	"ForwDatagrams",
[InUnknownProtos]	"InUnknownProtos",
[InDiscards]	"InDiscards",
[InDelivers]	"InDelivers",
[OutRequests]	"OutRequests",
[OutDiscards]	"OutDiscards",
[OutNoRoutes]	"OutNoRoutes",
[ReasmTimeout]	"ReasmTimeout",
[ReasmReqds]	"ReasmReqds",
[ReasmOKs]	"ReasmOKs",
[ReasmFails]	"ReasmFails",
[FragOKs]	"FragOKs",
[FragFails]	"FragFails",
[FragCreates]	"FragCreates",
};

.
58,76c
	Forwarding,
	DefaultTTL,
	InReceives,
	InHdrErrors,
	InAddrErrors,
	ForwDatagrams,
	InUnknownProtos,
	InDiscards,
	InDelivers,
	OutRequests,
	OutDiscards,
	OutNoRoutes,
	ReasmTimeout,
	ReasmReqds,
	ReasmOKs,
	ReasmFails,
	FragOKs,
	FragFails,
	FragCreates,

	Nstats,
.
55,56c
enum
.
## diffname ip/ip.c 2000/0905
## diff -e /n/emeliedump/2000/0706/sys/src/9/ip/ip.c /n/emeliedump/2000/0905/sys/src/9/ip/ip.c
18c
	IP_HLEN		= 0x05,		/* Header length in words */
.
## diffname ip/ip.c 2000/0913
## diff -e /n/emeliedump/2000/0905/sys/src/9/ip/ip.c /n/emeliedump/2000/0913/sys/src/9/ip/ip.c
221c
	medialen = ifc->maxmtu - ifc->m->hsize;
.
## diffname ip/ip.c 2000/1111
## diff -e /n/emeliedump/2000/0913/sys/src/9/ip/ip.c /n/emeliedump/2000/1111/sys/src/9/ip/ip.c
8c
#include	"../ip/ip.h"
.
## diffname ip/ip.c 2001/0430
## diff -e /n/emeliedump/2000/1111/sys/src/9/ip/ip.c /n/emeliedump/2001/0430/sys/src/9/ip/ip.c
268c
	if(gating)
		fragoff = nhgets(eh->frag);
	else
		fragoff = 0;
	dlen += fragoff;
	for(; fragoff < dlen; fragoff += seglen) {
.
226,227c
		if(!gating){
			eh->frag[0] = 0;
			eh->frag[1] = 0;
		}
.
209c
	if(!gating)
		eh->tos = tos;
.
## diffname ip/ip.c 2001/0623
## diff -e /n/emeliedump/2001/0430/sys/src/9/ip/ip.c /n/emeliedump/2001/0623/sys/src/9/ip/ip.c
458c
		(*p->rcv)(p, ifc, bp);
.
431c
			icmpttlexceeded(f, ifc, bp);
.
347c
ipiput(Fs *f, Ipifc *ifc, Block *bp)
.
## diffname ip/ip.c 2001/1007
## diff -e /n/emeliedump/2001/0623/sys/src/9/ip/ip.c /n/emeliedump/2001/1007/sys/src/9/ip/ip.c
272c
		fragoff = nhgets(eh->frag)<<3;
.
153c
	ulong fragoff;
.
## diffname ip/ip.c 2001/1117
## diff -e /n/emeliedump/2001/1007/sys/src/9/ip/ip.c /n/emeliedump/2001/1117/sys/src/9/ip/ip.c
717a
}

enum
{
	Nmtucache=	128,
};

typedef struct MTUcache MTUcache;

struct MTUcache
{
	uchar	ip[IPaddrlen];
	ulong	mtu;
	ulong	ms;
};

static struct {
	Lock;
	MTUcache c[Nmtucache];
} mc;

void
update_mtucache(uchar *ip, ulong mtu)
{
	MTUcache *oldest, *p;

	if(mtu < 512)
		return;

	lock(&mc);
	oldest = mc.c;
	for(p = mc.c; p < &mc.c[Nmtucache]; p++){
		if(ipcmp(ip, p->ip) == 0){
			p->mtu = mtu;
			p->ms = msec;
			break;
		}
		if(p->ms < oldest->ms)
			oldest = p;
	}
	if(p == &mc.c[Nmtucache]){
		ipmove(oldest->ip, ip);
		oldest->mtu = mtu;
		oldest->ms = msec;
	}
	unlock(&mc);
}

ulong
restrict_mtu(uchar *ip, ulong mtu)
{
	MTUcache *p;

	lock(&mc);
	for(p = mc.c; p < &mc.c[Nmtucache]; p++){
		if(p->ms + 1000*10*60 < msec){
			memset(p->ip, 0, sizeof(p->ip));
			p->ms = 0;
		}
		if(ipcmp(ip, p->ip) == 0){
			if(p->mtu < mtu)
				mtu = p->mtu;
			break;
		}
	}
	unlock(&mc);

	return mtu;
.
442,443c
	/* reassemble */
.
434a
		
		/* reassemble if the interface expects it */
		if(r->ifc->reassemble){
			frag = nhgets(h->frag);
			if(frag) {
				h->tos = 0;
				if(frag & IP_MF)
					h->tos = 1;
				bp = ipreassemble(ip, frag, bp, h);
				if(bp == nil)
					return;
				h = (Iphdr *)(bp->rp);
			}
		}
.
## diffname ip/ip.c 2002/0424
## diff -e /n/emeliedump/2001/1117/sys/src/9/ip/ip.c /n/emeliedump/2002/0424/sys/src/9/ip/ip.c
408a
			hnputs(h->length, olen-hl+(IP_HLEN<<2));
.
403a
			olen = nhgets(h->length);
.
356a
	int olen;
.
## diffname ip/ip.c 2002/0507
## diff -e /n/emeliedump/2002/0424/sys/src/9/ip/ip.c /n/emeliedump/2002/0507/sys/src/9/ip/ip.c
741,802d
736,739d
706,709c
	f = ip->fragfree4;
	ip->fragfree4 = f->next;
	f->next = ip->flisthead4;
	ip->flisthead4 = f;
.
704c
		ipfragfree4(ip, f);
.
702c
		for(f = ip->flisthead4; f->next; f = f->next)
.
700c
	while(ip->fragfree4 == nil) {
.
698c
	Fragment4 *f;
.
695,696c
Fragment4 *
ipfragallo4(IP *ip)
.
693c
 * ipfragallo4 - allocate a reassembly queue - assume hold fraglock4
.
687,688c
	frag->next = ip->fragfree4;
	ip->fragfree4 = frag;
.
678c
	l = &ip->flisthead4;
.
669c
	Fragment4 *fl, **l;
.
667c
ipfragfree4(IP *ip, Fragment4 *frag)
.
664c
 * ipfragfree4 - Free a list of fragments - assume hold fraglock4
.
659c
	qunlock(&ip->fraglock4);
.
653c
			qunlock(&ip->fraglock4);
.
650c
			ipfragfree4(ip, f);
.
644c
				bl->rp += IP4HDR;
.
614c
				memmove((*l)->rp + ovlap, (*l)->rp, IP4HDR);
.
590c
				qunlock(&ip->fraglock4);
.
567c
		qunlock(&ip->fraglock4);
.
560c
		f = ipfragallo4(ip);
.
556c
	BKFG(bp)->flen = nhgets(ih->length)-IP4HDR;
.
546c
		qunlock(&ip->fraglock4);
.
543c
			ipfragfree4(ip, f);
.
532c
			ipfragfree4(ip, f);
.
526,527c
	for(f = ip->flisthead4; f; f = fnext){
		fnext = f->next;	/* because ipfragfree4 changes the list */
.
521c
	qlock(&ip->fraglock4);
.
518c
		ih = (Ip4hdr*)(bp->rp);
.
504c
	Fragment4 *f, *fnext;
.
500c
ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
.
471c
	proto = h->proto;
	p = Fsrcvpcol(f, proto);
.
468c
		h = (Ip4hdr*)(bp->rp);
.
465c
		bp = ip4reassemble(ip, frag, bp, h);
.
459d
454,455c
		tos = h->tos;
		hop = h->ttl;
		ipoput4(f, bp, 1, hop - 1, tos);
.
449c
				h = (Ip4hdr*)(bp->rp);
.
446c
				bp = ip4reassemble(ip, frag, bp, h);
.
438c

.
434c
			icmpttlexceeded(f, ifc->lifc->local, bp);
.
432c
		hop = h->ttl;
		if(hop < 1) {
.
424a

.
421d
409,411c
			h = (Ip4hdr*)(bp->rp);
			h->vihl = (IP_VER4|IP_HLEN4);
			hnputs(h->length, olen-hl+(IP_HLEN4<<2));
.
406,407c
			dp = bp->rp + (hl - (IP_HLEN4<<2));
			memmove(dp, h, IP_HLEN4<<2);
.
403c
	  /* If this is not routed strip off the options */
.
397c
		if(hl < (IP_HLEN4<<2)) {
.
395c
	if((h->vihl&0x0F) != IP_HLEN4) {
.
390d
382a
	h = (Ip4hdr*)(bp->rp);

.
381d
373,374c
		if(hl < IP4HDR)
			hl = IP4HDR;
.
362,365d
358a
	if(BLKIPVER(bp) != IP_VER4) {
		ipiput6(f, ifc, bp);
		return;
	}

.
357d
350c
	int hop, tos, proto, olen;
	Ip4hdr *h;
.
331,348d
329c
ipiput4(Fs *f, Ipifc *ifc, Block *bp)
.
290c
		hnputs(feh->length, seglen + IP4HDR);
.
280,281c
		memmove(nb->wp, eh, IP4HDR);
		nb->wp += IP4HDR;
.
277,278c
		nb = allocb(IP4HDR+seglen);
		feh = (Ip4hdr*)(nb->rp);
.
264c
	offset = IP4HDR;
.
262c
		lid = incref(&ip->id4);
.
257c
	dlen = len - IP4HDR;
.
249c
	seglen = (medialen - IP4HDR) & ~7;
.
234,235d
225c
			hnputs(eh->id, incref(&ip->id4));
.
207c
		eh->vihl = IP_VER4|IP_HLEN4;
.
163c
	eh = (Ip4hdr*)(bp->rp);
.
155c
	Ip4hdr *eh, *feh;
.
149c
ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos)
.
135a

	ip_init_6(f);
.
128a
ip_init_6(Fs *f)
{
	v6params *v6p;

	v6p = smalloc(sizeof(v6params));
	
	v6p->rp.mflag		= 0;		// default not managed
	v6p->rp.oflag		= 0;
	v6p->rp.maxraint	= 600000;	// millisecs
	v6p->rp.minraint	= 200000;
	v6p->rp.linkmtu		= 0;		// no mtu sent
	v6p->rp.reachtime	= 0;
	v6p->rp.rxmitra		= 0;
	v6p->rp.ttl		= MAXTTL;
	v6p->rp.routerlt	= 3*(v6p->rp.maxraint);	

	v6p->hp.rxmithost	= 1000;		// v6 RETRANS_TIMER

	v6p->cdrouter 		= -1;

	f->v6p			= v6p;

}

void
initfrag(IP *ip, int size)
{
	Fragment4 *fq4, *eq4;
	Fragment6 *fq6, *eq6;

	ip->fragfree4 = (Fragment4*)malloc(sizeof(Fragment4) * size);
	if(ip->fragfree4 == nil)
		panic("initfrag");

	eq4 = &ip->fragfree4[size];
	for(fq4 = ip->fragfree4; fq4 < eq4; fq4++)
		fq4->next = fq4+1;

	ip->fragfree4[size-1].next = nil;

	ip->fragfree6 = (Fragment6*)malloc(sizeof(Fragment6) * size);
	if(ip->fragfree6 == nil)
		panic("initfrag");

	eq6 = &ip->fragfree6[size];
	for(fq6 = ip->fragfree6; fq6 < eq6; fq6++)
		fq6->next = fq6+1;

	ip->fragfree6[size-1].next = nil;
}

void
.
127a

.
124,126c
Block*		ip4reassemble(IP*, int, Block*, Ip4hdr*);
void		ipfragfree4(IP*, Fragment4*);
Fragment4*	ipfragallo4(IP*);
.
103,116c
#define BLKIP(xp)	((Ip4hdr*)((xp)->rp))
.
79a
struct Fragment4
{
	Block*	blist;
	Fragment4*	next;
	ulong 	src;
	ulong 	dst;
	ushort	id;
	ulong 	age;
};

struct Fragment6
{
	Block*	blist;
	Fragment6*	next;
	uchar 	src[IPaddrlen];
	uchar 	dst[IPaddrlen];
	uint	id;
	ulong 	age;
};

struct Ipfrag
{
	ushort	foff;
	ushort	flen;
};

/* an instance of IP */
struct IP
{
	ulong		stats[Nstats];

	QLock		fraglock4;
	Fragment4*	flisthead4;
	Fragment4*	fragfree4;
	Ref		id4;

	QLock		fraglock6;
	Fragment6*	flisthead6;
	Fragment6*	fragfree6;
	Ref		id6;

	int		iprouting;	/* true if we route like a gateway */
};

.
38,53d
31c
	uchar	ttl;      	/* Time to live */
.
24c
#define BLKIPVER(xp)	(((Ip4hdr*)((xp)->rp))->vihl&0xF0)

struct Ip4hdr
.
20a
	IP6FHDR		= 8, 		/* sizeof(Fraghdr6) */
.
16,18c
	IP4HDR		= 20,		/* sizeof(Ip4hdr) */
	IP6HDR		= 40,		/* sizeof(Ip6hdr) */
	IP_HLEN4	= 0x05,		/* Header length in words */
.
10,12c
typedef struct Ip4hdr		Ip4hdr;
typedef struct	IP	IP;
typedef struct	Fragment4	Fragment4;
typedef struct	Fragment6	Fragment6;
typedef struct	Ipfrag	Ipfrag;
.
8c
#include	"ip.h"
.
## diffname ip/ip.c 2002/0615
## diff -e /n/emeliedump/2002/0507/sys/src/9/ip/ip.c /n/emeliedump/2002/0615/sys/src/9/ip/ip.c
24c
	IP_MAX		= 64*1024,	/* Maximum Internet packet size */
.
## diffname ip/ip.c 2002/0710
## diff -e /n/emeliedump/2002/0615/sys/src/9/ip/ip.c /n/emeliedump/2002/0710/sys/src/9/ip/ip.c
768c
	f->age = NOW + 30000;
.
588c
		if(f->age < NOW){
.
## diffname ip/ip.c 2002/1204
## diff -e /n/emeliedump/2002/0710/sys/src/9/ip/ip.c /n/emeliedump/2002/1204/sys/src/9/ip/ip.c
317a
		icmpcantfrag(f, bp);
.
314a
if((eh->frag[0] & (IP_DF>>8)) && !gating) print("%V: DF set\n", eh->dst);

.
## diffname ip/ip.c 2002/1207
## diff -e /n/emeliedump/2002/1204/sys/src/9/ip/ip.c /n/emeliedump/2002/1207/sys/src/9/ip/ip.c
529a

	/* don't let any frag info go up the stack */
	h->frag[0] = 0;
	h->frag[1] = 0;
.
320c
		icmpcantfrag(f, bp, medialen);
.
## diffname ip/ip.c 2003/0209
## diff -e /n/emeliedump/2002/1207/sys/src/9/ip/ip.c /n/emeliedump/2003/0209/sys/src/9/ip/ip.c
297c
	medialen = ifc->maxtu - ifc->m->hsize;
.
## diffname ip/ip.c 2003/0213
## diff -e /n/emeliedump/2003/0209/sys/src/9/ip/ip.c /n/emeliedump/2003/0213/sys/src/9/ip/ip.c
444c
	if((bp->flag & Bipck) == 0 && ipcsum(&h->vihl)) {
.
## diffname ip/ip.c 2003/0214
## diff -e /n/emeliedump/2003/0213/sys/src/9/ip/ip.c /n/emeliedump/2003/0214/sys/src/9/ip/ip.c
264a
		if(!gating){
			freeblist(bp);	
			error("no route");
		}
.
233a
	Proto *pr;
.
## diffname ip/ip.c 2003/0216
## diff -e /n/emeliedump/2003/0214/sys/src/9/ip/ip.c /n/emeliedump/2003/0216/sys/src/9/ip/ip.c
267c
			freeblist(bp);
print("ipoput4: no route\n");
.
## diffname ip/ip.c 2003/0220
## diff -e /n/emeliedump/2003/0216/sys/src/9/ip/ip.c /n/emeliedump/2003/0220/sys/src/9/ip/ip.c
407c
	freeblist(bp);
	return rv;
.
318c
		return 0;
.
266,270c
		rv = -1;
.
234c
	int rv = 0;
.
223c
int
.
## diffname ip/ip.c 2003/0308
## diff -e /n/emeliedump/2003/0220/sys/src/9/ip/ip.c /n/emeliedump/2003/0308/sys/src/9/ip/ip.c
519c
		ipoput4(f, bp, 1, hop - 1, tos, &conv);
.
487c
		/* don't forward to source's network */
		conv.r = nil;
		r = v4lookup(f, h->dst, &conv);
		if(r != nil && r->ifc == ifc){
.
483,485d
478a
		Conv conv;

.
418c
	Route *r;
.
276c
		sr = v4lookup(f, eh->src, nil);
.
262c
	r = v4lookup(f, eh->dst, c);
.
224c
ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
.
## diffname ip/ip.c 2003/0318
## diff -e /n/emeliedump/2003/0308/sys/src/9/ip/ip.c /n/emeliedump/2003/0318/sys/src/9/ip/ip.c
504a
if(r->ifc == nil) panic("nil route rfc");
.
489c
		if(r == nil || r->ifc == ifc){
.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].