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 *
compinit(PPP * ppp)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
compfini(void * as)168 compfini(void *as)
169 {
170 Cstate *cs;
171
172 cs = as;
173 free(cs);
174 }
175
176
177 static Block*
comp(PPP * ppp,ushort proto,Block * b,int * protop)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 *
compresetreq(void * as,Block * b)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
comp2(Cstate * cs,uchar * p,int n)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
compfront(Cstate * cs)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
compreset(Cstate * cs)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
complit(Cstate * s,int c)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
compcopy(Cstate * s,int off,int len)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
compout(Cstate * s,ulong data,int bits)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
printkey(uchar * key)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 *
uncinit(PPP * ppp)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*
uncomp(PPP * ppp,Block * b,int * protop,Block ** r)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*
uncomp2(Uncstate * s,Block * b,ushort count)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
uncresetack(void *,Block *)719 uncresetack(void*, Block*)
720 {
721 }
722
723 static void
uncfini(void * as)724 uncfini(void *as)
725 {
726 Uncstate *s;
727
728 s = as;
729 free(s);
730 }
731
732 static void
setkey(uchar * key,uchar * startkey)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
hischeck(Uncstate * s)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
ipcheck(uchar * p,int len)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 }
931