Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <libsec.h>
4
#include <ip.h>
5
#include <auth.h>
6
#include "ppp.h"
7
 
8
enum {
9
	HistorySize=	8*1024,
10
	Cminmatch	= 3,		/* sintest match possible */
11
	Chshift		= 4,		/* nice compromise between space & time */
12
	Cnhash		= 1<<(Chshift*Cminmatch),
13
	HMASK		= Cnhash-1,
14
};
15
 
16
typedef struct Carena Carena;
17
struct Carena
18
{
19
	uchar	*pos;			/* current place, also amount of history filled */
20
	uchar	buf[HistorySize];
21
};
22
 
23
typedef struct Cstate Cstate;
24
struct Cstate
25
{
26
	QLock;
27
	int	count;
28
	int	reset;		/* compressor has been reset */
29
	int	front;		/* move to begining of history */
30
	ulong	sreg;		/* output shift reg */
31
	int	bits;		/* number of bits in sreg */
32
	Block	*b; 		/* output block */
33
 
34
	/*
35
	 * state for hashing compressor
36
	 */
37
	Carena	arenas[2];
38
	Carena	*hist;
39
	Carena	*ohist;
40
	ulong	hash[Cnhash];
41
	int	h;
42
	ulong	me;
43
	ulong	split;
44
 
45
	int	encrypt;
46
	uchar	startkey[16];
47
	uchar	key[16];
48
	RC4state rc4key;
49
};
50
 
51
typedef struct Uncstate Uncstate;
52
struct Uncstate
53
{
54
	int	count;	 	/* packet count - detects missing packets */
55
	int	resetid;	/* id of reset requests */
56
	uchar	his[HistorySize];
57
	int	indx;		/* current indx in history */
58
	int	size;		/* current history size */
59
	uchar	startkey[16];
60
	uchar	key[16];
61
	RC4state rc4key;
62
};
63
 
64
/* packet flags */
65
enum {
66
	Preset=		(1<<15),	/* reset history */
67
	Pfront=		(1<<14),	/* move packet to front of history */
68
	Pcompress=	(1<<13),	/* packet is compressed */
69
	Pencrypt=	(1<<12),	/* packet is encrypted */
70
};
71
 
72
enum {
73
	Lit7,		/* seven bit literal */
74
	Lit8,		/* eight bit literal */
75
	Off6,		/* six bit offset */
76
	Off8,		/* eight bit offset */
77
	Off13,		/* thirteen bit offset */
78
};
79
 
80
/* decode first four bits */
81
int decode[16] = {
82
	Lit7,	
83
	Lit7,
84
	Lit7,
85
	Lit7,
86
	Lit7,
87
	Lit7,
88
	Lit7,
89
	Lit7,
90
	Lit8,
91
	Lit8,	
92
	Lit8,
93
	Lit8,	
94
	Off13,
95
	Off13,
96
	Off8,
97
	Off6,
98
};
99
 
100
 
101
static	void		*compinit(PPP*);
102
static	Block*		comp(PPP*, ushort, Block*, int*);
103
static	void		comp2(Cstate*, uchar*, int);
104
static	Block		*compresetreq(void*, Block*);
105
static	void		compfini(void*);
106
static	void		complit(Cstate*, int);
107
static	void		compcopy(Cstate*, int, int);
108
static	void		compout(Cstate*, ulong, int);
109
static	void		compfront(Cstate*);
110
static	void		hashcheck(Cstate*);
111
static	void		compreset(Cstate*);
112
static	int		hashit(uchar*);
113
 
114
 
115
static	void		*uncinit(PPP*);
116
static	Block*		uncomp(PPP*, Block*, int *protop, Block**);
117
static	Block		*uncomp2(Uncstate *s, Block*, ushort);
118
static	void		uncfini(void*);
119
static	void		uncresetack(void*, Block*);
120
static  int		ipcheck(uchar*, int);
121
static  void		hischeck(Uncstate*);
122
 
123
static	void		setkey(uchar *key, uchar *startkey);
124
 
125
Comptype cmppc = {
126
	compinit,
127
	comp,
128
	compresetreq,
129
	compfini
130
};
131
 
