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

2003/0216/ip/ip.c (diff list | history)

ip/ip.c on 1997/0327
1997/0327    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
 
2002/0507    
#include	"ip.h" 
1997/0327    
 
2002/0507    
typedef struct Ip4hdr		Ip4hdr; 
typedef struct	IP	IP; 
typedef struct	Fragment4	Fragment4; 
typedef struct	Fragment6	Fragment6; 
typedef struct	Ipfrag	Ipfrag; 
1997/0327    
 
enum 
{ 
2002/0507    
	IP4HDR		= 20,		/* sizeof(Ip4hdr) */ 
	IP6HDR		= 40,		/* sizeof(Ip6hdr) */ 
	IP_HLEN4	= 0x05,		/* Header length in words */ 
1997/0327    
	IP_DF		= 0x4000,	/* Don't fragment */ 
	IP_MF		= 0x2000,	/* More fragments */ 
2002/0507    
	IP6FHDR		= 8, 		/* sizeof(Fraghdr6) */ 
2002/0615    
	IP_MAX		= 64*1024,	/* Maximum Internet packet size */ 
1997/0327    
}; 
 
2002/0507    
#define BLKIPVER(xp)	(((Ip4hdr*)((xp)->rp))->vihl&0xF0) 
 
struct Ip4hdr 
1997/0327    
{ 
1998/0306    
	uchar	vihl;		/* Version and header length */ 
	uchar	tos;		/* Type of service */ 
	uchar	length[2];	/* packet length */ 
1998/0313    
	uchar	id[2];		/* ip->identification */ 
1998/0306    
	uchar	frag[2];	/* Fragment information */ 
2002/0507    
	uchar	ttl;      	/* Time to live */ 
1998/0306    
	uchar	proto;		/* Protocol */ 
	uchar	cksum[2];	/* Header checksum */ 
1998/0313    
	uchar	src[4];		/* IP source */ 
	uchar	dst[4];		/* IP destination */ 
1997/0327    
}; 
 
1998/0313    
/* MIB II counters */ 
2000/0706    
enum 
1998/0313    
{ 
2000/0706    
	Forwarding, 
	DefaultTTL, 
	InReceives, 
	InHdrErrors, 
	InAddrErrors, 
	ForwDatagrams, 
	InUnknownProtos, 
	InDiscards, 
	InDelivers, 
	OutRequests, 
	OutDiscards, 
	OutNoRoutes, 
	ReasmTimeout, 
	ReasmReqds, 
	ReasmOKs, 
	ReasmFails, 
	FragOKs, 
	FragFails, 
	FragCreates, 
 
	Nstats, 
1998/0313    
}; 
1997/0327    
 
2002/0507    
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 */ 
}; 
 
2000/0706    
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", 
}; 
 
2002/0507    
#define BLKIP(xp)	((Ip4hdr*)((xp)->rp)) 
1997/0327    
/* 
 * 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)) 
 
1998/0313    
ushort		ipcsum(uchar*); 
2002/0507    
Block*		ip4reassemble(IP*, int, Block*, Ip4hdr*); 
void		ipfragfree4(IP*, Fragment4*); 
Fragment4*	ipfragallo4(IP*); 
1998/0313    
 
2002/0507    
 
1998/0313    
void 
2002/0507    
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 
1998/0313    
ip_init(Fs *f) 
1997/0916    
{ 
1998/0313    
	IP *ip; 
1997/0916    
 
1998/0313    
	ip = smalloc(sizeof(IP)); 
	initfrag(ip, 100); 
	f->ip = ip; 
2002/0507    
 
	ip_init_6(f); 
1998/0313    
} 
1997/0327    
 
void 
1998/0314    
iprouting(Fs *f, int on) 
{ 
	f->ip->iprouting = on; 
1998/0813    
	if(f->ip->iprouting==0) 
2000/0706    
		f->ip->stats[Forwarding] = 2; 
1998/0813    
	else 
2000/0706    
		f->ip->stats[Forwarding] = 1;	 
1998/0314    
} 
 
void 
2002/0507    
ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos) 
1997/0327    
{ 
1998/0306    
	Ipifc *ifc; 
	uchar *gate; 
2001/1007    
	ulong fragoff; 
1997/0327    
	Block *xp, *nb; 
2002/0507    
	Ip4hdr *eh, *feh; 
1997/0327    
	int lid, len, seglen, chunk, dlen, blklen, offset, medialen; 
1998/0313    
	Route *r, *sr; 
	IP *ip; 
2003/0214    
	Proto *pr; 
1997/0327    
 
1998/0313    
	ip = f->ip; 
 
1997/0327    
	/* Fill out the ip header */ 
