added buflen arg to vj_uncompress_uncomp
[ppp.git] / modules / ppp_comp.c
1 /*
2  * ppp_comp.c - STREAMS module for kernel-level compression and CCP support.
3  *
4  * Copyright (c) 1994 The Australian National University.
5  * All rights reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation is hereby granted, provided that the above copyright
9  * notice appears in all copies.  This software is provided without any
10  * warranty, express or implied. The Australian National University
11  * makes no representations about the suitability of this software for
12  * any purpose.
13  *
14  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
15  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
17  * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
18  * OF SUCH DAMAGE.
19  *
20  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
21  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
24  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
25  * OR MODIFICATIONS.
26  *
27  * $Id: ppp_comp.c,v 1.3 1996/05/28 00:55:44 paulus Exp $
28  */
29
30 /*
31  * This file is used under SVR4, Solaris 2, SunOS 4, and OSF/1.
32  */
33
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/errno.h>
37 #include <sys/stream.h>
38
39 #ifdef SVR4
40 #include <sys/conf.h>
41 #include <sys/cmn_err.h>
42 #include <sys/ddi.h>
43 #else
44 #include <sys/user.h>
45 #endif /* SVR4 */
46
47 #include <net/ppp_defs.h>
48 #include <net/pppio.h>
49 #include "ppp_mod.h"
50
51 #include <netinet/in.h>
52 #include <netinet/in_systm.h>
53 #include <netinet/ip.h>
54 #include <net/vjcompress.h>
55
56 #define PACKETPTR       mblk_t *
57 #include <net/ppp-comp.h>
58
59 MOD_OPEN_DECL(ppp_comp_open);
60 MOD_CLOSE_DECL(ppp_comp_close);
61 static int ppp_comp_rput __P((queue_t *, mblk_t *));
62 static int ppp_comp_rsrv __P((queue_t *));
63 static int ppp_comp_wput __P((queue_t *, mblk_t *));
64 static int ppp_comp_wsrv __P((queue_t *));
65 static void ppp_comp_ccp __P((queue_t *, mblk_t *, int));
66 static int msg_byte __P((mblk_t *, unsigned int));
67
68 /* Extract byte i of message mp. */
69 #define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \
70                          msg_byte((mp), (i)))
71
72 /* Is this LCP packet one we have to transmit using LCP defaults? */
73 #define LCP_USE_DFLT(mp)        (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
74
75 static struct module_info minfo = {
76     0xbadf, "ppp_comp", 0, INFPSZ, 16384, 4096,
77 };
78
79 static struct qinit r_init = {
80     ppp_comp_rput, ppp_comp_rsrv, ppp_comp_open, ppp_comp_close,
81     NULL, &minfo, NULL
82 };
83
84 static struct qinit w_init = {
85     ppp_comp_wput, ppp_comp_wsrv, NULL, NULL, NULL, &minfo, NULL
86 };
87
88 struct streamtab ppp_compinfo = {
89     &r_init, &w_init, NULL, NULL
90 };
91
92 int ppp_comp_count;             /* number of module instances in use */
93
94 typedef struct comp_state {
95     int         flags;
96     int         mru;
97     int         mtu;
98     int         unit;
99     struct compressor *xcomp;
100     void        *xstate;
101     struct compressor *rcomp;
102     void        *rstate;
103     struct vjcompress vj_comp;
104     int         vj_last_ierrors;
105     struct pppstat stats;
106 } comp_state_t;
107
108 /* Bits in flags are as defined in pppio.h. */
109 #define CCP_ERR         (CCP_ERROR | CCP_FATALERROR)
110 #define LAST_MOD        0x1000000       /* no ppp modules below us */
111
112 #define MAX_IPHDR       128     /* max TCP/IP header size */
113 #define MAX_VJHDR       20      /* max VJ compressed header size (?) */
114
115 #undef MIN              /* just in case */
116 #define MIN(a, b)       ((a) < (b)? (a): (b))
117
118 /*
119  * List of compressors we know about.
120  */
121
122 extern struct compressor ppp_bsd_compress;
123 extern struct compressor ppp_deflate;
124
125 struct compressor *ppp_compressors[] = {
126 #if DO_BSD_COMPRESS
127     &ppp_bsd_compress,
128 #endif
129 #if DO_DEFLATE
130     &ppp_deflate,
131 #endif
132     NULL
133 };
134
135 /*
136  * STREAMS module entry points.
137  */
138 MOD_OPEN(ppp_comp_open)
139 {
140     comp_state_t *cp;
141
142     if (q->q_ptr == NULL) {
143         cp = (comp_state_t *) ALLOC_SLEEP(sizeof(comp_state_t));
144         if (cp == NULL)
145             OPEN_ERROR(ENOSR);
146         WR(q)->q_ptr = q->q_ptr = (caddr_t) cp;
147         bzero((caddr_t)cp, sizeof(comp_state_t));
148         cp->mru = PPP_MRU;
149         cp->mtu = PPP_MRU;
150         cp->xstate = NULL;
151         cp->rstate = NULL;
152         vj_compress_init(&cp->vj_comp, -1);
153         ++ppp_comp_count;
154         qprocson(q);
155     }
156     return 0;
157 }
158
159 MOD_CLOSE(ppp_comp_close)
160 {
161     comp_state_t *cp;
162
163     qprocsoff(q);
164     cp = (comp_state_t *) q->q_ptr;
165     if (cp != NULL) {
166         if (cp->xstate != NULL)
167             (*cp->xcomp->comp_free)(cp->xstate);
168         if (cp->rstate != NULL)
169             (*cp->rcomp->decomp_free)(cp->rstate);
170         FREE(cp, sizeof(comp_state_t));
171         q->q_ptr = NULL;
172         OTHERQ(q)->q_ptr = NULL;
173         --ppp_comp_count;
174     }
175     return 0;
176 }
177
178 static int
179 ppp_comp_wput(q, mp)
180     queue_t *q;
181     mblk_t *mp;
182 {
183     struct iocblk *iop;
184     comp_state_t *cp;
185     int error, len;
186     int flags, mask;
187     mblk_t *np;
188     struct compressor **comp;
189     struct ppp_stats *psp;
190     struct ppp_comp_stats *csp;
191     unsigned char *opt_data;
192     int nxslots, nrslots;
193
194     cp = (comp_state_t *) q->q_ptr;
195     switch (mp->b_datap->db_type) {
196
197     case M_DATA:
198         putq(q, mp);
199         break;
200
201     case M_IOCTL:
202         iop = (struct iocblk *) mp->b_rptr;
203         error = EINVAL;
204         switch (iop->ioc_cmd) {
205
206         case PPPIO_CFLAGS:
207             /* set/get CCP state */
208             if (iop->ioc_count != 2 * sizeof(int))
209                 break;
210             flags = ((int *) mp->b_cont->b_rptr)[0];
211             mask = ((int *) mp->b_cont->b_rptr)[1];
212             cp->flags = (cp->flags & ~mask) | (flags & mask);
213             if ((mask & CCP_ISOPEN) && (flags & CCP_ISOPEN) == 0) {
214                 if (cp->xstate != NULL) {
215                     (*cp->xcomp->comp_free)(cp->xstate);
216                     cp->xstate = NULL;
217                 }
218                 if (cp->rstate != NULL) {
219                     (*cp->rcomp->decomp_free)(cp->rstate);
220                     cp->rstate = NULL;
221                 }
222                 cp->flags &= ~CCP_ISUP;
223             }
224             error = 0;
225             iop->ioc_count = sizeof(int);
226             ((int *) mp->b_cont->b_rptr)[0] = cp->flags;
227             mp->b_cont->b_wptr = mp->b_cont->b_rptr + sizeof(int);
228             break;
229
230         case PPPIO_VJINIT:
231             /*
232              * Initialize VJ compressor/decompressor
233              */
234             if (iop->ioc_count != 2)
235                 break;
236             nxslots = mp->b_cont->b_rptr[0] + 1;
237             nrslots = mp->b_cont->b_rptr[1] + 1;
238             if (nxslots > MAX_STATES || nrslots > MAX_STATES)
239                 break;
240             vj_compress_init(&cp->vj_comp, nxslots);
241             cp->vj_last_ierrors = cp->stats.ppp_ierrors;
242             error = 0;
243             iop->ioc_count = 0;
244             break;
245
246         case PPPIO_XCOMP:
247         case PPPIO_RCOMP:
248             if (iop->ioc_count <= 0)
249                 break;
250             opt_data = mp->b_cont->b_rptr;
251             len = mp->b_cont->b_wptr - opt_data;
252             if (len > iop->ioc_count)
253                 len = iop->ioc_count;
254             if (opt_data[1] < 2 || opt_data[1] > len)
255                 break;
256             for (comp = ppp_compressors; *comp != NULL; ++comp)
257                 if ((*comp)->compress_proto == opt_data[0]) {
258                     /* here's the handler! */
259                     error = 0;
260                     if (iop->ioc_cmd == PPPIO_XCOMP) {
261                         if (cp->xstate != NULL)
262                             (*cp->xcomp->comp_free)(cp->xstate);
263                         cp->xcomp = *comp;
264                         cp->xstate = (*comp)->comp_alloc(opt_data, len);
265                         if (cp->xstate == NULL)
266                             error = ENOSR;
267                     } else {
268                         if (cp->rstate != NULL)
269                             (*cp->rcomp->decomp_free)(cp->rstate);
270                         cp->rcomp = *comp;
271                         cp->rstate = (*comp)->decomp_alloc(opt_data, len);
272                         if (cp->rstate == NULL)
273                             error = ENOSR;
274                     }
275                     break;
276                 }
277             iop->ioc_count = 0;
278             break;
279
280         case PPPIO_GETSTAT:
281             if ((cp->flags & LAST_MOD) == 0) {
282                 error = -1;     /* let the ppp_ahdl module handle it */
283                 break;
284             }
285             np = allocb(sizeof(struct ppp_stats), BPRI_HI);
286             if (np == 0) {
287                 error = ENOSR;
288                 break;
289             }
290             if (mp->b_cont != 0)
291                 freemsg(mp->b_cont);
292             mp->b_cont = np;
293             psp = (struct ppp_stats *) np->b_wptr;
294             np->b_wptr += sizeof(struct ppp_stats);
295             iop->ioc_count = sizeof(struct ppp_stats);
296             psp->p = cp->stats;
297             psp->vj = cp->vj_comp.stats;
298             error = 0;
299             break;
300
301         case PPPIO_GETCSTAT:
302             np = allocb(sizeof(struct ppp_comp_stats), BPRI_HI);
303             if (np == 0) {
304                 error = ENOSR;
305                 break;
306             }
307             if (mp->b_cont != 0)
308                 freemsg(mp->b_cont);
309             mp->b_cont = np;
310             csp = (struct ppp_comp_stats *) np->b_wptr;
311             np->b_wptr += sizeof(struct ppp_comp_stats);
312             iop->ioc_count = sizeof(struct ppp_comp_stats);
313             bzero((caddr_t)csp, sizeof(struct ppp_comp_stats));
314             if (cp->xstate != 0)
315                 (*cp->xcomp->comp_stat)(cp->xstate, &csp->c);
316             if (cp->rstate != 0)
317                 (*cp->rcomp->decomp_stat)(cp->rstate, &csp->d);
318             error = 0;
319             break;
320
321         case PPPIO_LASTMOD:
322             cp->flags |= LAST_MOD;
323             error = 0;
324             break;
325
326         default:
327             error = -1;
328             break;
329         }
330
331         if (error < 0)
332             putnext(q, mp);
333         else if (error == 0) {
334             mp->b_datap->db_type = M_IOCACK;
335             qreply(q, mp);
336         } else {
337             mp->b_datap->db_type = M_IOCNAK;
338             iop->ioc_error = error;
339             iop->ioc_count = 0;
340             qreply(q, mp);
341         }
342         break;
343
344     case M_CTL:
345         switch (*mp->b_rptr) {
346         case PPPCTL_MTU:
347             cp->mtu = ((unsigned short *)mp->b_rptr)[1];
348             break;
349         case PPPCTL_MRU:
350             cp->mru = ((unsigned short *)mp->b_rptr)[1];
351             break;
352         case PPPCTL_UNIT:
353             cp->unit = mp->b_rptr[1];
354             break;
355         }
356         putnext(q, mp);
357         break;
358
359     default:
360         putnext(q, mp);
361     }
362 }
363
364 static int
365 ppp_comp_wsrv(q)
366     queue_t *q;
367 {
368     mblk_t *mp, *cmp = NULL, *np;
369     comp_state_t *cp;
370     int len, proto, type, hlen, code;
371     struct ip *ip;
372     unsigned char *vjhdr, *dp;
373
374     cp = (comp_state_t *) q->q_ptr;
375     while ((mp = getq(q)) != 0) {
376         /* assert(mp->b_datap->db_type == M_DATA) */
377         if (!canputnext(q)) {
378             putbq(q, mp);
379             return;
380         }
381
382         /*
383          * First check the packet length and work out what the protocol is.
384          */
385         len = msgdsize(mp);
386         if (len < PPP_HDRLEN) {
387             DPRINT1("ppp_comp_wsrv: bogus short packet (%d)\n", len);
388             freemsg(mp);
389             cp->stats.ppp_oerrors++;
390             putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
391             continue;
392         }
393         proto = (MSG_BYTE(mp, 2) << 8) + MSG_BYTE(mp, 3);
394
395         /*
396          * Make sure we've got enough data in the first mblk
397          * and that we are its only user.
398          */
399         if (proto = PPP_CCP)
400             hlen = len;
401         else if (proto = PPP_IP)
402             hlen = PPP_HDRLEN + MAX_IPHDR;
403         else
404             hlen = PPP_HDRLEN;
405         if (hlen > len)
406             hlen = len;
407         if (mp->b_wptr < mp->b_rptr + hlen || mp->b_datap->db_ref > 1) {
408             PULLUP(mp, hlen);
409             if (mp == 0) {
410                 DPRINT1("ppp_comp_wsrv: pullup failed (%d)\n", hlen);
411                 cp->stats.ppp_oerrors++;
412                 putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
413                 continue;
414             }
415         }
416         proto = PPP_PROTOCOL(mp->b_rptr);
417
418         /*
419          * Do VJ compression if requested.
420          */
421         if (proto == PPP_IP && (cp->flags & COMP_VJC)) {
422             ip = (struct ip *) (mp->b_rptr + PPP_HDRLEN);
423             if (ip->ip_p == IPPROTO_TCP) {
424                 type = vj_compress_tcp(ip, len - PPP_HDRLEN, &cp->vj_comp,
425                                        (cp->flags & COMP_VJCCID), &vjhdr);
426                 switch (type) {
427                 case TYPE_UNCOMPRESSED_TCP:
428                     mp->b_rptr[3] = proto = PPP_VJC_UNCOMP;
429                     break;
430                 case TYPE_COMPRESSED_TCP:
431                     dp = vjhdr - PPP_HDRLEN;
432                     dp[1] = mp->b_rptr[1]; /* copy control field */
433                     dp[0] = mp->b_rptr[0]; /* copy address field */
434                     dp[2] = 0;             /* set protocol field */
435                     dp[3] = proto = PPP_VJC_COMP;
436                     mp->b_rptr = dp;
437                     break;
438                 }
439             }
440         }
441
442         /*
443          * Do packet compression if enabled.
444          */
445         if (proto == PPP_CCP)
446             ppp_comp_ccp(q, mp, 0);
447         else if (proto != PPP_LCP && (cp->flags & CCP_COMP_RUN)
448                  && cp->xstate != NULL) {
449             len = msgdsize(mp);
450             (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len,
451                                    (cp->flags & CCP_ISUP? cp->mtu: 0));
452             if (cmp != NULL) {
453                 freemsg(mp);
454                 mp = cmp;
455             }
456         }
457
458         /*
459          * Do address/control and protocol compression if enabled.
460          */
461         if ((cp->flags & COMP_AC)
462             && !(proto == PPP_LCP && LCP_USE_DFLT(mp))) {
463             mp->b_rptr += 2;    /* drop the address & ctrl fields */
464             if (proto < 0x100 && (cp->flags & COMP_PROT))
465                 ++mp->b_rptr;   /* drop the high protocol byte */
466         } else if (proto < 0x100 && (cp->flags & COMP_PROT)) {
467             /* shuffle up the address & ctrl fields */
468             mp->b_rptr[2] = mp->b_rptr[1];
469             mp->b_rptr[1] = mp->b_rptr[0];
470             ++mp->b_rptr;
471         }
472
473         cp->stats.ppp_opackets++;
474         cp->stats.ppp_obytes += msgdsize(mp);
475         putnext(q, mp);
476     }
477 }
478
479 static int
480 ppp_comp_rput(q, mp)
481     queue_t *q;
482     mblk_t *mp;
483 {
484     comp_state_t *cp;
485     struct iocblk *iop;
486     struct ppp_stats *psp;
487
488     cp = (comp_state_t *) q->q_ptr;
489     switch (mp->b_datap->db_type) {
490
491     case M_DATA:
492         putq(q, mp);
493         break;
494
495     case M_IOCACK:
496         iop = (struct iocblk *) mp->b_rptr;
497         switch (iop->ioc_cmd) {
498         case PPPIO_GETSTAT:
499             /*
500              * Catch this on the way back from the ppp_ahdl module
501              * so we can fill in the VJ stats.
502              */
503             if (mp->b_cont == 0 || iop->ioc_count != sizeof(struct ppp_stats))
504                 break;
505             psp = (struct ppp_stats *) mp->b_cont->b_rptr;
506             psp->vj = cp->vj_comp.stats;
507             break;
508         }
509         putnext(q, mp);
510         break;
511
512     case M_CTL:
513         switch (mp->b_rptr[0]) {
514         case PPPCTL_IERROR:
515             ++cp->stats.ppp_ierrors;
516             break;
517         case PPPCTL_OERROR:
518             ++cp->stats.ppp_oerrors;
519             break;
520         }
521         putnext(q, mp);
522         break;
523
524     default:
525         putnext(q, mp);
526     }
527 }
528
529 static int
530 ppp_comp_rsrv(q)
531     queue_t *q;
532 {
533     int proto, rv, i;
534     mblk_t *mp, *dmp = NULL, *np;
535     uchar_t *dp, *iphdr;
536     comp_state_t *cp;
537     int len, hlen, vjlen;
538     u_int iphlen;
539
540     cp = (comp_state_t *) q->q_ptr;
541     while ((mp = getq(q)) != 0) {
542         /* assert(mp->b_datap->db_type == M_DATA) */
543         if (!canputnext(q)) {
544             putbq(q, mp);
545             return;
546         }
547
548         len = msgdsize(mp);
549         cp->stats.ppp_ibytes += len;
550         cp->stats.ppp_ipackets++;
551
552         /*
553          * First work out the protocol and where the PPP header ends.
554          */
555         i = 0;
556         proto = MSG_BYTE(mp, 0);
557         if (proto == PPP_ALLSTATIONS) {
558             i = 2;
559             proto = MSG_BYTE(mp, 2);
560         }
561         if ((proto & 1) == 0) {
562             ++i;
563             proto = (proto << 8) + MSG_BYTE(mp, i);
564         }
565         hlen = i + 1;
566
567         /*
568          * Now reconstruct a complete, contiguous PPP header at the
569          * start of the packet.
570          */
571         if (hlen < ((cp->flags & DECOMP_AC)? 0: 2)
572                    + ((cp->flags & DECOMP_PROT)? 1: 2)) {
573             /* count these? */
574             goto bad;
575         }
576         if (mp->b_rptr + hlen > mp->b_wptr) {
577             adjmsg(mp, hlen);   /* XXX check this call */
578             hlen = 0;
579         }
580         if (hlen != PPP_HDRLEN) {
581             /*
582              * We need to put some bytes on the front of the packet
583              * to make a full-length PPP header.
584              * If we can put them in *mp, we do, otherwise we
585              * tack another mblk on the front.
586              * XXX we really shouldn't need to carry around
587              * the address and control at this stage.
588              */
589             dp = mp->b_rptr + hlen - PPP_HDRLEN;
590             if (dp < mp->b_datap->db_base || mp->b_datap->db_ref > 1) {
591                 np = allocb(PPP_HDRLEN, BPRI_MED);
592                 if (np == 0)
593                     goto bad;
594                 np->b_cont = mp;
595                 mp->b_rptr += hlen;
596                 mp = np;
597                 dp = mp->b_wptr;
598                 mp->b_wptr += PPP_HDRLEN;
599             } else
600                 mp->b_rptr = dp;
601
602             dp[0] = PPP_ALLSTATIONS;
603             dp[1] = PPP_UI;
604             dp[2] = proto >> 8;
605             dp[3] = proto;
606         }
607
608         /*
609          * Now see if we have a compressed packet to decompress,
610          * or a CCP packet to take notice of.
611          */
612         proto = PPP_PROTOCOL(mp->b_rptr);
613         if (proto == PPP_CCP) {
614             len = msgdsize(mp);
615             if (mp->b_wptr < mp->b_rptr + len) {
616                 PULLUP(mp, len);
617                 if (mp == 0)
618                     goto bad;
619             }
620             ppp_comp_ccp(q, mp, 1);
621         } else if (proto == PPP_COMP) {
622             if ((cp->flags & CCP_ISUP)
623                 && (cp->flags & CCP_DECOMP_RUN) && cp->rstate
624                 && (cp->flags & CCP_ERR) == 0) {
625                 rv = (*cp->rcomp->decompress)(cp->rstate, mp, &dmp);
626                 switch (rv) {
627                 case DECOMP_OK:
628                     freemsg(mp);
629                     mp = dmp;
630                     if (mp == NULL) {
631                         /* no error, but no packet returned either. */
632                         continue;
633                     }
634                     break;
635                 case DECOMP_ERROR:
636                     cp->flags |= CCP_ERROR;
637                     ++cp->stats.ppp_ierrors;
638                     putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
639                     break;
640                 case DECOMP_FATALERROR:
641                     cp->flags |= CCP_FATALERROR;
642                     ++cp->stats.ppp_ierrors;
643                     putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
644                     break;
645                 }
646             }
647         } else if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
648             (*cp->rcomp->incomp)(cp->rstate, mp);
649         }
650
651         /*
652          * Now do VJ decompression.
653          */
654         proto = PPP_PROTOCOL(mp->b_rptr);
655         if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
656             len = msgdsize(mp) - PPP_HDRLEN;
657             if ((cp->flags & DECOMP_VJC) == 0 || len <= 0)
658                 goto bad;
659
660             /*
661              * Advance past the ppp header.
662              * Here we assume that the whole PPP header is in the first mblk.
663              */
664             np = mp;
665             dp = np->b_rptr + PPP_HDRLEN;
666             if (dp >= mp->b_wptr) {
667                 np = np->b_cont;
668                 dp = np->b_rptr;
669             }
670
671             /*
672              * Make sure we have sufficient contiguous data at this point.
673              */
674             hlen = (proto == PPP_VJC_COMP)? MAX_VJHDR: MAX_IPHDR;
675             if (hlen > len)
676                 hlen = len;
677             if (np->b_wptr < dp + hlen || np->b_datap->db_ref > 1) {
678                 PULLUP(mp, hlen + PPP_HDRLEN);
679                 if (mp == 0)
680                     goto bad;
681                 np = mp;
682                 dp = np->b_rptr + PPP_HDRLEN;
683             }
684
685             if (proto == PPP_VJC_COMP) {
686                 /*
687                  * Decompress VJ-compressed packet.
688                  * First reset compressor if an input error has occurred.
689                  */
690                 if (cp->stats.ppp_ierrors != cp->vj_last_ierrors) {
691                     vj_uncompress_err(&cp->vj_comp);
692                     cp->vj_last_ierrors = cp->stats.ppp_ierrors;
693                 }
694
695                 vjlen = vj_uncompress_tcp(dp, np->b_wptr - dp, len,
696                                           &cp->vj_comp, &iphdr, &iphlen);
697                 if (vjlen < 0)
698                     goto bad;
699
700                 /* drop ppp and vj headers off */
701                 if (mp != np) {
702                     freeb(mp);
703                     mp = np;
704                 }
705                 mp->b_rptr = dp + vjlen;
706
707                 /* allocate a new mblk for the ppp and ip headers */
708                 if ((np = allocb(iphlen + PPP_HDRLEN + 4, BPRI_MED)) == 0)
709                     goto bad;
710                 dp = np->b_rptr;        /* prepend mblk with TCP/IP hdr */
711                 dp[0] = PPP_ALLSTATIONS; /* reconstruct PPP header */
712                 dp[1] = PPP_UI;
713                 dp[2] = PPP_IP >> 8;
714                 dp[3] = PPP_IP;
715                 bcopy((caddr_t)iphdr, (caddr_t)dp + PPP_HDRLEN, iphlen);
716                 np->b_wptr = dp + iphlen + PPP_HDRLEN;
717                 np->b_cont = mp;
718
719                 /* XXX there seems to be a bug which causes panics in strread
720                    if we make an mbuf with only the IP header in it :-( */
721                 if (mp->b_wptr - mp->b_rptr > 4) {
722                     bcopy((caddr_t)mp->b_rptr, (caddr_t)np->b_wptr, 4);
723                     mp->b_rptr += 4;
724                     np->b_wptr += 4;
725                 } else {
726                     bcopy((caddr_t)mp->b_rptr, (caddr_t)np->b_wptr,
727                           mp->b_wptr - mp->b_rptr);
728                     np->b_wptr += mp->b_wptr - mp->b_rptr;
729                     np->b_cont = mp->b_cont;
730                     freeb(mp);
731                 }
732
733                 mp = np;
734
735             } else {
736                 /*
737                  * "Decompress" a VJ-uncompressed packet.
738                  */
739                 if (!vj_uncompress_uncomp(dp, hlen, &cp->vj_comp))
740                     goto bad;
741                 mp->b_rptr[3] = PPP_IP; /* fix up the PPP protocol field */
742             }
743         }
744
745         putnext(q, mp);
746         continue;
747
748     bad:
749         if (mp != 0)
750             freemsg(mp);
751         cp->stats.ppp_ierrors++;
752         putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
753     }
754 }
755
756 /*
757  * Handle a CCP packet being sent or received.
758  * Here all the data in the packet is in a single mbuf.
759  */
760 static void
761 ppp_comp_ccp(q, mp, rcvd)
762     queue_t *q;
763     mblk_t *mp;
764     int rcvd;
765 {
766     int len, clen;
767     comp_state_t *cp;
768     unsigned char *dp;
769
770     len = msgdsize(mp);
771     if (len < PPP_HDRLEN + CCP_HDRLEN)
772         return;
773
774     cp = (comp_state_t *) q->q_ptr;
775     dp = mp->b_rptr + PPP_HDRLEN;
776     len -= PPP_HDRLEN;
777     clen = CCP_LENGTH(dp);
778     if (clen > len)
779         return;
780
781     switch (CCP_CODE(dp)) {
782     case CCP_CONFREQ:
783     case CCP_TERMREQ:
784     case CCP_TERMACK:
785         cp->flags &= ~CCP_ISUP;
786         break;
787
788     case CCP_CONFACK:
789         if ((cp->flags & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN
790             && clen >= CCP_HDRLEN + CCP_OPT_MINLEN
791             && clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
792             if (!rcvd) {
793                 if (cp->xstate != NULL
794                     && (*cp->xcomp->comp_init)
795                         (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
796                          cp->unit, 0, 0))
797                     cp->flags |= CCP_COMP_RUN;
798             } else {
799                 if (cp->rstate != NULL
800                     && (*cp->rcomp->decomp_init)
801                         (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
802                          cp->unit, 0, cp->mru, 0))
803                     cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
804             }
805         }
806         break;
807
808     case CCP_RESETACK:
809         if (cp->flags & CCP_ISUP) {
810             if (!rcvd) {
811                 if (cp->xstate && (cp->flags & CCP_COMP_RUN))
812                     (*cp->xcomp->comp_reset)(cp->xstate);
813             } else {
814                 if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
815                     (*cp->rcomp->decomp_reset)(cp->rstate);
816                     cp->flags &= ~CCP_ERROR;
817                 }
818             }
819         }
820         break;
821     }
822 }
823
824 #if DEBUG
825 dump_msg(mp)
826     mblk_t *mp;
827 {
828     dblk_t *db;
829
830     while (mp != 0) {
831         db = mp->b_datap;
832         DPRINT2("mp=%x cont=%x ", mp, mp->b_cont);
833         DPRINT3("rptr=%x wptr=%x datap=%x\n", mp->b_rptr, mp->b_wptr, db);
834         DPRINT2("  base=%x lim=%x", db->db_base, db->db_lim);
835         DPRINT2(" ref=%d type=%d\n", db->db_ref, db->db_type);
836         mp = mp->b_cont;
837     }
838 }
839 #endif
840
841 static int
842 msg_byte(mp, i)
843     mblk_t *mp;
844     unsigned int i;
845 {
846     while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
847         mp = mp->b_cont;
848     if (mp == 0)
849         return -1;
850     return mp->b_rptr[i];
851 }