132
Uncomptype uncmppc = {
133
	uncinit,
134
	uncomp,
135
	uncresetack,
136
	uncfini
137
};
138
 
139
static void *
140
compinit(PPP *ppp)
141
{
142
	Cstate *cs;
143
 
144
	cs = mallocz(sizeof(Cstate), 1);
145
	cs->hist = &cs->arenas[0];
146
	cs->ohist = &cs->arenas[1];
147
	compreset(cs);
148
	/*
149
	 * make reset clear the hash table
150
	 */
151
	cs->me = ~0;
152
	compreset(cs);
153
 
154
	cs->reset = 0;
155
 
156
	if(ppp->sendencrypted) {
157
		cs->encrypt = 1;
158
		memmove(cs->startkey, ppp->key, 16);
159
		memmove(cs->key, ppp->key, 16);
160
		setkey(cs->key, cs->startkey);
161
		setupRC4state(&cs->rc4key, cs->key, 16);
162
	}
163
 
164
	return cs;
165
}
166
 
167
static void
168
compfini(void *as)
169
{
170
	Cstate *cs;
171
 
172
	cs = as;
173
	free(cs);
174
}
175
 
176
 
177
static Block*
178
comp(PPP *ppp, ushort proto, Block *b, int *protop)
179
{
180
	Cstate *s;
181
	int n, n2;
182
	ushort count;
183
 
184
	s = ppp->cstate;
185
	*protop = 0;
186
 
187
	qlock(s);
188
 
189
	/* put protocol into b */
190
	b->rptr -= 2;
191
	if(b->rptr < b->base)
192
		sysfatal("mppc: not enough header in block");
193
	b->rptr[0] = proto>>8;
194
	b->rptr[1] = proto;
195
 
196
	n = BLEN(b);
197
	s->bits = 0;
198
	s->b = allocb(n*9/8+20);
199
	s->b->wptr += 2;	/* leave room for mppc header */
200
 
201
	comp2(s, b->rptr, n);
202
 
203
	/* flush sreg */
204
	if(s->bits)
205
		*s->b->wptr++ = s->sreg<<(8-s->bits);
206
	if(s->b->wptr > s->b->lim)
207
		sysfatal("mppc: comp: output block overflowed");
208
 
209
	n2 = BLEN(s->b);
210
 
211
	if(n2 > n-2 && !s->encrypt) {
212
		/* expened and not excrypting so send as a regular packet */
213
//netlog("mppc: comp: expanded\n"); 
214
		compreset(s);
215
		freeb(s->b);
216
		b->rptr += 2;
217
		qunlock(s);
218
		*protop = proto;
219
		return b;
220
	}
221
 
222
	count = s->count++;
223
	s->count &= 0xfff;
224
	if(s->front)
225
		count |= Pfront;
226
	if(s->reset)
227
		count |= Preset;
228
	s->reset = 0;
229
	s->front = 0;
230
 
231
	if(n2 > n) {
232
//netlog("mppc: comp: expanded\n"); 
233
		freeb(s->b);
234
		/* make room for count */
235
		compreset(s);
236
		b->rptr -= 2;
237
	} else {
238
		freeb(b);
239
		b = s->b;
240
		count |= Pcompress;
241
	}
242
	s->b = nil;
243
 
244
	if(s->encrypt) {
245
		count |= Pencrypt;
246
		if((count&0xff) == 0xff) {
247
//netlog("mppc: comp: changing key\n"); 
248
			setkey(s->key, s->startkey);
249
			setupRC4state(&s->rc4key, s->key, 16);
250
			rc4(&s->rc4key, s->key, 16);
251
			setupRC4state(&s->rc4key, s->key, 16);
252
		} else if(count&Preset)
253
			setupRC4state(&s->rc4key, s->key, 16);
254
		rc4(&s->rc4key, b->rptr+2, BLEN(b)-2);
255
//netlog("mppc: encrypt %ux\n", count);
256
	}
257
 
258
	b->rptr[0] = count>>8;
259
	b->rptr[1] = count;
260
 
261
	qunlock(s);
262
 
263
	*protop = Pcdata;
264
	return b;
265
}
266
 