2002/0507    
	eh = (Ip4hdr*)(bp->rp); 
1997/0327    
 
2000/0706    
	ip->stats[OutRequests]++; 
1998/0313    
 
1998/0306    
	/* Number of uchars in data and ip header to write */ 
1997/0327    
	len = blocklen(bp); 
1998/0313    
 
1997/0327    
	if(gating){ 
		chunk = nhgets(eh->length); 
		if(chunk > len){ 
2000/0706    
			ip->stats[OutDiscards]++; 
1998/0313    
			netlog(f, Logip, "short gated packet\n"); 
1998/0308    
			goto free; 
1997/0327    
		} 
		if(chunk < len) 
			len = chunk; 
	} 
1998/0306    
	if(len >= IP_MAX){ 
2000/0706    
		ip->stats[OutDiscards]++; 
1998/0313    
		netlog(f, Logip, "exceeded ip max size %V\n", eh->dst); 
1998/0308    
		goto free; 
1997/0327    
	} 
 
1998/0313    
	r = v4lookup(f, eh->dst); 
1998/0306    
	if(r == nil){ 
2000/0706    
		ip->stats[OutNoRoutes]++; 
1998/0313    
		netlog(f, Logip, "no interface %V\n", eh->dst); 
2003/0214    
		if(!gating){ 
2003/0216    
			freeblist(bp); 
print("ipoput4: no route\n"); 
2003/0214    
			error("no route"); 
		} 
1998/0308    
		goto free; 
1997/0327    
	} 
1998/0313    
 
	ifc = r->ifc; 
	if(r->type & (Rifc|Runi)) 
1998/0306    
		gate = eh->dst; 
	else 
1998/0313    
	if(r->type & (Rbcast|Rmulti)) { 
		gate = eh->dst; 
		sr = v4lookup(f, eh->src); 
		if(sr != nil && (sr->type & Runi)) 
			ifc = sr->ifc; 
	} 
	else 
1998/0306    
		gate = r->v4.gate; 
1998/0313    
 
1999/10041    
	if(!gating) 
2002/0507    
		eh->vihl = IP_VER4|IP_HLEN4; 
1999/10041    
	eh->ttl = ttl; 
2001/0430    
	if(!gating) 
		eh->tos = tos; 
1997/0327    
 
1999/0302    
	if(!canrlock(ifc)) 
		goto free; 
1998/0307    
	if(waserror()){ 
		runlock(ifc); 
		nexterror(); 
	} 
	if(ifc->m == nil) 
		goto raise; 
 
1997/0327    
	/* If we dont need to fragment just send it */ 
2003/0209    
	medialen = ifc->maxtu - ifc->m->hsize; 
1997/0327    
	if(len <= medialen) { 
		if(!gating) 
2002/0507    
			hnputs(eh->id, incref(&ip->id4)); 
1997/0327    
		hnputs(eh->length, len); 
2001/0430    
		if(!gating){ 
			eh->frag[0] = 0; 
			eh->frag[1] = 0; 
		} 
1997/0327    
		eh->cksum[0] = 0; 
		eh->cksum[1] = 0; 
		hnputs(eh->cksum, ipcsum(&eh->vihl)); 
1998/0306    
		ifc->m->bwrite(ifc, bp, V4, gate); 
1998/0307    
		runlock(ifc); 
		poperror(); 
1997/0327    
		return; 
	} 
 
2002/1204    
if((eh->frag[0] & (IP_DF>>8)) && !gating) print("%V: DF set\n", eh->dst); 
 
1997/0327    
	if(eh->frag[0] & (IP_DF>>8)){ 
2000/0706    
		ip->stats[FragFails]++; 
		ip->stats[OutDiscards]++; 
2002/1207    
		icmpcantfrag(f, bp, medialen); 
1998/0313    
		netlog(f, Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst); 
1997/0327    
		goto raise; 
	} 
 
2002/0507    
	seglen = (medialen - IP4HDR) & ~7; 
1997/0327    
	if(seglen < 8){ 
2000/0706    
		ip->stats[FragFails]++; 
		ip->stats[OutDiscards]++; 
1998/0313    
		netlog(f, Logip, "%V seglen < 8\n", eh->dst); 
1997/0327    
		goto raise; 
	} 
 
2002/0507    
	dlen = len - IP4HDR; 
1997/0327    
	xp = bp; 
	if(gating) 
		lid = nhgets(eh->id); 
	else 
2002/0507    
		lid = incref(&ip->id4); 
1997/0327    
 
2002/0507    
	offset = IP4HDR; 
