]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/ppp/mppc.c
format pointer subtraction results with %zd instead of %ld (for long -> intptr on...
[plan9front.git] / sys / src / cmd / ip / ppp / mppc.c
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");
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");
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 = %zd ", 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 }