267
static Block *
268
compresetreq(void *as, Block *b)
269
{
270
	Cstate *cs;
271
 
272
	cs = as;
273
netlog("mppc: comp: reset request\n");
274
	qlock(cs);
275
	compreset(cs);
276
	qunlock(cs);
277
 
278
	freeb(b);
279
 
280
	return nil;
281
}
282
 
283
static void
284
comp2(Cstate *cs, uchar *p, int n)
285
{
286
	Carena *hist, *ohist;
287
	ulong *hash, me, split, you, last;
288
	uchar *s, *t, *et, *buf, *obuf, *pos, *opos;
289
	int i, h, m;
290
 
291
	/*
292
	 * check for wrap
293
	 */
294
	if(cs->me + n < cs->me)
295
		compreset(cs);
296
 
297
	if(cs->hist->pos + n > cs->hist->buf + HistorySize)
298
		compfront(cs);
299
 
300
	hist = cs->hist;
301
	ohist = cs->ohist;
302
 
303
	hash = cs->hash;
304
	me = cs->me;
305
	split = cs->split;
306
 
307
	memmove(hist->pos, p, n);
308
	p = hist->pos;
309
	hist->pos = pos = p + n;
310
 
311
	m = Cminmatch;
312
	if(m > n)
313
		m = n;
314
	h = cs->h;
315
	for(i = 0; i < m; i++) {
316
		h = (((h)<<Chshift) ^ p[i]) & HMASK;
317
		last = me + (i - (Cminmatch-1));
318
		if(last >= split && last != me)
319
			hash[h] = last;
320
	}
321
 
322
	buf = hist->buf - split;
323
	obuf = ohist->buf + HistorySize - split;
324
	opos = ohist->pos;
325
	while(p < pos) {
326
		you = hash[h];
327
		if(you < split) {
328
			if(me - you >= HistorySize)
329
				t = opos;
330
			else
331
				t = obuf + you;
332
			et = opos;
333
		} else {
334
			t = buf + you;
335
			et = pos;
336
		}
337
		m = pos - p;
338
		if(m < et - t)
339
			et = t + m;
340
		for(s = p; t < et; t++) {
341
			if(*s != *t)
342
				break;
343
			s++;
344
		}
345
		m = s - p;
346
		if(m < Cminmatch) {
347
			complit(cs, *p);
348
			s = p + 1;
349
		} else
350
			compcopy(cs, me - you, m);
351
 
352
		for(; p != s; p++) {
353
			if(p + Cminmatch <= pos) {
354
				hash[h] = me;
355
				if(p + Cminmatch < pos)
356
					h = (((h)<<Chshift) ^ p[Cminmatch]) & HMASK;
357
			}
358
			me++;
359
		}
360
	}
361
 
362
	cs->h = h;
363
	cs->me = me;
364
}
365
 
366
static void
367
compfront(Cstate *cs)
368
{
369
	Carena *th;
370
 
371
	cs->front = 1;
372
 
373
	th = cs->ohist;
374
	cs->ohist = cs->hist;
375
	cs->hist = th;
376
	cs->hist->pos = cs->hist->buf;
377
	cs->h = 0;
378
	cs->me = cs->split + HistorySize;
379
	cs->split = cs->me;
380
}
381
 
382
static void
383
compreset(Cstate *cs)
384
{
385
	ulong me;
386
 
387
	cs->reset = 1;
388
 
389
	me = cs->me;
390
	if(me + 2 * HistorySize < me){
391
		me = 0;
392
		memset(cs->hash, 0, sizeof(cs->hash));
393
	}
394
	cs->me = me + 2 * HistorySize;
395
	cs->split = cs->me;
396
	cs->hist->pos = cs->hist->buf;
397
	cs->ohist->pos = cs->ohist->buf;
398
}
399
 
400
static void
401
complit(Cstate *s, int c)
402
{
403
	if(c&0x80)
404
		compout(s, 0x100|(c&0x7f), 9);
405
	else
406
		compout(s, c, 8);
407
}
408
 