1997/0327    
	while(xp != nil && offset && offset >= BLEN(xp)) { 
		offset -= BLEN(xp); 
		xp = xp->next; 
	} 
	xp->rp += offset; 
 
2001/0430    
	if(gating) 
2001/1007    
		fragoff = nhgets(eh->frag)<<3; 
2001/0430    
	else 
		fragoff = 0; 
	dlen += fragoff; 
	for(; fragoff < dlen; fragoff += seglen) { 
2002/0507    
		nb = allocb(IP4HDR+seglen); 
		feh = (Ip4hdr*)(nb->rp); 
1997/0327    
 
2002/0507    
		memmove(nb->wp, eh, IP4HDR); 
		nb->wp += IP4HDR; 
1997/0327    
 
		if((fragoff + seglen) >= dlen) { 
			seglen = dlen - fragoff; 
			hnputs(feh->frag, fragoff>>3); 
		} 
		else	 
			hnputs(feh->frag, (fragoff>>3)|IP_MF); 
 
2002/0507    
		hnputs(feh->length, seglen + IP4HDR); 
1997/0327    
		hnputs(feh->id, lid); 
 
		/* Copy up the data area */ 
		chunk = seglen; 
		while(chunk) { 
			if(!xp) { 
2000/0706    
				ip->stats[OutDiscards]++; 
				ip->stats[FragFails]++; 
1997/0327    
				freeblist(nb); 
1998/0313    
				netlog(f, Logip, "!xp: chunk %d\n", chunk); 
1997/0327    
				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; 
1998/0313    
		}  
1997/0327    
 
		feh->cksum[0] = 0; 
		feh->cksum[1] = 0; 
		hnputs(feh->cksum, ipcsum(&feh->vihl)); 
1998/0306    
		ifc->m->bwrite(ifc, nb, V4, gate); 
2000/0706    
		ip->stats[FragCreates]++; 
1997/0327    
	} 
2000/0706    
	ip->stats[FragOKs]++; 
1997/0327    
raise: 
1998/0307    
	runlock(ifc); 
	poperror(); 
1998/0308    
free: 
1997/0327    
	freeblist(bp);	 
} 
 
void 
2002/0507    
ipiput4(Fs *f, Ipifc *ifc, Block *bp) 
1997/0327    
{ 
1998/0313    
	int hl; 
2002/0507    
	int hop, tos, proto, olen; 
	Ip4hdr *h; 
1997/0327    
	Proto *p; 
	ushort frag; 
	int notforme; 
1998/0313    
	uchar *dp, v6dst[IPaddrlen]; 
	IP *ip; 
1998/1209    
	Route *r, *sr; 
1997/0327    
 
2002/0507    
	if(BLKIPVER(bp) != IP_VER4) { 
		ipiput6(f, ifc, bp); 
		return; 
	} 
 
1998/0313    
	ip = f->ip; 
2000/0706    
	ip->stats[InReceives]++; 
1998/0313    
 
1998/0326    
	/* 
1998/0331    
	 *  Ensure we have all the header info in the first 
1998/0326    
	 *  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); 
2002/0507    
		if(hl < IP4HDR) 
			hl = IP4HDR; 
1998/0326    
		if(hl > 64) 
			hl = 64; 
		bp = pullupblock(bp, hl); 
1997/0327    
		if(bp == nil) 
			return; 
	} 
 
2002/0507    
	h = (Ip4hdr*)(bp->rp); 
 
1998/0306    
	/* dump anything that whose header doesn't checksum */ 
2003/0213    
	if((bp->flag & Bipck) == 0 && ipcsum(&h->vihl)) { 
2000/0706    
		ip->stats[InHdrErrors]++; 
1998/1208    
		netlog(f, Logip, "ip: checksum error %V\n", h->src); 
1997/0327    
		freeblist(bp); 
		return; 
	} 
1998/0306    
	v4tov6(v6dst, h->dst); 
1998/0313    
	notforme = ipforme(f, v6dst) == 0; 
 
	/* Check header length and version */ 
2002/0507    
	if((h->vihl&0x0F) != IP_HLEN4) { 
1998/0313    
		hl = (h->vihl&0xF)<<2; 
2002/0507    
		if(hl < (IP_HLEN4<<2)) { 
2000/0706    
			ip->stats[InHdrErrors]++; 
1998/0313    
			netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl); 
			freeblist(bp); 
			return; 
		} 
2002/0507    
	  /* If this is not routed strip off the options */ 
1998/0313    
		if(notforme == 0) { 
2002/0424    
			olen = nhgets(h->length); 
2002/0507    
			dp = bp->rp + (hl - (IP_HLEN4<<2)); 
			memmove(dp, h, IP_HLEN4<<2); 
1998/0313    
			bp->rp = dp; 
2002/0507    
			h = (Ip4hdr*)(bp->rp); 
			h->vihl = (IP_VER4|IP_HLEN4); 
			hnputs(h->length, olen-hl+(IP_HLEN4<<2)); 
1998/0313    
		} 
	} 
 
	/* route */ 
