237 lines · 3.8 KB · C
RawDownload
#include "all.h" #include "../ip/ip.h" #define	DEBUG	if(cons.flags&Fip)print typedef	struct	Rock	Rock;typedef	struct	Frag	Frag; struct	Frag{	int	start;	int	end;}; struct	Rock{	uchar	src[Pasize];	uchar	dst[Pasize];	int	id;		/* src,dst,id are address of the rock */	Msgbuf*	mb;		/* reassembly. if 0, the rock is empty */	Timet	age;		/* timeout to throw away */	int	last;		/* set to data size when last frag arrives */	int	nfrag;	Frag	frag[Nfrag];}; staticstruct{	Lock;	Rock	rock[Nrock];} ip; voidipreceive(Enpkt *ep, int l, Ifc *ifc){	Ippkt *p;	Msgbuf *mb;	Rock *r, *or;	Frag *f;	int len, id, frag, off, loff, i, n;//	Ippkt pkt;	Timet t; 	p = (Ippkt*)ep;	if(l < Ensize+Ipsize) {		ifc->sumerr++;		print("ip: en too small\n");		return;	}	if(l > LARGEBUF) {		ifc->sumerr++;		print("ip: en too large\n");		return;	} //	memmove(&pkt, p, Ensize+Ipsize);	/* copy pkt to 'real' memory */	if(p->vihl != (IP_VER|IP_HLEN))		return;	if(!ipforme(p->dst, ifc))		return;//	if((m->flags & Bipck) == 0)	if(ipcsum(&p->vihl)) {		ifc->sumerr++;//		print("ip: checksum error (from %I)\n", p->src);		return;	} 	frag = nhgets(p->frag);	len = nhgets(p->length) - Ipsize;	id = nhgets(p->id); 	/*	 * total ip msg fits into one frag	 */	if((frag & ~IP_DF) == 0) {		mb = mballoc(l, 0, Mbip3);//		memmove(mb->data, &pkt, Ensize+Ipsize);//		memmove(mb->data + (Ensize+Ipsize),//			(uchar*)p + (Ensize+Ipsize), l-(Ensize+Ipsize));		memmove(mb->data, (uchar*)p, l);		goto send;	} 	/*	 * throw away old rocks.	 */	t = toytime();	lock(&ip);	r = ip.rock;	for(i=0; i<Nrock; i++,r++)		if(r->mb && t >= r->age) {			mbfree(r->mb);			r->mb = 0;		} 	/*	 * reassembly of fragments	 * look up rock by src, dst, id.	 */	or = 0;	r = ip.rock;	for(i=0; i<Nrock; i++,r++) {		if(r->mb == 0) {			if(or == 0)				or = r;			continue;		}		if(id == r->id)		if(memcmp(r->src, p->src, Pasize) == 0)		if(memcmp(r->dst, p->dst, Pasize) == 0)			goto found;	}	r = or;	if(r == 0) {		/* no available rocks */		r = ip.rock;		for(i=0; i<Nrock; i++,r++)			if(r->mb) {				mbfree(r->mb);				r->mb = 0;			}		r = ip.rock;	}	r->id = id;	r->mb = mballoc(LARGEBUF, 0, Mbip2);	memmove(r->src, p->src, Pasize);	memmove(r->dst, p->dst, Pasize);	r->nfrag = 0;	r->last = 0; found:	mb = r->mb;	r->age = t + SECOND(30); 	off = (frag & ~(IP_DF|IP_MF)) << 3;	if(len+off+Ensize+Ipsize > mb->count) {		/* ip pkt too big */		mbfree(mb);		r->mb = 0;		goto uout;	}	if(!(frag & IP_MF))		r->last = off+len;		/* found the end */ 	memmove(mb->data+(Ensize+Ipsize)+off,		(uchar*)p + (Ensize+Ipsize), len); 	/*	 * frag algorithm:	 * first entry is easy	 */	n = r->nfrag;	if(n == 0) {		r->frag[0].start = off;		r->frag[0].end = off+len;		r->nfrag = 1;		goto span;	} 	/*	 * two in a row is easy	 */	if(r->frag[n-1].end == off) {		r->frag[n-1].end += len;		goto span;	} 	/*	 * add this frag	 */	if(n >= Nfrag) {		/* too many frags */		mbfree(mb);		r->mb = 0;		goto uout;	}	r->frag[n].start = off;	r->frag[n].end = off+len;	n++;	r->nfrag = n; span:	/*	 * see if we span the whole list	 * can be O(n**2), but usually much smaller	 */	if(r->last == 0)		goto uout;	off = 0; spanloop:	loff = off;	f = r->frag;	for(i=0; i<n; i++,f++)		if(off >= f->start && off < f->end)			off = f->end;	if(loff == off)		goto uout;	if(off < r->last)		goto spanloop; 	memmove(mb->data, p, Ensize+Ipsize);	p = (Ippkt*)mb->data;	hnputs(p->length, r->last+Ipsize);	l = r->last + (Ensize+Ipsize);	mb->count = l;	r->mb = 0;	unlock(&ip); send:	switch(p->proto) {	default:		mbfree(mb);		break;	case Ilproto:		ilrecv(mb, ifc);		break;	case Udpproto:		udprecv(mb, ifc);		break;	case Icmpproto:		icmprecv(mb, ifc);		break;	case Igmpproto:		igmprecv(mb, ifc);		break;	case Tcpproto:		tcprecv(mb, ifc);		break;	}	return; uout:	unlock(&ip);}