409
static void
410
compcopy(Cstate *s, int off, int len)
411
{
412
	int i;
413
	ulong mask;
414
 
415
	if(off<64)
416
		compout(s, 0x3c0|off, 10);
417
	else if(off<320)
418
		compout(s, 0xe00|(off-64), 12);
419
	else
420
		compout(s, 0xc000|(off-320), 16);
421
	if(len < 3)
422
		sysfatal("compcopy: bad len: %d", len);
423
	if(len == 3)
424
		compout(s, 0, 1);
425
	else {
426
		for(i=3; (1<<i) <= len; i++)
427
			;
428
		mask = (1<<(i-1))-1;
429
		compout(s, (((1<<(i-2))-1)<<i) | len&mask, (i-1)<<1);
430
	}
431
}
432
 
433
static void
434
compout(Cstate *s, ulong data, int bits)
435
{
436
	ulong sreg;
437
 
438
	sreg = s->sreg;
439
	sreg <<= bits;
440
	sreg |= data;
441
	bits += s->bits;
442
	while(bits >= 8) {
443
		*s->b->wptr++ = sreg>>(bits-8);
444
		bits -= 8;
445
	}
446
	s->sreg = sreg;
447
	s->bits = bits;
448
}
449
 
450
void
451
printkey(uchar *key)
452
{
453
	char buf[200], *p;
454
	int i;
455
 
456
	p = buf;
457
	for(i=0; i<16; i++)
458
		p += sprint(p, "%.2ux ", key[i]);
459
//netlog("key = %s\n", buf);
460
}
461
 
462
static	void *
463
uncinit(PPP *ppp)
464
{
465
	Uncstate *s;
466
 
467
	s = mallocz(sizeof(Uncstate), 1);
468
 
469
	s->count = 0xfff;	/* count of non existant last packet */
470
	memmove(s->startkey, ppp->key, 16);
471
	memmove(s->key, ppp->key, 16);
472
	setkey(s->key, s->startkey);
473
	setupRC4state(&s->rc4key, s->key, 16);
474
 
475
	return s;
476
}
477
 
478
static	Block*
479
uncomp(PPP *ppp, Block *b, int *protop, Block **r)
480
{
481
	Uncstate *s;
482
	ushort proto;
483
	ushort count;
484
	Lcpmsg *m;
485
 
486
	*r = nil;
487
	*protop = 0;
488
	s = ppp->uncstate;
489
	if(BLEN(b) < 2){
490
		syslog(0, "ppp", ": mppc: short packet\n");
491
		freeb(b);
492
		return nil;
493
	}
494
	count = nhgets(b->rptr);
495
	b->rptr += 2;
496
 
497
	b = uncomp2(s, b, count);
498
 
499
	if(b == nil) {
500
//netlog("ppp: mppc: reset request\n");
501
		/* return reset request packet */
502
		*r = alloclcp(Lresetreq, s->resetid++, 4, &m);
503
		hnputs(m->len, 4);
504
		*protop = 0;
505
		return nil;
506
	}
507
 
508
	if(BLEN(b) < 2){
509
		syslog(0, "ppp", ": mppc: short packet\n");
510
		freeb(b);
511
		*protop = 0;
512
		return nil;
513
	}
514
	proto = nhgets(b->rptr);
515
	b->rptr += 2;
516
 
517
/*
518
	if(proto == 0x21)
519
		if(!ipcheck(b->rptr, BLEN(b)))
520
			hischeck(s);
521
*/
522
 
523
	*protop = proto;
524
	return b;
525
}
526
 
527
#define NEXTBYTE	sreg = (sreg<<8) | *p++; n--; bits += 8
528
int	maxoff;
529
 