1998/0306    
	if(notforme) { 
1998/1209    
		if(!ip->iprouting){ 
2000/0220    
			freeb(bp); 
1998/1209    
			return; 
		} 
		/* don't forward to source's network */ 
		sr = v4lookup(f, h->src); 
		r = v4lookup(f, h->dst); 
2002/0507    
 
1998/1209    
		if(r == nil || sr == r){ 
2000/0706    
			ip->stats[OutDiscards]++; 
1998/1209    
			freeblist(bp); 
			return; 
		} 
 
		/* don't forward if packet has timed out */ 
2002/0507    
		hop = h->ttl; 
		if(hop < 1) { 
2000/0706    
			ip->stats[InHdrErrors]++; 
2002/0507    
			icmpttlexceeded(f, ifc->lifc->local, bp); 
1998/1209    
			freeblist(bp); 
			return; 
		} 
2002/0507    
 
2001/1117    
		/* 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; 
2002/0507    
				bp = ip4reassemble(ip, frag, bp, h); 
2001/1117    
				if(bp == nil) 
					return; 
2002/0507    
				h = (Ip4hdr*)(bp->rp); 
2001/1117    
			} 
		} 
1998/1209    
 
2000/0706    
		ip->stats[ForwDatagrams]++; 
2002/0507    
		tos = h->tos; 
		hop = h->ttl; 
		ipoput4(f, bp, 1, hop - 1, tos); 
1998/0306    
		return; 
	} 
 
1997/0327    
	frag = nhgets(h->frag); 
	if(frag) { 
		h->tos = 0; 
		if(frag & IP_MF) 
			h->tos = 1; 
2002/0507    
		bp = ip4reassemble(ip, frag, bp, h); 
1997/0327    
		if(bp == nil) 
			return; 
2002/0507    
		h = (Ip4hdr*)(bp->rp); 
1997/0327    
	} 
2002/1207    
 
	/* don't let any frag info go up the stack */ 
	h->frag[0] = 0; 
	h->frag[1] = 0; 
1997/0327    
 
2002/0507    
	proto = h->proto; 
	p = Fsrcvpcol(f, proto); 
1998/0313    
	if(p != nil && p->rcv != nil) { 
2000/0706    
		ip->stats[InDelivers]++; 
2001/0623    
		(*p->rcv)(p, ifc, bp); 
1998/0313    
		return; 
	} 
2000/0706    
	ip->stats[InDiscards]++; 
	ip->stats[InUnknownProtos]++; 
1998/0313    
	freeblist(bp); 
1997/0327    
} 
 
int 
1998/0313    
ipstats(Fs *f, char *buf, int len) 
1997/0327    
{ 
1998/0313    
	IP *ip; 
2000/0706    
	char *p, *e; 
	int i; 
1997/0327    
 
1998/0313    
	ip = f->ip; 
2000/0706    
	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; 
1997/0327    
} 
 
