xref: /plan9/sys/src/libventi/packet.c (revision 9ba92a1a1d8a653f6050241dbdbd039f2ecb1dc2)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <venti.h>
4368c31abSDavid du Colombier #include <libsec.h>
59a747e4fSDavid du Colombier 
6368c31abSDavid du Colombier typedef struct Mem Mem;
7368c31abSDavid du Colombier typedef struct Frag Frag;
89a747e4fSDavid du Colombier 
9368c31abSDavid du Colombier enum {
10368c31abSDavid du Colombier 	BigMemSize = MaxFragSize,
11368c31abSDavid du Colombier 	SmallMemSize = BigMemSize/8,
12368c31abSDavid du Colombier 	NLocalFrag = 2
13368c31abSDavid du Colombier };
14368c31abSDavid du Colombier 
15368c31abSDavid du Colombier /* position to carve out of a Mem */
16368c31abSDavid du Colombier enum {
17368c31abSDavid du Colombier 	PFront,
18368c31abSDavid du Colombier 	PMiddle,
19368c31abSDavid du Colombier 	PEnd
20368c31abSDavid du Colombier };
21368c31abSDavid du Colombier 
22368c31abSDavid du Colombier struct Mem
23368c31abSDavid du Colombier {
24368c31abSDavid du Colombier 	Lock lk;
25368c31abSDavid du Colombier 	int ref;
26368c31abSDavid du Colombier 	uchar *bp;
27368c31abSDavid du Colombier 	uchar *ep;
28368c31abSDavid du Colombier 	uchar *rp;
29368c31abSDavid du Colombier 	uchar *wp;
30368c31abSDavid du Colombier 	Mem *next;
31368c31abSDavid du Colombier };
32368c31abSDavid du Colombier 
33368c31abSDavid du Colombier enum {
34368c31abSDavid du Colombier 	FragLocalFree,
35368c31abSDavid du Colombier 	FragLocalAlloc,
36368c31abSDavid du Colombier 	FragGlobal
37368c31abSDavid du Colombier };
38368c31abSDavid du Colombier 
39368c31abSDavid du Colombier struct Frag
40368c31abSDavid du Colombier {
41368c31abSDavid du Colombier 	int state;
42368c31abSDavid du Colombier 	Mem *mem;
43368c31abSDavid du Colombier 	uchar *rp;
44368c31abSDavid du Colombier 	uchar *wp;
45368c31abSDavid du Colombier 	Frag *next;
46368c31abSDavid du Colombier 	void (*free)(void*);
47368c31abSDavid du Colombier 	void *a;
48368c31abSDavid du Colombier 	Packet *p;	/* parent packet, for debugging only */
49368c31abSDavid du Colombier };
50368c31abSDavid du Colombier 
51368c31abSDavid du Colombier struct Packet
52368c31abSDavid du Colombier {
53368c31abSDavid du Colombier 	int size;
54368c31abSDavid du Colombier 	int asize;  /* allocated memory - greater than size unless foreign frags */
55368c31abSDavid du Colombier 	ulong pc;
56368c31abSDavid du Colombier 
57368c31abSDavid du Colombier 	Packet *next;
58368c31abSDavid du Colombier 
59368c31abSDavid du Colombier 	Frag *first;
60368c31abSDavid du Colombier 	Frag *last;
61368c31abSDavid du Colombier 
62368c31abSDavid du Colombier 	Frag local[NLocalFrag];
63368c31abSDavid du Colombier };
64368c31abSDavid du Colombier 
65368c31abSDavid du Colombier static Frag *fragalloc(Packet*, int n, int pos, Frag *next);
66368c31abSDavid du Colombier static Frag *fragdup(Packet*, Frag*);
67368c31abSDavid du Colombier static void fragfree(Frag*);
68368c31abSDavid du Colombier 
69368c31abSDavid du Colombier static Mem *memalloc(int, int);
70368c31abSDavid du Colombier static void memfree(Mem*);
71368c31abSDavid du Colombier static int memhead(Mem *m, uchar *rp, int n);
72368c31abSDavid du Colombier static int memtail(Mem *m, uchar *wp, int n);
739a747e4fSDavid du Colombier 
749a747e4fSDavid du Colombier static char EPacketSize[] = "bad packet size";
759a747e4fSDavid du Colombier static char EPacketOffset[] = "bad packet offset";
769a747e4fSDavid du Colombier static char EBadSize[] = "bad size";
779a747e4fSDavid du Colombier 
78368c31abSDavid du Colombier #ifdef NOTDEF
79368c31abSDavid du Colombier static void checkpacket(Packet*);
80368c31abSDavid du Colombier #endif
81368c31abSDavid du Colombier 
82368c31abSDavid du Colombier /*
83368c31abSDavid du Colombier  * the free list is primarily for speed, but it is
84368c31abSDavid du Colombier  * also necessary for packetsplit that packets
85368c31abSDavid du Colombier  * are never freed -- a packet can contain a different
86368c31abSDavid du Colombier  * packet's local fragments, thanks to packetsplit!
87368c31abSDavid du Colombier  */
889a747e4fSDavid du Colombier static struct {
899a747e4fSDavid du Colombier 	Lock lk;
909a747e4fSDavid du Colombier 	Packet *packet;
919a747e4fSDavid du Colombier 	int npacket;
929a747e4fSDavid du Colombier 	Frag *frag;
939a747e4fSDavid du Colombier 	int nfrag;
94368c31abSDavid du Colombier 	Mem *bigmem;
95368c31abSDavid du Colombier 	int nbigmem;
96368c31abSDavid du Colombier 	Mem *smallmem;
97368c31abSDavid du Colombier 	int nsmallmem;
98368c31abSDavid du Colombier } freelist;
999a747e4fSDavid du Colombier 
1009a747e4fSDavid du Colombier #define FRAGSIZE(f) ((f)->wp - (f)->rp)
101368c31abSDavid du Colombier #define FRAGASIZE(f) ((f)->mem ? (f)->mem->ep - (f)->mem->bp : 0)
1029a747e4fSDavid du Colombier 
103368c31abSDavid du Colombier #define NOTFREE(p) assert((p)->size>=0)/*; checkpacket(p)*/
1049a747e4fSDavid du Colombier 
1059a747e4fSDavid du Colombier Packet *
packetalloc(void)106368c31abSDavid du Colombier packetalloc(void)
1079a747e4fSDavid du Colombier {
1089a747e4fSDavid du Colombier 	Packet *p;
1099a747e4fSDavid du Colombier 
110368c31abSDavid du Colombier 	lock(&freelist.lk);
111368c31abSDavid du Colombier 	p = freelist.packet;
1129a747e4fSDavid du Colombier 	if(p != nil)
113368c31abSDavid du Colombier 		freelist.packet = p->next;
1149a747e4fSDavid du Colombier 	else
115368c31abSDavid du Colombier 		freelist.npacket++;
116368c31abSDavid du Colombier 	unlock(&freelist.lk);
1179a747e4fSDavid du Colombier 
1189a747e4fSDavid du Colombier 	if(p == nil)
119368c31abSDavid du Colombier 		p = vtbrk(sizeof(Packet));
1209a747e4fSDavid du Colombier 	else
1219a747e4fSDavid du Colombier 		assert(p->size == -1);
1229a747e4fSDavid du Colombier 	p->size = 0;
1239a747e4fSDavid du Colombier 	p->asize = 0;
1249a747e4fSDavid du Colombier 	p->first = nil;
1259a747e4fSDavid du Colombier 	p->last = nil;
1269a747e4fSDavid du Colombier 	p->next = nil;
127368c31abSDavid du Colombier 	p->pc = getcallerpc((char*)&p+8);	/* might not work, but fine */
1289a747e4fSDavid du Colombier 
129368c31abSDavid du Colombier 	NOTFREE(p);
1309a747e4fSDavid du Colombier 	return p;
1319a747e4fSDavid du Colombier }
1329a747e4fSDavid du Colombier 
1339a747e4fSDavid du Colombier void
packetfree(Packet * p)134368c31abSDavid du Colombier packetfree(Packet *p)
1359a747e4fSDavid du Colombier {
1369a747e4fSDavid du Colombier 	Frag *f, *ff;
1379a747e4fSDavid du Colombier 
138368c31abSDavid du Colombier 	if(p == nil)
139368c31abSDavid du Colombier 		return;
1409a747e4fSDavid du Colombier 
1419a747e4fSDavid du Colombier 	NOTFREE(p);
142368c31abSDavid du Colombier 	p->pc = getcallerpc(&p);
1439a747e4fSDavid du Colombier 
1449a747e4fSDavid du Colombier 	for(f=p->first; f!=nil; f=ff) {
1459a747e4fSDavid du Colombier 		ff = f->next;
146368c31abSDavid du Colombier 		fragfree(f);
1479a747e4fSDavid du Colombier 	}
148368c31abSDavid du Colombier 	p->first = (void*)0xDeadBeef;
149368c31abSDavid du Colombier 	p->last = (void*)0xDeadBeef;
150368c31abSDavid du Colombier 	p->size = -1;
1519a747e4fSDavid du Colombier 
152368c31abSDavid du Colombier 	lock(&freelist.lk);
153368c31abSDavid du Colombier 	p->next = freelist.packet;
154368c31abSDavid du Colombier 	freelist.packet = p;
155368c31abSDavid du Colombier 	unlock(&freelist.lk);
1569a747e4fSDavid du Colombier }
1579a747e4fSDavid du Colombier 
1589a747e4fSDavid du Colombier Packet *
packetdup(Packet * p,int offset,int n)159368c31abSDavid du Colombier packetdup(Packet *p, int offset, int n)
1609a747e4fSDavid du Colombier {
1619a747e4fSDavid du Colombier 	Frag *f, *ff;
1629a747e4fSDavid du Colombier 	Packet *pp;
1639a747e4fSDavid du Colombier 
1649a747e4fSDavid du Colombier 	NOTFREE(p);
1659a747e4fSDavid du Colombier 	if(offset < 0 || n < 0 || offset+n > p->size) {
166368c31abSDavid du Colombier 		werrstr(EBadSize);
1679a747e4fSDavid du Colombier 		return nil;
1689a747e4fSDavid du Colombier 	}
1699a747e4fSDavid du Colombier 
170368c31abSDavid du Colombier 	pp = packetalloc();
171368c31abSDavid du Colombier 	pp->pc = getcallerpc(&p);
172368c31abSDavid du Colombier 	if(n == 0){
173368c31abSDavid du Colombier 		NOTFREE(pp);
1749a747e4fSDavid du Colombier 		return pp;
175368c31abSDavid du Colombier 	}
1769a747e4fSDavid du Colombier 
1779a747e4fSDavid du Colombier 	pp->size = n;
1789a747e4fSDavid du Colombier 
1799a747e4fSDavid du Colombier 	/* skip offset */
1809a747e4fSDavid du Colombier 	for(f=p->first; offset >= FRAGSIZE(f); f=f->next)
1819a747e4fSDavid du Colombier 		offset -= FRAGSIZE(f);
1829a747e4fSDavid du Colombier 
1839a747e4fSDavid du Colombier 	/* first frag */
184368c31abSDavid du Colombier 	ff = fragdup(pp, f);
1859a747e4fSDavid du Colombier 	ff->rp += offset;
1869a747e4fSDavid du Colombier 	pp->first = ff;
1879a747e4fSDavid du Colombier 	n -= FRAGSIZE(ff);
1889a747e4fSDavid du Colombier 	pp->asize += FRAGASIZE(ff);
1899a747e4fSDavid du Colombier 
1909a747e4fSDavid du Colombier 	/* the remaining */
1919a747e4fSDavid du Colombier 	while(n > 0) {
1929a747e4fSDavid du Colombier 		f = f->next;
193368c31abSDavid du Colombier 		ff->next = fragdup(pp, f);
1949a747e4fSDavid du Colombier 		ff = ff->next;
1959a747e4fSDavid du Colombier 		n -= FRAGSIZE(ff);
1969a747e4fSDavid du Colombier 		pp->asize += FRAGASIZE(ff);
1979a747e4fSDavid du Colombier 	}
1989a747e4fSDavid du Colombier 
1999a747e4fSDavid du Colombier 	/* fix up last frag: note n <= 0 */
2009a747e4fSDavid du Colombier 	ff->wp += n;
2019a747e4fSDavid du Colombier 	ff->next = nil;
2029a747e4fSDavid du Colombier 	pp->last = ff;
2039a747e4fSDavid du Colombier 
204368c31abSDavid du Colombier 	NOTFREE(pp);
205368c31abSDavid du Colombier 	NOTFREE(p);
2069a747e4fSDavid du Colombier 	return pp;
2079a747e4fSDavid du Colombier }
2089a747e4fSDavid du Colombier 
2099a747e4fSDavid du Colombier Packet *
packetsplit(Packet * p,int n)210368c31abSDavid du Colombier packetsplit(Packet *p, int n)
2119a747e4fSDavid du Colombier {
2129a747e4fSDavid du Colombier 	Packet *pp;
2139a747e4fSDavid du Colombier 	Frag *f, *ff;
2149a747e4fSDavid du Colombier 
2159a747e4fSDavid du Colombier 	NOTFREE(p);
2169a747e4fSDavid du Colombier 	if(n < 0 || n > p->size) {
217368c31abSDavid du Colombier 		werrstr(EPacketSize);
2189a747e4fSDavid du Colombier 		return nil;
2199a747e4fSDavid du Colombier 	}
2209a747e4fSDavid du Colombier 
221368c31abSDavid du Colombier 	pp = packetalloc();
222368c31abSDavid du Colombier 	pp->pc = getcallerpc(&p);
223368c31abSDavid du Colombier 	if(n == 0){
224368c31abSDavid du Colombier 		NOTFREE(pp);
2259a747e4fSDavid du Colombier 		return pp;
226368c31abSDavid du Colombier 	}
2279a747e4fSDavid du Colombier 
2289a747e4fSDavid du Colombier 	pp->size = n;
2299a747e4fSDavid du Colombier 	p->size -= n;
2309a747e4fSDavid du Colombier 	ff = nil;
2319a747e4fSDavid du Colombier 	for(f=p->first; n > 0 && n >= FRAGSIZE(f); f=f->next) {
2329a747e4fSDavid du Colombier 		n -= FRAGSIZE(f);
2339a747e4fSDavid du Colombier 		p->asize -= FRAGASIZE(f);
2349a747e4fSDavid du Colombier 		pp->asize += FRAGASIZE(f);
235368c31abSDavid du Colombier 		f->p = pp;
2369a747e4fSDavid du Colombier 		ff = f;
2379a747e4fSDavid du Colombier 	}
2389a747e4fSDavid du Colombier 
2399a747e4fSDavid du Colombier 	/* split shared frag */
2409a747e4fSDavid du Colombier 	if(n > 0) {
241368c31abSDavid du Colombier 		f->p = pp;
2429a747e4fSDavid du Colombier 		ff = f;
243368c31abSDavid du Colombier 		f = fragdup(p, ff);
2449a747e4fSDavid du Colombier 		pp->asize += FRAGASIZE(ff);
2459a747e4fSDavid du Colombier 		ff->wp = ff->rp + n;
2469a747e4fSDavid du Colombier 		f->rp += n;
2479a747e4fSDavid du Colombier 	}
2489a747e4fSDavid du Colombier 
2499a747e4fSDavid du Colombier 	pp->first = p->first;
2509a747e4fSDavid du Colombier 	pp->last = ff;
251368c31abSDavid du Colombier 	ff->next = nil;
2529a747e4fSDavid du Colombier 	p->first = f;
253368c31abSDavid du Colombier 	if(f == nil || f->next == nil)
254368c31abSDavid du Colombier 		p->last = f;
255368c31abSDavid du Colombier 	NOTFREE(pp);
256368c31abSDavid du Colombier 	NOTFREE(p);
2579a747e4fSDavid du Colombier 	return pp;
2589a747e4fSDavid du Colombier }
2599a747e4fSDavid du Colombier 
2609a747e4fSDavid du Colombier int
packetconsume(Packet * p,uchar * buf,int n)261368c31abSDavid du Colombier packetconsume(Packet *p, uchar *buf, int n)
2629a747e4fSDavid du Colombier {
2639a747e4fSDavid du Colombier 	NOTFREE(p);
264368c31abSDavid du Colombier 	if(buf && packetcopy(p, buf, 0, n) < 0)
265368c31abSDavid du Colombier 		return -1;
266368c31abSDavid du Colombier 	return packettrim(p, n, p->size-n);
2679a747e4fSDavid du Colombier }
2689a747e4fSDavid du Colombier 
2699a747e4fSDavid du Colombier int
packettrim(Packet * p,int offset,int n)270368c31abSDavid du Colombier packettrim(Packet *p, int offset, int n)
2719a747e4fSDavid du Colombier {
2729a747e4fSDavid du Colombier 	Frag *f, *ff;
2739a747e4fSDavid du Colombier 
2749a747e4fSDavid du Colombier 	NOTFREE(p);
2759a747e4fSDavid du Colombier 	if(offset < 0 || offset > p->size) {
276368c31abSDavid du Colombier 		werrstr(EPacketOffset);
277368c31abSDavid du Colombier 		return -1;
2789a747e4fSDavid du Colombier 	}
2799a747e4fSDavid du Colombier 
2809a747e4fSDavid du Colombier 	if(n < 0 || offset + n > p->size) {
281368c31abSDavid du Colombier 		werrstr(EPacketOffset);
282368c31abSDavid du Colombier 		return -1;
2839a747e4fSDavid du Colombier 	}
2849a747e4fSDavid du Colombier 
2859a747e4fSDavid du Colombier 	p->size = n;
2869a747e4fSDavid du Colombier 
2879a747e4fSDavid du Colombier 	/* easy case */
2889a747e4fSDavid du Colombier 	if(n == 0) {
2899a747e4fSDavid du Colombier 		for(f=p->first; f != nil; f=ff) {
2909a747e4fSDavid du Colombier 			ff = f->next;
291368c31abSDavid du Colombier 			fragfree(f);
2929a747e4fSDavid du Colombier 		}
2939a747e4fSDavid du Colombier 		p->first = p->last = nil;
2949a747e4fSDavid du Colombier 		p->asize = 0;
295368c31abSDavid du Colombier 		NOTFREE(p);
296368c31abSDavid du Colombier 		return 0;
2979a747e4fSDavid du Colombier 	}
2989a747e4fSDavid du Colombier 
2999a747e4fSDavid du Colombier 	/* free before offset */
3009a747e4fSDavid du Colombier 	for(f=p->first; offset >= FRAGSIZE(f); f=ff) {
3019a747e4fSDavid du Colombier 		p->asize -= FRAGASIZE(f);
3029a747e4fSDavid du Colombier 		offset -= FRAGSIZE(f);
3039a747e4fSDavid du Colombier 		ff = f->next;
304368c31abSDavid du Colombier 		fragfree(f);
3059a747e4fSDavid du Colombier 	}
3069a747e4fSDavid du Colombier 
3079a747e4fSDavid du Colombier 	/* adjust frag */
3089a747e4fSDavid du Colombier 	f->rp += offset;
3099a747e4fSDavid du Colombier 	p->first = f;
3109a747e4fSDavid du Colombier 
3119a747e4fSDavid du Colombier 	/* skip middle */
3129a747e4fSDavid du Colombier 	for(; n > 0 && n > FRAGSIZE(f); f=f->next)
3139a747e4fSDavid du Colombier 		n -= FRAGSIZE(f);
3149a747e4fSDavid du Colombier 
3159a747e4fSDavid du Colombier 	/* adjust end */
3169a747e4fSDavid du Colombier 	f->wp = f->rp + n;
3179a747e4fSDavid du Colombier 	p->last = f;
3189a747e4fSDavid du Colombier 	ff = f->next;
3199a747e4fSDavid du Colombier 	f->next = nil;
3209a747e4fSDavid du Colombier 
3219a747e4fSDavid du Colombier 	/* free after */
3229a747e4fSDavid du Colombier 	for(f=ff; f != nil; f=ff) {
3239a747e4fSDavid du Colombier 		p->asize -= FRAGASIZE(f);
3249a747e4fSDavid du Colombier 		ff = f->next;
325368c31abSDavid du Colombier 		fragfree(f);
3269a747e4fSDavid du Colombier 	}
327368c31abSDavid du Colombier 	NOTFREE(p);
328368c31abSDavid du Colombier 	return 0;
3299a747e4fSDavid du Colombier }
3309a747e4fSDavid du Colombier 
3319a747e4fSDavid du Colombier uchar *
packetheader(Packet * p,int n)332368c31abSDavid du Colombier packetheader(Packet *p, int n)
3339a747e4fSDavid du Colombier {
3349a747e4fSDavid du Colombier 	Frag *f;
3359a747e4fSDavid du Colombier 	Mem *m;
3369a747e4fSDavid du Colombier 
3379a747e4fSDavid du Colombier 	NOTFREE(p);
3389a747e4fSDavid du Colombier 	if(n <= 0 || n > MaxFragSize) {
339368c31abSDavid du Colombier 		werrstr(EPacketSize);
340368c31abSDavid du Colombier 		return nil;
3419a747e4fSDavid du Colombier 	}
3429a747e4fSDavid du Colombier 
3439a747e4fSDavid du Colombier 	p->size += n;
3449a747e4fSDavid du Colombier 
3459a747e4fSDavid du Colombier 	/* try and fix in current frag */
3469a747e4fSDavid du Colombier 	f = p->first;
3479a747e4fSDavid du Colombier 	if(f != nil) {
3489a747e4fSDavid du Colombier 		m = f->mem;
3499a747e4fSDavid du Colombier 		if(n <= f->rp - m->bp)
350368c31abSDavid du Colombier 		if(m->ref == 1 || memhead(m, f->rp, n) >= 0) {
3519a747e4fSDavid du Colombier 			f->rp -= n;
352368c31abSDavid du Colombier 			NOTFREE(p);
3539a747e4fSDavid du Colombier 			return f->rp;
3549a747e4fSDavid du Colombier 		}
3559a747e4fSDavid du Colombier 	}
3569a747e4fSDavid du Colombier 
3579a747e4fSDavid du Colombier 	/* add frag to front */
358368c31abSDavid du Colombier 	f = fragalloc(p, n, PEnd, p->first);
3599a747e4fSDavid du Colombier 	p->asize += FRAGASIZE(f);
3609a747e4fSDavid du Colombier 	if(p->first == nil)
3619a747e4fSDavid du Colombier 		p->last = f;
3629a747e4fSDavid du Colombier 	p->first = f;
363368c31abSDavid du Colombier 	NOTFREE(p);
3649a747e4fSDavid du Colombier 	return f->rp;
3659a747e4fSDavid du Colombier }
3669a747e4fSDavid du Colombier 
3679a747e4fSDavid du Colombier uchar *
packettrailer(Packet * p,int n)368368c31abSDavid du Colombier packettrailer(Packet *p, int n)
3699a747e4fSDavid du Colombier {
3709a747e4fSDavid du Colombier 	Mem *m;
3719a747e4fSDavid du Colombier 	Frag *f;
3729a747e4fSDavid du Colombier 
3739a747e4fSDavid du Colombier 	NOTFREE(p);
3749a747e4fSDavid du Colombier 	if(n <= 0 || n > MaxFragSize) {
375368c31abSDavid du Colombier 		werrstr(EPacketSize);
376368c31abSDavid du Colombier 		return nil;
3779a747e4fSDavid du Colombier 	}
3789a747e4fSDavid du Colombier 
3799a747e4fSDavid du Colombier 	p->size += n;
3809a747e4fSDavid du Colombier 
3819a747e4fSDavid du Colombier 	/* try and fix in current frag */
3829a747e4fSDavid du Colombier 	if(p->first != nil) {
3839a747e4fSDavid du Colombier 		f = p->last;
3849a747e4fSDavid du Colombier 		m = f->mem;
3859a747e4fSDavid du Colombier 		if(n <= m->ep - f->wp)
386368c31abSDavid du Colombier 		if(m->ref == 1 || memtail(m, f->wp, n) >= 0) {
3879a747e4fSDavid du Colombier 			f->wp += n;
388368c31abSDavid du Colombier 			NOTFREE(p);
3899a747e4fSDavid du Colombier 			return f->wp - n;
3909a747e4fSDavid du Colombier 		}
3919a747e4fSDavid du Colombier 	}
3929a747e4fSDavid du Colombier 
3939a747e4fSDavid du Colombier 	/* add frag to end */
394368c31abSDavid du Colombier 	f = fragalloc(p, n, (p->first == nil)?PMiddle:PFront, nil);
3959a747e4fSDavid du Colombier 	p->asize += FRAGASIZE(f);
3969a747e4fSDavid du Colombier 	if(p->first == nil)
3979a747e4fSDavid du Colombier 		p->first = f;
3989a747e4fSDavid du Colombier 	else
3999a747e4fSDavid du Colombier 		p->last->next = f;
4009a747e4fSDavid du Colombier 	p->last = f;
401368c31abSDavid du Colombier 	NOTFREE(p);
4029a747e4fSDavid du Colombier 	return f->rp;
4039a747e4fSDavid du Colombier }
4049a747e4fSDavid du Colombier 
405368c31abSDavid du Colombier void
packetprefix(Packet * p,uchar * buf,int n)406368c31abSDavid du Colombier packetprefix(Packet *p, uchar *buf, int n)
4079a747e4fSDavid du Colombier {
4089a747e4fSDavid du Colombier 	Frag *f;
4099a747e4fSDavid du Colombier 	int nn;
4109a747e4fSDavid du Colombier 	Mem *m;
4119a747e4fSDavid du Colombier 
4129a747e4fSDavid du Colombier 	NOTFREE(p);
4139a747e4fSDavid du Colombier 	if(n <= 0)
414368c31abSDavid du Colombier 		return;
4159a747e4fSDavid du Colombier 
4169a747e4fSDavid du Colombier 	p->size += n;
4179a747e4fSDavid du Colombier 
4189a747e4fSDavid du Colombier 	/* try and fix in current frag */
4199a747e4fSDavid du Colombier 	f = p->first;
4209a747e4fSDavid du Colombier 	if(f != nil) {
4219a747e4fSDavid du Colombier 		m = f->mem;
4229a747e4fSDavid du Colombier 		nn = f->rp - m->bp;
4239a747e4fSDavid du Colombier 		if(nn > n)
4249a747e4fSDavid du Colombier 			nn = n;
425368c31abSDavid du Colombier 		if(m->ref == 1 || memhead(m, f->rp, nn) >= 0) {
4269a747e4fSDavid du Colombier 			f->rp -= nn;
4279a747e4fSDavid du Colombier 			n -= nn;
4289a747e4fSDavid du Colombier 			memmove(f->rp, buf+n, nn);
4299a747e4fSDavid du Colombier 		}
4309a747e4fSDavid du Colombier 	}
4319a747e4fSDavid du Colombier 
4329a747e4fSDavid du Colombier 	while(n > 0) {
4339a747e4fSDavid du Colombier 		nn = n;
4349a747e4fSDavid du Colombier 		if(nn > MaxFragSize)
4359a747e4fSDavid du Colombier 			nn = MaxFragSize;
436368c31abSDavid du Colombier 		f = fragalloc(p, nn, PEnd, p->first);
4379a747e4fSDavid du Colombier 		p->asize += FRAGASIZE(f);
4389a747e4fSDavid du Colombier 		if(p->first == nil)
4399a747e4fSDavid du Colombier 			p->last = f;
4409a747e4fSDavid du Colombier 		p->first = f;
4419a747e4fSDavid du Colombier 		n -= nn;
4429a747e4fSDavid du Colombier 		memmove(f->rp, buf+n, nn);
4439a747e4fSDavid du Colombier 	}
444368c31abSDavid du Colombier 	NOTFREE(p);
4459a747e4fSDavid du Colombier }
4469a747e4fSDavid du Colombier 
447368c31abSDavid du Colombier void
packetappend(Packet * p,uchar * buf,int n)448368c31abSDavid du Colombier packetappend(Packet *p, uchar *buf, int n)
4499a747e4fSDavid du Colombier {
4509a747e4fSDavid du Colombier 	Frag *f;
4519a747e4fSDavid du Colombier 	int nn;
4529a747e4fSDavid du Colombier 	Mem *m;
4539a747e4fSDavid du Colombier 
4549a747e4fSDavid du Colombier 	NOTFREE(p);
4559a747e4fSDavid du Colombier 	if(n <= 0)
456368c31abSDavid du Colombier 		return;
4579a747e4fSDavid du Colombier 
4589a747e4fSDavid du Colombier 	p->size += n;
4599a747e4fSDavid du Colombier 	/* try and fix in current frag */
4609a747e4fSDavid du Colombier 	if(p->first != nil) {
4619a747e4fSDavid du Colombier 		f = p->last;
4629a747e4fSDavid du Colombier 		m = f->mem;
4639a747e4fSDavid du Colombier 		nn = m->ep - f->wp;
4649a747e4fSDavid du Colombier 		if(nn > n)
4659a747e4fSDavid du Colombier 			nn = n;
466368c31abSDavid du Colombier 		if(m->ref == 1 || memtail(m, f->wp, nn) >= 0) {
4679a747e4fSDavid du Colombier 			memmove(f->wp, buf, nn);
4689a747e4fSDavid du Colombier 			f->wp += nn;
4699a747e4fSDavid du Colombier 			buf += nn;
4709a747e4fSDavid du Colombier 			n -= nn;
4719a747e4fSDavid du Colombier 		}
4729a747e4fSDavid du Colombier 	}
4739a747e4fSDavid du Colombier 
4749a747e4fSDavid du Colombier 	while(n > 0) {
4759a747e4fSDavid du Colombier 		nn = n;
4769a747e4fSDavid du Colombier 		if(nn > MaxFragSize)
4779a747e4fSDavid du Colombier 			nn = MaxFragSize;
478368c31abSDavid du Colombier 		f = fragalloc(p, nn, (p->first == nil)?PMiddle:PFront, nil);
4799a747e4fSDavid du Colombier 		p->asize += FRAGASIZE(f);
4809a747e4fSDavid du Colombier 		if(p->first == nil)
4819a747e4fSDavid du Colombier 			p->first = f;
4829a747e4fSDavid du Colombier 		else
4839a747e4fSDavid du Colombier 			p->last->next = f;
4849a747e4fSDavid du Colombier 		p->last = f;
4859a747e4fSDavid du Colombier 		memmove(f->rp, buf, nn);
4869a747e4fSDavid du Colombier 		buf += nn;
4879a747e4fSDavid du Colombier 		n -= nn;
4889a747e4fSDavid du Colombier 	}
489368c31abSDavid du Colombier 	NOTFREE(p);
4909a747e4fSDavid du Colombier }
4919a747e4fSDavid du Colombier 
492368c31abSDavid du Colombier void
packetconcat(Packet * p,Packet * pp)493368c31abSDavid du Colombier packetconcat(Packet *p, Packet *pp)
4949a747e4fSDavid du Colombier {
495368c31abSDavid du Colombier 	Frag *f;
496368c31abSDavid du Colombier 
4979a747e4fSDavid du Colombier 	NOTFREE(p);
4989a747e4fSDavid du Colombier 	NOTFREE(pp);
4999a747e4fSDavid du Colombier 	if(pp->size == 0)
500368c31abSDavid du Colombier 		return;
5019a747e4fSDavid du Colombier 	p->size += pp->size;
5029a747e4fSDavid du Colombier 	p->asize += pp->asize;
503368c31abSDavid du Colombier 	for(f=pp->first; f; f=f->next)
504368c31abSDavid du Colombier 		f->p = p;
5059a747e4fSDavid du Colombier 
5069a747e4fSDavid du Colombier 	if(p->first != nil)
5079a747e4fSDavid du Colombier 		p->last->next = pp->first;
5089a747e4fSDavid du Colombier 	else
5099a747e4fSDavid du Colombier 		p->first = pp->first;
510368c31abSDavid du Colombier 
5119a747e4fSDavid du Colombier 	p->last = pp->last;
5129a747e4fSDavid du Colombier 	pp->size = 0;
5139a747e4fSDavid du Colombier 	pp->asize = 0;
5149a747e4fSDavid du Colombier 	pp->first = nil;
5159a747e4fSDavid du Colombier 	pp->last = nil;
516368c31abSDavid du Colombier 	NOTFREE(p);
517368c31abSDavid du Colombier 	NOTFREE(pp);
5189a747e4fSDavid du Colombier }
5199a747e4fSDavid du Colombier 
5209a747e4fSDavid du Colombier uchar *
packetpeek(Packet * p,uchar * buf,int offset,int n)521368c31abSDavid du Colombier packetpeek(Packet *p, uchar *buf, int offset, int n)
5229a747e4fSDavid du Colombier {
5239a747e4fSDavid du Colombier 	Frag *f;
5249a747e4fSDavid du Colombier 	int nn;
5259a747e4fSDavid du Colombier 	uchar *b;
5269a747e4fSDavid du Colombier 
5279a747e4fSDavid du Colombier 	NOTFREE(p);
5289a747e4fSDavid du Colombier 	if(n == 0)
5299a747e4fSDavid du Colombier 		return buf;
5309a747e4fSDavid du Colombier 
5319a747e4fSDavid du Colombier 	if(offset < 0 || offset >= p->size) {
532368c31abSDavid du Colombier 		werrstr(EPacketOffset);
533368c31abSDavid du Colombier 		return nil;
5349a747e4fSDavid du Colombier 	}
5359a747e4fSDavid du Colombier 
5369a747e4fSDavid du Colombier 	if(n < 0 || offset + n > p->size) {
537368c31abSDavid du Colombier 		werrstr(EPacketSize);
538368c31abSDavid du Colombier 		return nil;
5399a747e4fSDavid du Colombier 	}
5409a747e4fSDavid du Colombier 
5419a747e4fSDavid du Colombier 	/* skip up to offset */
5429a747e4fSDavid du Colombier 	for(f=p->first; offset >= FRAGSIZE(f); f=f->next)
5439a747e4fSDavid du Colombier 		offset -= FRAGSIZE(f);
5449a747e4fSDavid du Colombier 
5459a747e4fSDavid du Colombier 	/* easy case */
546368c31abSDavid du Colombier 	if(offset + n <= FRAGSIZE(f)){
547368c31abSDavid du Colombier 		NOTFREE(p);
5489a747e4fSDavid du Colombier 		return f->rp + offset;
549368c31abSDavid du Colombier 	}
5509a747e4fSDavid du Colombier 
5519a747e4fSDavid du Colombier 	for(b=buf; n>0; n -= nn) {
5529a747e4fSDavid du Colombier 		nn = FRAGSIZE(f) - offset;
5539a747e4fSDavid du Colombier 		if(nn > n)
5549a747e4fSDavid du Colombier 			nn = n;
5559a747e4fSDavid du Colombier 		memmove(b, f->rp+offset, nn);
5569a747e4fSDavid du Colombier 		offset = 0;
5579a747e4fSDavid du Colombier 		f = f->next;
5589a747e4fSDavid du Colombier 		b += nn;
5599a747e4fSDavid du Colombier 	}
5609a747e4fSDavid du Colombier 
561368c31abSDavid du Colombier 	NOTFREE(p);
5629a747e4fSDavid du Colombier 	return buf;
5639a747e4fSDavid du Colombier }
5649a747e4fSDavid du Colombier 
5659a747e4fSDavid du Colombier int
packetcopy(Packet * p,uchar * buf,int offset,int n)566368c31abSDavid du Colombier packetcopy(Packet *p, uchar *buf, int offset, int n)
5679a747e4fSDavid du Colombier {
5689a747e4fSDavid du Colombier 	uchar *b;
5699a747e4fSDavid du Colombier 
5709a747e4fSDavid du Colombier 	NOTFREE(p);
571368c31abSDavid du Colombier 	b = packetpeek(p, buf, offset, n);
5729a747e4fSDavid du Colombier 	if(b == nil)
573368c31abSDavid du Colombier 		return -1;
5749a747e4fSDavid du Colombier 	if(b != buf)
5759a747e4fSDavid du Colombier 		memmove(buf, b, n);
576368c31abSDavid du Colombier 	return 0;
5779a747e4fSDavid du Colombier }
5789a747e4fSDavid du Colombier 
5799a747e4fSDavid du Colombier int
packetfragments(Packet * p,IOchunk * io,int nio,int offset)580368c31abSDavid du Colombier packetfragments(Packet *p, IOchunk *io, int nio, int offset)
5819a747e4fSDavid du Colombier {
5829a747e4fSDavid du Colombier 	Frag *f;
5839a747e4fSDavid du Colombier 	int size;
5849a747e4fSDavid du Colombier 	IOchunk *eio;
5859a747e4fSDavid du Colombier 
5869a747e4fSDavid du Colombier 	NOTFREE(p);
5879a747e4fSDavid du Colombier 	if(p->size == 0 || nio <= 0)
5889a747e4fSDavid du Colombier 		return 0;
5899a747e4fSDavid du Colombier 
5909a747e4fSDavid du Colombier 	if(offset < 0 || offset > p->size) {
591368c31abSDavid du Colombier 		werrstr(EPacketOffset);
5929a747e4fSDavid du Colombier 		return -1;
5939a747e4fSDavid du Colombier 	}
5949a747e4fSDavid du Colombier 
5959a747e4fSDavid du Colombier 	for(f=p->first; offset >= FRAGSIZE(f); f=f->next)
5969a747e4fSDavid du Colombier 		offset -= FRAGSIZE(f);
5979a747e4fSDavid du Colombier 
5989a747e4fSDavid du Colombier 	size = 0;
5999a747e4fSDavid du Colombier 	eio = io + nio;
6009a747e4fSDavid du Colombier 	for(; f != nil && io < eio; f=f->next) {
6019a747e4fSDavid du Colombier 		io->addr = f->rp + offset;
6029a747e4fSDavid du Colombier 		io->len = f->wp - (f->rp + offset);
6039a747e4fSDavid du Colombier 		offset = 0;
6049a747e4fSDavid du Colombier 		size += io->len;
6059a747e4fSDavid du Colombier 		io++;
6069a747e4fSDavid du Colombier 	}
607368c31abSDavid du Colombier 	for(; io < eio; io++){
608368c31abSDavid du Colombier 		io->addr = nil;
609368c31abSDavid du Colombier 		io->len = 0;
610368c31abSDavid du Colombier 	}
6119a747e4fSDavid du Colombier 	return size;
6129a747e4fSDavid du Colombier }
6139a747e4fSDavid du Colombier 
6149a747e4fSDavid du Colombier void
packetstats(void)615368c31abSDavid du Colombier packetstats(void)
6169a747e4fSDavid du Colombier {
6179a747e4fSDavid du Colombier 	Packet *p;
6189a747e4fSDavid du Colombier 	Frag *f;
6199a747e4fSDavid du Colombier 	Mem *m;
6209a747e4fSDavid du Colombier 
6219a747e4fSDavid du Colombier 	int np, nf, nsm, nbm;
6229a747e4fSDavid du Colombier 
623368c31abSDavid du Colombier 	lock(&freelist.lk);
6249a747e4fSDavid du Colombier 	np = 0;
625368c31abSDavid du Colombier 	for(p=freelist.packet; p; p=p->next)
6269a747e4fSDavid du Colombier 		np++;
6279a747e4fSDavid du Colombier 	nf = 0;
628368c31abSDavid du Colombier 	for(f=freelist.frag; f; f=f->next)
6299a747e4fSDavid du Colombier 		nf++;
6309a747e4fSDavid du Colombier 	nsm = 0;
631368c31abSDavid du Colombier 	for(m=freelist.smallmem; m; m=m->next)
6329a747e4fSDavid du Colombier 		nsm++;
6339a747e4fSDavid du Colombier 	nbm = 0;
634368c31abSDavid du Colombier 	for(m=freelist.bigmem; m; m=m->next)
6359a747e4fSDavid du Colombier 		nbm++;
6369a747e4fSDavid du Colombier 
6379a747e4fSDavid du Colombier 	fprint(2, "packet: %d/%d frag: %d/%d small mem: %d/%d big mem: %d/%d\n",
638368c31abSDavid du Colombier 		np, freelist.npacket,
639368c31abSDavid du Colombier 		nf, freelist.nfrag,
640368c31abSDavid du Colombier 		nsm, freelist.nsmallmem,
641368c31abSDavid du Colombier 		nbm, freelist.nbigmem);
6429a747e4fSDavid du Colombier 
643368c31abSDavid du Colombier 	unlock(&freelist.lk);
6449a747e4fSDavid du Colombier }
6459a747e4fSDavid du Colombier 
6469a747e4fSDavid du Colombier 
647368c31abSDavid du Colombier uint
packetsize(Packet * p)648368c31abSDavid du Colombier packetsize(Packet *p)
6499a747e4fSDavid du Colombier {
6509a747e4fSDavid du Colombier 	NOTFREE(p);
651368c31abSDavid du Colombier 	if(1) {
6529a747e4fSDavid du Colombier 		Frag *f;
6539a747e4fSDavid du Colombier 		int size = 0;
6549a747e4fSDavid du Colombier 
6559a747e4fSDavid du Colombier 		for(f=p->first; f; f=f->next)
6569a747e4fSDavid du Colombier 			size += FRAGSIZE(f);
6579a747e4fSDavid du Colombier 		if(size != p->size)
658368c31abSDavid du Colombier 			fprint(2, "packetsize %d %d\n", size, p->size);
6599a747e4fSDavid du Colombier 		assert(size == p->size);
6609a747e4fSDavid du Colombier 	}
6619a747e4fSDavid du Colombier 	return p->size;
6629a747e4fSDavid du Colombier }
6639a747e4fSDavid du Colombier 
664368c31abSDavid du Colombier uint
packetasize(Packet * p)665368c31abSDavid du Colombier packetasize(Packet *p)
6669a747e4fSDavid du Colombier {
6679a747e4fSDavid du Colombier 	NOTFREE(p);
6689a747e4fSDavid du Colombier 	if(0) {
6699a747e4fSDavid du Colombier 		Frag *f;
6709a747e4fSDavid du Colombier 		int asize = 0;
6719a747e4fSDavid du Colombier 
6729a747e4fSDavid du Colombier 		for(f=p->first; f; f=f->next)
6739a747e4fSDavid du Colombier 			asize += FRAGASIZE(f);
6749a747e4fSDavid du Colombier 		if(asize != p->asize)
675368c31abSDavid du Colombier 			fprint(2, "packetasize %d %d\n", asize, p->asize);
6769a747e4fSDavid du Colombier 		assert(asize == p->asize);
6779a747e4fSDavid du Colombier 	}
6789a747e4fSDavid du Colombier 	return p->asize;
6799a747e4fSDavid du Colombier }
6809a747e4fSDavid du Colombier 
6819a747e4fSDavid du Colombier void
packetsha1(Packet * p,uchar digest[VtScoreSize])682368c31abSDavid du Colombier packetsha1(Packet *p, uchar digest[VtScoreSize])
6839a747e4fSDavid du Colombier {
684368c31abSDavid du Colombier 	DigestState ds;
6859a747e4fSDavid du Colombier 	Frag *f;
6869a747e4fSDavid du Colombier 	int size;
6879a747e4fSDavid du Colombier 
6889a747e4fSDavid du Colombier 	NOTFREE(p);
689368c31abSDavid du Colombier 	memset(&ds, 0, sizeof ds);
6909a747e4fSDavid du Colombier 	size = p->size;
6919a747e4fSDavid du Colombier 	for(f=p->first; f; f=f->next) {
692368c31abSDavid du Colombier 		sha1(f->rp, FRAGSIZE(f), nil, &ds);
6939a747e4fSDavid du Colombier 		size -= FRAGSIZE(f);
6949a747e4fSDavid du Colombier 	}
6959a747e4fSDavid du Colombier 	assert(size == 0);
696368c31abSDavid du Colombier 	sha1(nil, 0, digest, &ds);
6979a747e4fSDavid du Colombier }
6989a747e4fSDavid du Colombier 
6999a747e4fSDavid du Colombier int
packetcmp(Packet * pkt0,Packet * pkt1)700368c31abSDavid du Colombier packetcmp(Packet *pkt0, Packet *pkt1)
7019a747e4fSDavid du Colombier {
7029a747e4fSDavid du Colombier 	Frag *f0, *f1;
7039a747e4fSDavid du Colombier 	int n0, n1, x;
7049a747e4fSDavid du Colombier 
7059a747e4fSDavid du Colombier 	NOTFREE(pkt0);
7069a747e4fSDavid du Colombier 	NOTFREE(pkt1);
7079a747e4fSDavid du Colombier 	f0 = pkt0->first;
7089a747e4fSDavid du Colombier 	f1 = pkt1->first;
7099a747e4fSDavid du Colombier 
7109a747e4fSDavid du Colombier 	if(f0 == nil)
7119a747e4fSDavid du Colombier 		return (f1 == nil)?0:-1;
7129a747e4fSDavid du Colombier 	if(f1 == nil)
7139a747e4fSDavid du Colombier 		return 1;
7149a747e4fSDavid du Colombier 	n0 = FRAGSIZE(f0);
7159a747e4fSDavid du Colombier 	n1 = FRAGSIZE(f1);
7169a747e4fSDavid du Colombier 
7179a747e4fSDavid du Colombier 	for(;;) {
7189a747e4fSDavid du Colombier 		if(n0 < n1) {
7199a747e4fSDavid du Colombier 			x = memcmp(f0->wp - n0, f1->wp - n1, n0);
7209a747e4fSDavid du Colombier 			if(x != 0)
7219a747e4fSDavid du Colombier 				return x;
7229a747e4fSDavid du Colombier 			n1 -= n0;
7239a747e4fSDavid du Colombier 			f0 = f0->next;
7249a747e4fSDavid du Colombier 			if(f0 == nil)
7259a747e4fSDavid du Colombier 				return -1;
7269a747e4fSDavid du Colombier 			n0 = FRAGSIZE(f0);
7279a747e4fSDavid du Colombier 		} else if (n0 > n1) {
7289a747e4fSDavid du Colombier 			x = memcmp(f0->wp - n0, f1->wp - n1, n1);
7299a747e4fSDavid du Colombier 			if(x != 0)
7309a747e4fSDavid du Colombier 				return x;
7319a747e4fSDavid du Colombier 			n0 -= n1;
7329a747e4fSDavid du Colombier 			f1 = f1->next;
7339a747e4fSDavid du Colombier 			if(f1 == nil)
7349a747e4fSDavid du Colombier 				return 1;
7359a747e4fSDavid du Colombier 			n1 = FRAGSIZE(f1);
7369a747e4fSDavid du Colombier 		} else { /* n0 == n1 */
7379a747e4fSDavid du Colombier 			x = memcmp(f0->wp - n0, f1->wp - n1, n0);
7389a747e4fSDavid du Colombier 			if(x != 0)
7399a747e4fSDavid du Colombier 				return x;
7409a747e4fSDavid du Colombier 			f0 = f0->next;
7419a747e4fSDavid du Colombier 			f1 = f1->next;
7429a747e4fSDavid du Colombier 			if(f0 == nil)
7439a747e4fSDavid du Colombier 				return (f1 == nil)?0:-1;
7449a747e4fSDavid du Colombier 			if(f1 == nil)
7459a747e4fSDavid du Colombier 				return 1;
7469a747e4fSDavid du Colombier 			n0 = FRAGSIZE(f0);
7479a747e4fSDavid du Colombier 			n1 = FRAGSIZE(f1);
7489a747e4fSDavid du Colombier 		}
7499a747e4fSDavid du Colombier 	}
7509a747e4fSDavid du Colombier }
7519a747e4fSDavid du Colombier 
7529a747e4fSDavid du Colombier static Frag *
fragalloc(Packet * p,int n,int pos,Frag * next)753368c31abSDavid du Colombier fragalloc(Packet *p, int n, int pos, Frag *next)
7549a747e4fSDavid du Colombier {
7559a747e4fSDavid du Colombier 	Frag *f, *ef;
7569a747e4fSDavid du Colombier 	Mem *m;
7579a747e4fSDavid du Colombier 
7589a747e4fSDavid du Colombier 	/* look for local frag */
7599a747e4fSDavid du Colombier 	f = &p->local[0];
7609a747e4fSDavid du Colombier 	ef = &p->local[NLocalFrag];
7619a747e4fSDavid du Colombier 	for(;f<ef; f++) {
7629a747e4fSDavid du Colombier 		if(f->state == FragLocalFree) {
7639a747e4fSDavid du Colombier 			f->state = FragLocalAlloc;
7649a747e4fSDavid du Colombier 			goto Found;
7659a747e4fSDavid du Colombier 		}
7669a747e4fSDavid du Colombier 	}
767368c31abSDavid du Colombier 	lock(&freelist.lk);
768368c31abSDavid du Colombier 	f = freelist.frag;
7699a747e4fSDavid du Colombier 	if(f != nil)
770368c31abSDavid du Colombier 		freelist.frag = f->next;
7719a747e4fSDavid du Colombier 	else
772368c31abSDavid du Colombier 		freelist.nfrag++;
773368c31abSDavid du Colombier 	unlock(&freelist.lk);
7749a747e4fSDavid du Colombier 
7759a747e4fSDavid du Colombier 	if(f == nil) {
776368c31abSDavid du Colombier 		f = vtbrk(sizeof(Frag));
7779a747e4fSDavid du Colombier 		f->state = FragGlobal;
7789a747e4fSDavid du Colombier 	}
7799a747e4fSDavid du Colombier 
7809a747e4fSDavid du Colombier Found:
7819a747e4fSDavid du Colombier 	f->next = next;
782368c31abSDavid du Colombier 	f->p = p;
7839a747e4fSDavid du Colombier 
784368c31abSDavid du Colombier 	if(n == 0){
785368c31abSDavid du Colombier 		f->mem = 0;
786368c31abSDavid du Colombier 		f->rp = 0;
787368c31abSDavid du Colombier 		f->wp = 0;
7889a747e4fSDavid du Colombier 		return f;
7899a747e4fSDavid du Colombier 	}
7909a747e4fSDavid du Colombier 
791368c31abSDavid du Colombier 	if(pos == PEnd && next == nil)
792368c31abSDavid du Colombier 		pos = PMiddle;
793368c31abSDavid du Colombier 	m = memalloc(n, pos);
794368c31abSDavid du Colombier 	f->mem = m;
795368c31abSDavid du Colombier 	f->rp = m->rp;
796368c31abSDavid du Colombier 	f->wp = m->wp;
797368c31abSDavid du Colombier 	return f;
798368c31abSDavid du Colombier }
799368c31abSDavid du Colombier 
800368c31abSDavid du Colombier Packet*
packetforeign(uchar * buf,int n,void (* free)(void * a),void * a)801368c31abSDavid du Colombier packetforeign(uchar *buf, int n, void (*free)(void *a), void *a)
802368c31abSDavid du Colombier {
803368c31abSDavid du Colombier 	Packet *p;
804368c31abSDavid du Colombier 	Frag *f;
805368c31abSDavid du Colombier 
806368c31abSDavid du Colombier 	p = packetalloc();
807368c31abSDavid du Colombier 	p->pc = getcallerpc(&buf);
808368c31abSDavid du Colombier 	f = fragalloc(p, 0, 0, nil);
809368c31abSDavid du Colombier 	f->free = free;
810368c31abSDavid du Colombier 	f->a = a;
811368c31abSDavid du Colombier 	f->next = nil;
812368c31abSDavid du Colombier 	f->rp = buf;
813368c31abSDavid du Colombier 	f->wp = buf+n;
814368c31abSDavid du Colombier 
815368c31abSDavid du Colombier 	p->first = f;
816368c31abSDavid du Colombier 	p->last = f;
817368c31abSDavid du Colombier 	p->size = n;
818368c31abSDavid du Colombier 	NOTFREE(p);
819368c31abSDavid du Colombier 	return p;
820368c31abSDavid du Colombier }
821368c31abSDavid du Colombier 
8229a747e4fSDavid du Colombier static Frag *
fragdup(Packet * p,Frag * f)823368c31abSDavid du Colombier fragdup(Packet *p, Frag *f)
8249a747e4fSDavid du Colombier {
8259a747e4fSDavid du Colombier 	Frag *ff;
8269a747e4fSDavid du Colombier 	Mem *m;
8279a747e4fSDavid du Colombier 
8289a747e4fSDavid du Colombier 	m = f->mem;
8299a747e4fSDavid du Colombier 
8309a747e4fSDavid du Colombier 	/*
8319a747e4fSDavid du Colombier 	 * m->rp && m->wp can be out of date when ref == 1
8329a747e4fSDavid du Colombier 	 * also, potentially reclaims space from previous frags
8339a747e4fSDavid du Colombier 	 */
834368c31abSDavid du Colombier 	if(m && m->ref == 1) {
8359a747e4fSDavid du Colombier 		m->rp = f->rp;
8369a747e4fSDavid du Colombier 		m->wp = f->wp;
8379a747e4fSDavid du Colombier 	}
8389a747e4fSDavid du Colombier 
839368c31abSDavid du Colombier 	ff = fragalloc(p, 0, 0, nil);
840368c31abSDavid du Colombier 	ff->mem = f->mem;
841368c31abSDavid du Colombier 	ff->rp = f->rp;
842368c31abSDavid du Colombier 	ff->wp = f->wp;
843368c31abSDavid du Colombier 	ff->next = f->next;
844368c31abSDavid du Colombier 
845368c31abSDavid du Colombier 	/*
846368c31abSDavid du Colombier 	 * We can't duplicate these -- there's no dup function.
847368c31abSDavid du Colombier 	 */
848368c31abSDavid du Colombier 	assert(f->free==nil && f->a==nil);
849368c31abSDavid du Colombier 
850368c31abSDavid du Colombier 	if(m){
8519a747e4fSDavid du Colombier 		lock(&m->lk);
8529a747e4fSDavid du Colombier 		m->ref++;
8539a747e4fSDavid du Colombier 		unlock(&m->lk);
854368c31abSDavid du Colombier 	}
855368c31abSDavid du Colombier 
856368c31abSDavid du Colombier 
8579a747e4fSDavid du Colombier 	return ff;
8589a747e4fSDavid du Colombier }
8599a747e4fSDavid du Colombier 
8609a747e4fSDavid du Colombier 
8619a747e4fSDavid du Colombier static void
fragfree(Frag * f)862368c31abSDavid du Colombier fragfree(Frag *f)
8639a747e4fSDavid du Colombier {
864368c31abSDavid du Colombier 	if(f->mem == nil){
865368c31abSDavid du Colombier 		if(f->free)
866368c31abSDavid du Colombier 			(*f->free)(f->a);
867368c31abSDavid du Colombier 	}else{
868368c31abSDavid du Colombier 		memfree(f->mem);
869368c31abSDavid du Colombier 		f->mem = 0;
870368c31abSDavid du Colombier 	}
8719a747e4fSDavid du Colombier 
8729a747e4fSDavid du Colombier 	if(f->state == FragLocalAlloc) {
8739a747e4fSDavid du Colombier 		f->state = FragLocalFree;
8749a747e4fSDavid du Colombier 		return;
8759a747e4fSDavid du Colombier 	}
8769a747e4fSDavid du Colombier 
877368c31abSDavid du Colombier 	lock(&freelist.lk);
878368c31abSDavid du Colombier 	f->next = freelist.frag;
879368c31abSDavid du Colombier 	freelist.frag = f;
880368c31abSDavid du Colombier 	unlock(&freelist.lk);
8819a747e4fSDavid du Colombier }
8829a747e4fSDavid du Colombier 
8839a747e4fSDavid du Colombier static Mem *
memalloc(int n,int pos)884368c31abSDavid du Colombier memalloc(int n, int pos)
8859a747e4fSDavid du Colombier {
8869a747e4fSDavid du Colombier 	Mem *m;
8879a747e4fSDavid du Colombier 	int nn;
8889a747e4fSDavid du Colombier 
8899a747e4fSDavid du Colombier 	if(n < 0 || n > MaxFragSize) {
890368c31abSDavid du Colombier 		werrstr(EPacketSize);
891*9ba92a1aSDavid du Colombier 		return nil;
8929a747e4fSDavid du Colombier 	}
8939a747e4fSDavid du Colombier 	if(n <= SmallMemSize) {
894368c31abSDavid du Colombier 		lock(&freelist.lk);
895368c31abSDavid du Colombier 		m = freelist.smallmem;
8969a747e4fSDavid du Colombier 		if(m != nil)
897368c31abSDavid du Colombier 			freelist.smallmem = m->next;
8989a747e4fSDavid du Colombier 		else
899368c31abSDavid du Colombier 			freelist.nsmallmem++;
900368c31abSDavid du Colombier 		unlock(&freelist.lk);
9019a747e4fSDavid du Colombier 		nn = SmallMemSize;
9029a747e4fSDavid du Colombier 	} else {
903368c31abSDavid du Colombier 		lock(&freelist.lk);
904368c31abSDavid du Colombier 		m = freelist.bigmem;
9059a747e4fSDavid du Colombier 		if(m != nil)
906368c31abSDavid du Colombier 			freelist.bigmem = m->next;
9079a747e4fSDavid du Colombier 		else
908368c31abSDavid du Colombier 			freelist.nbigmem++;
909368c31abSDavid du Colombier 		unlock(&freelist.lk);
9109a747e4fSDavid du Colombier 		nn = BigMemSize;
9119a747e4fSDavid du Colombier 	}
9129a747e4fSDavid du Colombier 
9139a747e4fSDavid du Colombier 	if(m == nil) {
914368c31abSDavid du Colombier 		m = vtbrk(sizeof(Mem));
915368c31abSDavid du Colombier 		m->bp = vtbrk(nn);
9169a747e4fSDavid du Colombier 		m->ep = m->bp + nn;
9179a747e4fSDavid du Colombier 	}
9189a747e4fSDavid du Colombier 	assert(m->ref == 0);
9199a747e4fSDavid du Colombier 	m->ref = 1;
9209a747e4fSDavid du Colombier 
9219a747e4fSDavid du Colombier 	switch(pos) {
9229a747e4fSDavid du Colombier 	default:
9239a747e4fSDavid du Colombier 		assert(0);
9249a747e4fSDavid du Colombier 	case PFront:
9259a747e4fSDavid du Colombier 		m->rp = m->bp;
9269a747e4fSDavid du Colombier 		break;
9279a747e4fSDavid du Colombier 	case PMiddle:
9289a747e4fSDavid du Colombier 		/* leave a little bit at end */
9299a747e4fSDavid du Colombier 		m->rp = m->ep - n - 32;
9309a747e4fSDavid du Colombier 		break;
9319a747e4fSDavid du Colombier 	case PEnd:
9329a747e4fSDavid du Colombier 		m->rp = m->ep - n;
9339a747e4fSDavid du Colombier 		break;
9349a747e4fSDavid du Colombier 	}
9359a747e4fSDavid du Colombier 	/* check we did not blow it */
9369a747e4fSDavid du Colombier 	if(m->rp < m->bp)
9379a747e4fSDavid du Colombier 		m->rp = m->bp;
9389a747e4fSDavid du Colombier 	m->wp = m->rp + n;
9399a747e4fSDavid du Colombier 	assert(m->rp >= m->bp && m->wp <= m->ep);
9409a747e4fSDavid du Colombier 	return m;
9419a747e4fSDavid du Colombier }
9429a747e4fSDavid du Colombier 
9439a747e4fSDavid du Colombier static void
memfree(Mem * m)944368c31abSDavid du Colombier memfree(Mem *m)
9459a747e4fSDavid du Colombier {
9469a747e4fSDavid du Colombier 	lock(&m->lk);
9479a747e4fSDavid du Colombier 	m->ref--;
9489a747e4fSDavid du Colombier 	if(m->ref > 0) {
9499a747e4fSDavid du Colombier 		unlock(&m->lk);
9509a747e4fSDavid du Colombier 		return;
9519a747e4fSDavid du Colombier 	}
9529a747e4fSDavid du Colombier 	unlock(&m->lk);
9539a747e4fSDavid du Colombier 	assert(m->ref == 0);
9549a747e4fSDavid du Colombier 
955368c31abSDavid du Colombier /*	memset(m->bp, 0xEF, m->ep-m->bp); */
9569a747e4fSDavid du Colombier 	switch(m->ep - m->bp) {
9579a747e4fSDavid du Colombier 	default:
9589a747e4fSDavid du Colombier 		assert(0);
9599a747e4fSDavid du Colombier 	case SmallMemSize:
960368c31abSDavid du Colombier 		lock(&freelist.lk);
961368c31abSDavid du Colombier 		m->next = freelist.smallmem;
962368c31abSDavid du Colombier 		freelist.smallmem = m;
963368c31abSDavid du Colombier 		unlock(&freelist.lk);
9649a747e4fSDavid du Colombier 		break;
9659a747e4fSDavid du Colombier 	case BigMemSize:
966368c31abSDavid du Colombier 		lock(&freelist.lk);
967368c31abSDavid du Colombier 		m->next = freelist.bigmem;
968368c31abSDavid du Colombier 		freelist.bigmem = m;
969368c31abSDavid du Colombier 		unlock(&freelist.lk);
9709a747e4fSDavid du Colombier 		break;
9719a747e4fSDavid du Colombier 	}
9729a747e4fSDavid du Colombier }
9739a747e4fSDavid du Colombier 
9749a747e4fSDavid du Colombier static int
memhead(Mem * m,uchar * rp,int n)975368c31abSDavid du Colombier memhead(Mem *m, uchar *rp, int n)
9769a747e4fSDavid du Colombier {
977368c31abSDavid du Colombier 	fprint(2, "memhead called\n");
978368c31abSDavid du Colombier 	abort();
9799a747e4fSDavid du Colombier 	lock(&m->lk);
9809a747e4fSDavid du Colombier 	if(m->rp != rp) {
9819a747e4fSDavid du Colombier 		unlock(&m->lk);
982368c31abSDavid du Colombier 		return -1;
9839a747e4fSDavid du Colombier 	}
9849a747e4fSDavid du Colombier 	m->rp -= n;
9859a747e4fSDavid du Colombier 	unlock(&m->lk);
986368c31abSDavid du Colombier 	return 0;
9879a747e4fSDavid du Colombier }
9889a747e4fSDavid du Colombier 
9899a747e4fSDavid du Colombier static int
memtail(Mem * m,uchar * wp,int n)990368c31abSDavid du Colombier memtail(Mem *m, uchar *wp, int n)
9919a747e4fSDavid du Colombier {
992368c31abSDavid du Colombier 	fprint(2, "memtail called\n");
993368c31abSDavid du Colombier 	abort();
9949a747e4fSDavid du Colombier 	lock(&m->lk);
9959a747e4fSDavid du Colombier 	if(m->wp != wp) {
9969a747e4fSDavid du Colombier 		unlock(&m->lk);
997368c31abSDavid du Colombier 		return -1;
9989a747e4fSDavid du Colombier 	}
9999a747e4fSDavid du Colombier 	m->wp += n;
10009a747e4fSDavid du Colombier 	unlock(&m->lk);
1001368c31abSDavid du Colombier 	return 0;
10029a747e4fSDavid du Colombier }
1003368c31abSDavid du Colombier 
1004368c31abSDavid du Colombier #ifdef NOTDEF
1005368c31abSDavid du Colombier static void
checkpacket(Packet * p)1006368c31abSDavid du Colombier checkpacket(Packet *p)
1007368c31abSDavid du Colombier {
1008368c31abSDavid du Colombier 	int s, as;
1009368c31abSDavid du Colombier 	Frag *f;
1010368c31abSDavid du Colombier 	Frag *ff;
1011368c31abSDavid du Colombier 
1012368c31abSDavid du Colombier 	s = 0;
1013368c31abSDavid du Colombier 	as = 0;
1014368c31abSDavid du Colombier 	ff=p->first;
1015368c31abSDavid du Colombier 	for(f=p->first; f; ff=f,f=f->next){
1016368c31abSDavid du Colombier 		assert(f->p == p);
1017368c31abSDavid du Colombier 		s += FRAGSIZE(f);
1018368c31abSDavid du Colombier 		as += FRAGASIZE(f);
1019368c31abSDavid du Colombier 	}
1020368c31abSDavid du Colombier 	assert(s == p->size);
1021368c31abSDavid du Colombier 	assert(as == p->asize);
1022368c31abSDavid du Colombier 	if(p->first)
1023368c31abSDavid du Colombier 		assert(ff==p->last);
1024368c31abSDavid du Colombier }
1025368c31abSDavid du Colombier #endif
1026