530
static	Block*
531
uncomp2(Uncstate *s, Block *b, ushort count)
532
{
533
	int ecount, n, bits, off, len, ones;
534
	ulong sreg;
535
	int t;
536
	uchar *p, c, *hp, *hs, *he, *hq;
537
 
538
	if(count&Preset) {
539
//netlog("mppc reset\n");
540
		s->indx = 0;
541
		s->size = 0;
542
		setupRC4state(&s->rc4key, s->key, 16);
543
	} else {
544
		ecount = (s->count+1)&0xfff;
545
		if((count&0xfff) != ecount) {
546
netlog("******* bad count - got %ux expected %ux\n", count&0xfff, ecount);
547
			freeb(b);
548
			return nil;
549
		}
550
		if(count&Pfront) {
551
			s->indx = 0;
552
/*			netlog("ppp: mppc: frount flag set\n"); */
553
		}
554
	}
555
 
556
	/* update key */
557
	n = (((count+1)>>8)&0xf) - (((s->count+1)>>8)&0xf);
558
	if(n < 0)
559
		n += 16;
560
//netlog("mppc count = %ux oldcount %ux n = %d\n", count, s->count, n);
561
	if(n < 0 || n > 1) {
562
		syslog(0, "ppp", ": mppc bad count %ux, %ux", count, s->count);
563
		freeb(b);
564
		return nil;
565
	}
566
	if(n == 1) {
567
		setkey(s->key, s->startkey);
568
		setupRC4state(&s->rc4key, s->key, 16);
569
		rc4(&s->rc4key, s->key, 16);
570
		setupRC4state(&s->rc4key, s->key, 16);
571
	}
572
 
573
	s->count = count;
574
 
575
	n = BLEN(b);
576
	p = b->rptr;
577
	if(count & Pencrypt) {
578
//netlog("mppc unencrypt count = %ux\n", count);
579
		rc4(&s->rc4key, p, n);
580
	}
581
 
582
	if(!(count & Pcompress)) {
583
//netlog("uncompress blen = %d\n", BLEN(b));
584
		return  b;
585
	}
586
 
587
	bits = 0;
588
	sreg = 0;
589
	hs = s->his;		/* history start */
590
	hp = hs+s->indx;	/* write pointer in history */
591
	he = hs+sizeof(s->his);	/* hsitory end */
592
	for(;;) {
593
		if(bits<4) {
594
			if(n==0) goto Done;
595
			NEXTBYTE;
596
		}
597
		t = decode[(sreg>>(bits-4))&0xf];
598
		switch(t) {
599
		default:
600
			sysfatal("mppc: bad decode!");
601
		case Lit7:
602
			bits -= 1;
603
			if(bits<7) {
604
				if(n==0) goto Done;
605
				NEXTBYTE;
606
			}
607
			c = (sreg>>(bits-7))&0x7f;
608
			bits -= 7;
609
			if(hp >= he) goto His;
610
			*hp++ = c;
611
/* netlog("\tlit7 %.2ux\n", c); */
612
			continue;
613
		case Lit8:
614
			bits -= 2;
615
			if(bits<7) {
616
				if(n==0) goto Eof;
617
				NEXTBYTE;
618
			}
619
			c = 0x80 | ((sreg>>(bits-7))&0x7f);
620
			bits -= 7;
621
			if(hp >= he) goto His;
622
			*hp++ = c;
623
/* netlog("\tlit8 %.2ux\n", c); */
624
			continue;
625
		case Off6:
626
			bits -= 4;
627
			if(bits<6) {
628
				if(n==0) goto Eof;
629
				NEXTBYTE;
630
			}
631
			off = (sreg>>(bits-6))&0x3f;
632
			bits -= 6;
633
			break;
634
		case Off8:
635
			bits -= 4;
636
			if(bits<8) {
637
				if(n==0) goto Eof;
638
				NEXTBYTE;
639
			}
640
			off = ((sreg>>(bits-8))&0xff)+64;
641
			bits -= 8;
642
			break;
643
		case Off13:
644
			bits -= 3;
645
			while(bits<13) {
646
				if(n==0) goto Eof;
647
				NEXTBYTE;
648
			}
649
			off = ((sreg>>(bits-13))&0x1fff)+320;
650
			bits -= 13;
651
/* netlog("\toff=%d bits = %d sreg = %ux t = %x\n", off, bits, sreg, t); */
652
			break;
653
		}
654
		for(ones=0;;ones++) {
655
			if(bits == 0) {
656
				if(n==0) goto Eof;
657
				NEXTBYTE;
658
			}
659
			bits--;
660
			if(!(sreg&(1<<bits)))
661
				break;
662
		}
663
		if(ones>11) {
664
netlog("ppp: mppc: bad length %d\n", ones);
665
			freeb(b);
666
			return nil;
667
		}
668
		if(ones == 0) {
669
			len = 3;
670
		} else {
671
			ones++;
672
			while(bits<ones) {
673
				if(n==0) goto Eof;
674
				NEXTBYTE;
675
			}
676
			len = (1<<ones) | ((sreg>>(bits-ones))&((1<<ones)-1));
677
			bits -= ones;
678
		}
679
 
680
		hq = hp-off;
681
		if(hq < hs) {
682
			hq += sizeof(s->his);
683
			if(hq-hs+len > s->size) 
684
				goto His;
685
		}
686
		if(hp+len > he) goto His;
687
		while(len) {
688
			*hp++ = *hq++;
689
			len--;
690
		}
691
	}
692
Done:
693
	freeb(b);
694
 
695
	/* build up return block */
696
	hq = hs+s->indx;
697
	len = hp-hq;
698
	b = allocb(len);
699
	memmove(b->wptr, hq, len);
700
	b->wptr += len;
701
netlog("ppp: mppc: len %d bits = %d n=%d\n", len, bits, n);
702
 
703
	s->indx += len;
704
	if(s->indx > s->size)
705
		s->size = s->indx;
706
 
707
	return b;
708
Eof:
709
netlog("*****unexpected end of data\n");
710
	freeb(b);
711
	return nil;
712
His:
713
netlog("*****bad history\n");
714
	freeb(b);
715
	return nil;
716
}
717
 