Block* 
2002/0507    
ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih) 
1997/0327    
{ 
	int fend; 
	ushort id; 
2002/0507    
	Fragment4 *f, *fnext; 
1998/0306    
	ulong src, dst; 
1997/0327    
	Block *bl, **l, *last, *prev; 
	int ovlap, len, fragsize, pktposn; 
 
1998/0313    
	src = nhgetl(ih->src); 
	dst = nhgetl(ih->dst); 
	id = nhgets(ih->id); 
1997/0327    
 
	/* 
	 *  block lists are too hard, pullupblock into a single block 
	 */ 
	if(bp->next){ 
		bp = pullupblock(bp, blocklen(bp)); 
2002/0507    
		ih = (Ip4hdr*)(bp->rp); 
1997/0327    
	} 
 
2002/0507    
	qlock(&ip->fraglock4); 
1997/0327    
 
	/* 
	 *  find a reassembly queue for this fragment 
	 */ 
2002/0507    
	for(f = ip->flisthead4; f; f = fnext){ 
		fnext = f->next;	/* because ipfragfree4 changes the list */ 
1997/0327    
		if(f->src == src && f->dst == dst && f->id == id) 
			break; 
2002/0710    
		if(f->age < NOW){ 
2000/0706    
			ip->stats[ReasmTimeout]++; 
2002/0507    
			ipfragfree4(ip, f); 
1997/0916    
		} 
1997/0327    
	} 
 
	/* 
	 *  if this isn't a fragmented packet, accept it 
	 *  and get rid of any fragments that might go 
	 *  with it. 
	 */ 
1998/0313    
	if(!ih->tos && (offset & ~(IP_MF|IP_DF)) == 0) { 
		if(f != nil) { 
2002/0507    
			ipfragfree4(ip, f); 
2000/0706    
			ip->stats[ReasmFails]++; 
1998/0313    
		} 
2002/0507    
		qunlock(&ip->fraglock4); 
1997/0327    
		return bp; 
	} 
 
1997/0504    
	if(bp->base+sizeof(Ipfrag) >= bp->rp){ 
		bp = padblock(bp, sizeof(Ipfrag)); 
		bp->rp += sizeof(Ipfrag); 
	} 
1997/0327    
 
	BKFG(bp)->foff = offset<<3; 
2002/0507    
	BKFG(bp)->flen = nhgets(ih->length)-IP4HDR; 
1997/0327    
 
	/* First fragment allocates a reassembly queue */ 
	if(f == nil) { 
2002/0507    
		f = ipfragallo4(ip); 
1997/0327    
		f->id = id; 
		f->src = src; 
		f->dst = dst; 
 
		f->blist = bp; 
 
2002/0507    
		qunlock(&ip->fraglock4); 
2000/0706    
		ip->stats[ReasmReqds]++; 
1997/0327    
		return nil; 
	} 
 
	/* 
	 *  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); 
2002/0507    
				qunlock(&ip->fraglock4); 
1997/0327    
				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; 
1998/0313    
				/* move up ih hdrs */ 
2002/0507    
				memmove((*l)->rp + ovlap, (*l)->rp, IP4HDR); 
1997/0327    
				(*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; 
2002/0507    
				bl->rp += IP4HDR; 
1997/0327    
				bl->wp = bl->rp + fragsize; 
			} 
 
			bl = f->blist; 
			f->blist = nil; 
2002/0507    
			ipfragfree4(ip, f); 
1998/0313    
			ih = BLKIP(bl); 
			hnputs(ih->length, len); 
2002/0507    
			qunlock(&ip->fraglock4); 
2000/0706    
			ip->stats[ReasmOKs]++; 
1997/0327    
			return bl;		 
		} 
		pktposn += BKFG(bl)->flen; 
	} 
2002/0507    
	qunlock(&ip->fraglock4); 
1997/0327    
	return nil; 
} 
 
/* 
2002/0507    
 * ipfragfree4 - Free a list of fragments - assume hold fraglock4 
1997/0327    
 */ 
void 
2002/0507    
ipfragfree4(IP *ip, Fragment4 *frag) 
1997/0327    
{ 
2002/0507    
	Fragment4 *fl, **l; 
1997/0327    
 
	if(frag->blist) 
		freeblist(frag->blist); 
 
	frag->src = 0; 
	frag->id = 0; 
	frag->blist = nil; 
 
2002/0507    
	l = &ip->flisthead4; 
1997/0327    
	for(fl = *l; fl; fl = fl->next) { 
		if(fl == frag) { 
			*l = frag->next; 
			break; 
		} 
		l = &fl->next; 
	} 
 
2002/0507    
	frag->next = ip->fragfree4; 
	ip->fragfree4 = frag; 
1997/0327    
 
} 
 
/* 
2002/0507    
 * ipfragallo4 - allocate a reassembly queue - assume hold fraglock4 
1997/0327    
 */ 
2002/0507    
Fragment4 * 
ipfragallo4(IP *ip) 
1997/0327    
{ 
2002/0507    
	Fragment4 *f; 
1997/0327    
 
2002/0507    
	while(ip->fragfree4 == nil) { 
1997/0529    
		/* free last entry on fraglist */ 
2002/0507    
		for(f = ip->flisthead4; f->next; f = f->next) 
1997/0529    
			; 
2002/0507    
		ipfragfree4(ip, f); 
1997/0327    
	} 
2002/0507    
	f = ip->fragfree4; 
	ip->fragfree4 = f->next; 
	f->next = ip->flisthead4; 
	ip->flisthead4 = f; 
2002/0710    
	f->age = NOW + 30000; 
1997/0327    
 
	return f; 
} 
 
ushort 
1998/0306    
ipcsum(uchar *addr) 
1997/0327    
{ 
	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); 
2001/1117    
} 
 
 


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