718
static	void
719
uncresetack(void*, Block*)
720
{
721
}
722
 
723
static	void
724
uncfini(void *as)
725
{
726
	Uncstate *s;
727
 
728
	s = as;	
729
	free(s);
730
}
731
 
732
static void
733
setkey(uchar *key, uchar *startkey)
734
{
735
	uchar pad[40];
736
	SHAstate *s;
737
	uchar digest[SHA1dlen];
738
 
739
	s = sha1(startkey, 16, nil, nil);
740
	memset(pad, 0, 40);
741
	sha1(pad, 40, nil, s);
742
	sha1(key, 16, nil, s);
743
	memset(pad, 0xf2, 40);
744
	sha1(pad, 40, digest, s);
745
	memmove(key, digest, 16);
746
}
747
 
748
 
749
/* code to check if IP packet looks good */
750
 
751
typedef struct Iphdr Iphdr;
752
struct Iphdr
753
{
754
	uchar	vihl;		/* Version and header length */
755
	uchar	tos;		/* Type of service */
756
	uchar	length[2];	/* packet length */
757
	uchar	id[2];		/* Identification */
758
	uchar	frag[2];	/* Fragment information */
759
	uchar	ttl;		/* Time to live */
760
	uchar	proto;		/* Protocol */
761
	uchar	cksum[2];	/* Header checksum */
762
	uchar	src[4];		/* Ip source */
763
	uchar	dst[4];		/* Ip destination */
764
};
765
 
766
enum
767
{
768
	QMAX		= 64*1024-1,
769
	IP_TCPPROTO	= 6,
770
	TCP_IPLEN	= 8,
771
	TCP_PHDRSIZE	= 12,
772
	TCP_HDRSIZE	= 20,
773
	TCP_PKT		= TCP_IPLEN+TCP_PHDRSIZE,
774
};
775
 
776
enum
777
{
778
	UDP_PHDRSIZE	= 12,
779
	UDP_HDRSIZE	= 20,
780
	UDP_IPHDR	= 8,
781
	IP_UDPPROTO	= 17,
782
	UDP_USEAD	= 12,
783
	UDP_RELSIZE	= 16,
784
 
785
	Udprxms		= 200,
786
	Udptickms	= 100,
787
	Udpmaxxmit	= 10,
788
};
789
 
790
typedef struct UDPhdr UDPhdr;
791
struct UDPhdr
792
{
793
	/* ip header */
794
	uchar	vihl;		/* Version and header length */
795
	uchar	tos;		/* Type of service */
796
	uchar	length[2];	/* packet length */
797
	uchar	id[2];		/* Identification */
798
	uchar	frag[2];	/* Fragment information */
799
	uchar	Unused;	
800
	uchar	udpproto;	/* Protocol */
801
	uchar	udpplen[2];	/* Header plus data length */
802
	uchar	udpsrc[4];	/* Ip source */
803
	uchar	udpdst[4];	/* Ip destination */
804
 
805
	/* udp header */
806
	uchar	udpsport[2];	/* Source port */
807
	uchar	udpdport[2];	/* Destination port */
808
	uchar	udplen[2];	/* data length */
809
	uchar	udpcksum[2];	/* Checksum */
810
};
811
 
812
typedef struct TCPhdr TCPhdr;
813
struct TCPhdr
814
{
815
	uchar	vihl;		/* Version and header length */
816
	uchar	tos;		/* Type of service */
817
	uchar	length[2];	/* packet length */
818
	uchar	id[2];		/* Identification */
819
	uchar	frag[2];	/* Fragment information */
820
	uchar	Unused;
821
	uchar	proto;
822
	uchar	tcplen[2];
823
	uchar	tcpsrc[4];
824
	uchar	tcpdst[4];
825
	uchar	tcpsport[2];
826
	uchar	tcpdport[2];
827
	uchar	tcpseq[4];
828
	uchar	tcpack[4];
829
	uchar	tcpflag[2];
830
	uchar	tcpwin[2];
831
	uchar	tcpcksum[2];
832
	uchar	tcpurg[2];
833
	/* Options segment */
834
	uchar	tcpopt[2];
835
	uchar	tcpmss[2];
836
};
837
 
838
static void
839
hischeck(Uncstate *s)
840
{
841
	uchar *p;
842
	Iphdr *iph;
843
	int len;
844
 
845
	p = s->his;
846
 
847
netlog("***** history check\n");
848
	while(p < s->his+s->size) {
849
		if(p[0] != 0 || p[1] != 0x21) {
850
netlog("***** unknown protocol\n");
851
			return;
852
		}
853
		p += 2;
854
netlog("off = %ld ", p-s->his);
855
		iph = (Iphdr*)p;
856
		len = nhgets(iph->length);
857
		ipcheck(p, len);
858
		p += len;
859
	}
860
}
861
 
862
 
863
static int
864
ipcheck(uchar *p, int len)
865
{
866
	Iphdr *iph;
867
	TCPhdr *tcph;
868
	ushort length;
869
	UDPhdr *uh;
870
	Block *bp;
871
	ushort cksum;
872
	int good;
873
 
874
	bp = allocb(len);
875
	memmove(bp->wptr, p, len);
876
	bp->wptr += len;
877
 
878
	good = 1;
879
 
880
	iph = (Iphdr *)(bp->rptr);
881
/* netlog("ppp: mppc: ipcheck %I %I len %d proto %d\n", iph->src, iph->dst, BLEN(bp), iph->proto); */
882
 
883
	if(len != nhgets(iph->length)) {
884
		netlog("***** bad length! %d %d\n", len, nhgets(iph->length));
885
		good = 0;
886
	}
887
 
888
	cksum = ipcsum(&iph->vihl);
889
	if(cksum) {
890
		netlog("***** IP proto cksum!!! %I %ux\n", iph->src, cksum);
891
		good = 0;
892
	}
893
 
894
	switch(iph->proto) {
895
	default:
896
		break;
897
	case IP_TCPPROTO:
898
 
899
		tcph = (TCPhdr*)(bp->rptr);
900
 
901
		length = nhgets(tcph->length);
902
 
903
		tcph->Unused = 0;
904
		hnputs(tcph->tcplen, length-TCP_PKT);
905
		cksum = ptclcsum(bp, TCP_IPLEN, length-TCP_IPLEN);
906
		if(cksum) {
907
			netlog("***** bad tcp proto cksum %ux!!!\n", cksum);
908
			good = 0;
909
		}
910
		break;
911
	case IP_UDPPROTO:
912
		uh = (UDPhdr*)(bp->rptr);
913
 
914
		/* Put back pseudo header for checksum */
915
		uh->Unused = 0;
916
		len = nhgets(uh->udplen);
917
		hnputs(uh->udpplen, len);
918
 
919
		if(nhgets(uh->udpcksum)) {
920
			cksum = ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE);
921
			if(cksum) {
922
				netlog("***** udp: proto cksum!!! %I %ux\n", uh->udpsrc, cksum);
923
				good = 0;
924
			}
925
		}
926
		break;
927
	}
928
	freeb(bp);
929
	return good;
930
}