]> git.ozlabs.org Git - ppp.git/blob - modules/ppp_comp.c
added idle time measurement
[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.1 1995/12/11 05:06:43 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
124 struct compressor *ppp_compressors[] = {
125 #if DO_BSD_COMPRESS
126     &ppp_bsd_compress,
127 #endif
128     NULL
129 };
130
131 /*
132  * STREAMS module entry points.
133  */
134 MOD_OPEN(ppp_comp_open)
135 {
136     comp_state_t *cp;
137
138     if (q->q_ptr == NULL) {
139         cp = (comp_state_t *) ALLOC_SLEEP(sizeof(comp_state_t));
140         if (cp == NULL)
141             OPEN_ERROR(ENOSR);
142         WR(q)->q_ptr = q->q_ptr = (caddr_t) cp;
143         bzero((caddr_t)cp, sizeof(comp_state_t));
144         cp->mru = PPP_MRU;
145         cp->mtu = PPP_MRU;
146         cp->xstate = NULL;
147         cp->rstate = NULL;
148         vj_compress_init(&cp->vj_comp, -1);
149         ++ppp_comp_count;
150         qprocson(q);
151     }
152     return 0;
153 }
154
155 MOD_CLOSE(ppp_comp_close)
156 {
157     comp_state_t *cp;
158
159     qprocsoff(q);
160     cp = (comp_state_t *) q->q_ptr;
161     if (cp != NULL) {
162         if (cp->xstate != NULL)
163             (*cp->xcomp->comp_free)(cp->xstate);
164         if (cp->rstate != NULL)
165             (*cp->rcomp->decomp_free)(cp->rstate);
166         FREE(cp, sizeof(comp_state_t));
167         q->q_ptr = NULL;
168         OTHERQ(q)->q_ptr = NULL;
169         --ppp_comp_count;
170     }
171     return 0;
172 }
173
174 static int
175 ppp_comp_wput(q, mp)
176     queue_t *q;
177     mblk_t *mp;
178 {
179     struct iocblk *iop;
180     comp_state_t *cp;
181     int error, len;
182     int flags, mask;
183     mblk_t *np;
184     struct compressor **comp;
185     struct ppp_stats *psp;
186     struct ppp_comp_stats *csp;
187     unsigned char *opt_data;
188     int nxslots, nrslots;
189
190     cp = (comp_state_t *) q->q_ptr;
191     switch (mp->b_datap->db_type) {
192
193     case M_DATA:
194         putq(q, mp);
195         break;
196
197     case M_IOCTL:
198         iop = (struct iocblk *) mp->b_rptr;
199         error = EINVAL;
200         switch (iop->ioc_cmd) {
201
202         case PPPIO_CFLAGS:
203             /* set/get CCP state */
204             if (iop->ioc_count != 2 * sizeof(int))
205                 break;
206             flags = ((int *) mp->b_cont->b_rptr)[0];
207             mask = ((int *) mp->b_cont->b_rptr)[1];
208             cp->flags = (cp->flags & ~mask) | (flags & mask);
209             if ((mask & CCP_ISOPEN) && (flags & CCP_ISOPEN) == 0) {
210                 if (cp->xstate != NULL) {
211                     (*cp->xcomp->comp_free)(cp->xstate);
212                     cp->xstate = NULL;
213                 }
214                 if (cp->rstate != NULL) {
215                     (*cp->rcomp->decomp_free)(cp->rstate);
216                     cp->rstate = NULL;
217                 }
218                 cp->flags &= ~CCP_ISUP;
219             }
220             error = 0;
221             iop->ioc_count = sizeof(int);
222             ((int *) mp->b_cont->b_rptr)[0] = cp->flags;
223             mp->b_cont->b_wptr = mp->b_cont->b_rptr + sizeof(int);
224             break;
225
226         case PPPIO_VJINIT:
227             /*
228              * Initialize VJ compressor/decompressor
229              */
230             if (iop->ioc_count != 2)
231                 break;
232             nxslots = mp->b_cont->b_rptr[0] + 1;
233             nrslots = mp->b_cont->b_rptr[1] + 1;
234             if (nxslots > MAX_STATES || nrslots > MAX_STATES)
235                 break;
236             vj_compress_init(&cp->vj_comp, nxslots);
237             cp->vj_last_ierrors = cp->stats.ppp_ierrors;
238             error = 0;
239             iop->ioc_count = 0;
240             break;
241
242         case PPPIO_XCOMP:
243         case PPPIO_RCOMP:
244             if (iop->ioc_count <= 0)
245                 break;
246             opt_data = mp->b_cont->b_rptr;
247             len = mp->b_cont->b_wptr - opt_data;
248             if (len > iop->ioc_count)
249                 len = iop->ioc_count;
250             if (opt_data[1] < 2 || opt_data[1] > len)
251                 break;
252             for (comp = ppp_compressors; *comp != NULL; ++comp)
253                 if ((*comp)->compress_proto == opt_data[0]) {
254                     /* here's the handler! */
255                     error = 0;
256                     if (iop->ioc_cmd == PPPIO_XCOMP) {
257                         if (cp->xstate != NULL)
258                             (*cp->xcomp->comp_free)(cp->xstate);
259                         cp->xcomp = *comp;
260                         cp->xstate = (*comp)->comp_alloc(opt_data, len);
261                         if (cp->xstate == NULL)
262                             error = ENOSR;
263                     } else {
264                         if (cp->rstate != NULL)
265                             (*cp->rcomp->decomp_free)(cp->rstate);
266                         cp->rcomp = *comp;
267                         cp->rstate = (*comp)->decomp_alloc(opt_data, len);
268                         if (cp->rstate == NULL)
269                             error = ENOSR;
270                     }
271                     break;
272                 }
273             iop->ioc_count = 0;
274             break;
275
276         case PPPIO_GETSTAT:
277             if ((cp->flags & LAST_MOD) == 0) {
278                 error = -1;     /* let the ppp_ahdl module handle it */
279                 break;
280             }
281             np = allocb(sizeof(struct ppp_stats), BPRI_HI);
282             if (np == 0) {
283                 error = ENOSR;
284                 break;
285             }
286             if (mp->b_cont != 0)
287                 freemsg(mp->b_cont);
288             mp->b_cont = np;
289             psp = (struct ppp_stats *) np->b_wptr;
290             np->b_wptr += sizeof(struct ppp_stats);
291             iop->ioc_count = sizeof(struct ppp_stats);
292             psp->p = cp->stats;
293             psp->vj = cp->vj_comp.stats;
294             error = 0;
295             break;
296
297         case PPPIO_GETCSTAT:
298             np = allocb(sizeof(struct ppp_comp_stats), BPRI_HI);
299             if (np == 0) {
300                 error = ENOSR;
301                 break;
302             }
303             if (mp->b_cont != 0)
304                 freemsg(mp->b_cont);
305             mp->b_cont = np;
306             csp = (struct ppp_comp_stats *) np->b_wptr;
307             np->b_wptr += sizeof(struct ppp_comp_stats);
308             iop->ioc_count = sizeof(struct ppp_comp_stats);
309             bzero((caddr_t)csp, sizeof(struct ppp_comp_stats));
310             if (cp->xstate != 0)
311                 (*cp->xcomp->comp_stat)(cp->xstate, &csp->c);
312             if (cp->rstate != 0)
313                 (*cp->rcomp->decomp_stat)(cp->rstate, &csp->d);
314             error = 0;
315             break;
316
317         case PPPIO_LASTMOD:
318             cp->flags |= LAST_MOD;
319             error = 0;
320             break;
321
322         default:
323             error = -1;
324             break;
325         }
326
327         if (error < 0)
328             putnext(q, mp);
329         else if (error == 0) {
330             mp->b_datap->db_type = M_IOCACK;
331             qreply(q, mp);
332         } else {
333             mp->b_datap->db_type = M_IOCNAK;
334             iop->ioc_error = error;
335             iop->ioc_count = 0;
336             qreply(q, mp);
337         }
338         break;
339
340     case M_CTL:
341         switch (*mp->b_rptr) {
342         case PPPCTL_MTU:
343             cp->mtu = ((unsigned short *)mp->b_rptr)[1];
344             break;
345         case PPPCTL_MRU:
346             cp->mru = ((unsigned short *)mp->b_rptr)[1];
347             break;
348         case PPPCTL_UNIT:
349             cp->unit = mp->b_rptr[1];
350             break;
351         }
352         putnext(q, mp);
353         break;
354
355     default:
356         putnext(q, mp);
357     }
358 }
359
360 static int
361 ppp_comp_wsrv(q)
362     queue_t *q;
363 {
364     mblk_t *mp, *cmp = NULL, *np;
365     comp_state_t *cp;
366     int len, proto, type, hlen, code;
367     struct ip *ip;
368     unsigned char *vjhdr, *dp;
369
370     cp = (comp_state_t *) q->q_ptr;
371     while ((mp = getq(q)) != 0) {
372         /* assert(mp->b_datap->db_type == M_DATA) */
373         if (!canputnext(q)) {
374             putbq(q, mp);
375             return;
376         }
377
378         /*
379          * First check the packet length and work out what the protocol is.
380          */
381         len = msgdsize(mp);
382         if (len < PPP_HDRLEN) {
383             DPRINT1("ppp_comp_wsrv: bogus short packet (%d)\n", len);
384             freemsg(mp);
385             cp->stats.ppp_oerrors++;
386             putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
387             continue;
388         }
389         proto = (MSG_BYTE(mp, 2) << 8) + MSG_BYTE(mp, 3);
390
391         /*
392          * Make sure we've got enough data in the first mblk
393          * and that we are its only user.
394          */
395         if (proto = PPP_CCP)
396             hlen = len;
397         else if (proto = PPP_IP)
398             hlen = PPP_HDRLEN + MAX_IPHDR;
399         else
400             hlen = PPP_HDRLEN;
401         if (hlen > len)
402             hlen = len;
403         if (mp->b_wptr < mp->b_rptr + hlen || mp->b_datap->db_ref > 1) {
404             PULLUP(mp, hlen);
405             if (mp == 0) {
406                 DPRINT1("ppp_comp_wsrv: pullup failed (%d)\n", hlen);
407                 cp->stats.ppp_oerrors++;
408                 putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
409                 continue;
410             }
411         }
412         proto = PPP_PROTOCOL(mp->b_rptr);
413
414         /*
415          * Do VJ compression if requested.
416          */
417         if (proto == PPP_IP && (cp->flags & COMP_VJC)) {
418             ip = (struct ip *) (mp->b_rptr + PPP_HDRLEN);
419             if (ip->ip_p == IPPROTO_TCP) {
420                 type = vj_compress_tcp(ip, len - PPP_HDRLEN, &cp->vj_comp,
421                                        (cp->flags & COMP_VJCCID), &vjhdr);
422                 switch (type) {
423                 case TYPE_UNCOMPRESSED_TCP:
424                     mp->b_rptr[3] = proto = PPP_VJC_UNCOMP;
425                     break;
426                 case TYPE_COMPRESSED_TCP:
427                     dp = vjhdr - PPP_HDRLEN;
428                     dp[1] = mp->b_rptr[1]; /* copy control field */
429                     dp[0] = mp->b_rptr[0]; /* copy address field */
430                     dp[2] = 0;             /* set protocol field */
431                     dp[3] = proto = PPP_VJC_COMP;
432                     mp->b_rptr = dp;
433                     break;
434                 }
435             }
436         }
437
438         /*
439          * Do packet compression if enabled.
440          */
441         if (proto == PPP_CCP)
442             ppp_comp_ccp(q, mp, 0);
443         else if (proto != PPP_LCP && (cp->flags & CCP_COMP_RUN)
444                  && cp->xstate != NULL) {
445             len = msgdsize(mp);
446             (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len,
447                                    (cp->flags & CCP_ISUP? cp->mtu: 0));
448             if (cmp != NULL) {
449                 freemsg(mp);
450                 mp = cmp;
451             }
452         }
453
454         /*
455          * Do address/control and protocol compression if enabled.
456          */
457         if ((cp->flags & COMP_AC)
458             && !(proto == PPP_LCP && LCP_USE_DFLT(mp))) {
459             mp->b_rptr += 2;    /* drop the address & ctrl fields */
460             if (proto < 0x100 && (cp->flags & COMP_PROT))
461                 ++mp->b_rptr;   /* drop the high protocol byte */
462         } else if (proto < 0x100 && (cp->flags & COMP_PROT)) {
463             /* shuffle up the address & ctrl fields */
464             mp->b_rptr[2] = mp->b_rptr[1];
465             mp->b_rptr[1] = mp->b_rptr[0];
466             ++mp->b_rptr;
467         }
468
469         cp->stats.ppp_opackets++;
470         cp->stats.ppp_obytes += msgdsize(mp);
471         putnext(q, mp);
472     }
473 }
474
475 static int
476 ppp_comp_rput(q, mp)
477     queue_t *q;
478     mblk_t *mp;
479 {
480     comp_state_t *cp;
481     struct iocblk *iop;
482     struct ppp_stats *psp;
483
484     cp = (comp_state_t *) q->q_ptr;
485     switch (mp->b_datap->db_type) {
486
487     case M_DATA:
488         putq(q, mp);
489         break;
490
491     case M_IOCACK:
492         iop = (struct iocblk *) mp->b_rptr;
493         switch (iop->ioc_cmd) {
494         case PPPIO_GETSTAT:
495             /*
496              * Catch this on the way back from the ppp_ahdl module
497              * so we can fill in the VJ stats.
498              */
499             if (mp->b_cont == 0 || iop->ioc_count != sizeof(struct ppp_stats))
500                 break;
501             psp = (struct ppp_stats *) mp->b_cont->b_rptr;
502             psp->vj = cp->vj_comp.stats;
503             break;
504         }
505         putnext(q, mp);
506         break;
507
508     case M_CTL:
509         switch (mp->b_rptr[0]) {
510         case PPPCTL_IERROR:
511             ++cp->stats.ppp_ierrors;
512             break;
513         case PPPCTL_OERROR:
514             ++cp->stats.ppp_oerrors;
515             break;
516         }
517         putnext(q, mp);
518         break;
519
520     default:
521         putnext(q, mp);
522     }
523 }
524
525 static int
526 ppp_comp_rsrv(q)
527     queue_t *q;
528 {
529     int proto, rv, i;
530     mblk_t *mp, *dmp = NULL, *np;
531     uchar_t *dp, *iphdr;
532     comp_state_t *cp;
533     int len, hlen, vjlen;
534     u_int iphlen;
535
536     cp = (comp_state_t *) q->q_ptr;
537     while ((mp = getq(q)) != 0) {
538         /* assert(mp->b_datap->db_type == M_DATA) */
539         if (!canputnext(q)) {
540             putbq(q, mp);
541             return;
542         }
543
544         len = msgdsize(mp);
545         cp->stats.ppp_ibytes += len;
546         cp->stats.ppp_ipackets++;
547
548         /*
549          * First work out the protocol and where the PPP header ends.
550          */
551         i = 0;
552         proto = MSG_BYTE(mp, 0);
553         if (proto == PPP_ALLSTATIONS) {
554             i = 2;
555             proto = MSG_BYTE(mp, 2);
556         }
557         if ((proto & 1) == 0) {
558             ++i;
559             proto = (proto << 8) + MSG_BYTE(mp, i);
560         }
561         hlen = i + 1;
562
563         /*
564          * Now reconstruct a complete, contiguous PPP header at the
565          * start of the packet.
566          */
567         if (hlen < ((cp->flags & DECOMP_AC)? 0: 2)
568                    + ((cp->flags & DECOMP_PROT)? 1: 2)) {
569             /* count these? */
570             goto bad;
571         }
572         if (mp->b_rptr + hlen > mp->b_wptr) {
573             adjmsg(mp, hlen);   /* XXX check this call */
574             hlen = 0;
575         }
576         if (hlen != PPP_HDRLEN) {
577             /*
578              * We need to put some bytes on the front of the packet
579              * to make a full-length PPP header.
580              * If we can put them in *mp, we do, otherwise we
581              * tack another mblk on the front.
582              * XXX we really shouldn't need to carry around
583              * the address and control at this stage.
584              */
585             dp = mp->b_rptr + hlen - PPP_HDRLEN;
586             if (dp < mp->b_datap->db_base || mp->b_datap->db_ref > 1) {
587                 np = allocb(PPP_HDRLEN, BPRI_MED);
588                 if (np == 0)
589                     goto bad;
590                 np->b_cont = mp;
591                 mp->b_rptr += hlen;
592                 mp = np;
593                 dp = mp->b_wptr;
594                 mp->b_wptr += PPP_HDRLEN;
595             } else
596                 mp->b_rptr = dp;
597
598             dp[0] = PPP_ALLSTATIONS;
599             dp[1] = PPP_UI;
600             dp[2] = proto >> 8;
601             dp[3] = proto;
602         }
603
604         /*
605          * Now see if we have a compressed packet to decompress,
606          * or a CCP packet to take notice of.
607          */
608         proto = PPP_PROTOCOL(mp->b_rptr);
609         if (proto == PPP_CCP) {
610             len = msgdsize(mp);
611             if (mp->b_wptr < mp->b_rptr + len) {
612                 PULLUP(mp, len);
613                 if (mp == 0)
614                     goto bad;
615             }
616             ppp_comp_ccp(q, mp, 1);
617         } else if (proto == PPP_COMP) {
618             if ((cp->flags & CCP_ISUP)
619                 && (cp->flags & CCP_DECOMP_RUN) && cp->rstate
620                 && (cp->flags & CCP_ERR) == 0) {
621                 rv = (*cp->rcomp->decompress)(cp->rstate, mp, &dmp);
622                 switch (rv) {
623                 case DECOMP_OK:
624                     freemsg(mp);
625                     mp = dmp;
626                     if (mp == NULL) {
627                         /* no error, but no packet returned either. */
628                         continue;
629                     }
630                     break;
631                 case DECOMP_ERROR:
632                     cp->flags |= CCP_ERROR;
633                     ++cp->stats.ppp_ierrors;
634                     putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
635                     break;
636                 case DECOMP_FATALERROR:
637                     cp->flags |= CCP_FATALERROR;
638                     ++cp->stats.ppp_ierrors;
639                     putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
640                     break;
641                 }
642             }
643         } else if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
644             (*cp->rcomp->incomp)(cp->rstate, mp);
645         }
646
647         /*
648          * Now do VJ decompression.
649          */
650         proto = PPP_PROTOCOL(mp->b_rptr);
651         if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
652             len = msgdsize(mp) - PPP_HDRLEN;
653             if ((cp->flags & DECOMP_VJC) == 0 || len <= 0)
654                 goto bad;
655
656             /*
657              * Advance past the ppp header.
658              * Here we assume that the whole PPP header is in the first mblk.
659              */
660             np = mp;
661             dp = np->b_rptr + PPP_HDRLEN;
662             if (dp >= mp->b_wptr) {
663                 np = np->b_cont;
664                 dp = np->b_rptr;
665             }
666
667             /*
668              * Make sure we have sufficient contiguous data at this point.
669              */
670             hlen = (proto == PPP_VJC_COMP)? MAX_VJHDR: MAX_IPHDR;
671             if (hlen > len)
672                 hlen = len;
673             if (np->b_wptr < dp + hlen || np->b_datap->db_ref > 1) {
674                 PULLUP(mp, hlen + PPP_HDRLEN);
675                 if (mp == 0)
676                     goto bad;
677                 np = mp;
678                 dp = np->b_rptr + PPP_HDRLEN;
679             }
680
681             if (proto == PPP_VJC_COMP) {
682                 /*
683                  * Decompress VJ-compressed packet.
684                  * First reset compressor if an input error has occurred.
685                  */
686                 if (cp->stats.ppp_ierrors != cp->vj_last_ierrors) {
687                     vj_uncompress_err(&cp->vj_comp);
688                     cp->vj_last_ierrors = cp->stats.ppp_ierrors;
689                 }
690
691                 vjlen = vj_uncompress_tcp(dp, np->b_wptr - dp, len,
692                                           &cp->vj_comp, &iphdr, &iphlen);
693                 if (vjlen < 0)
694                     goto bad;
695
696                 /* drop ppp and vj headers off */
697                 if (mp != np) {
698                     freeb(mp);
699                     mp = np;
700                 }
701                 mp->b_rptr = dp + vjlen;
702
703                 /* allocate a new mblk for the ppp and ip headers */
704                 if ((np = allocb(iphlen + PPP_HDRLEN + 4, BPRI_MED)) == 0)
705                     goto bad;
706                 dp = np->b_rptr;        /* prepend mblk with TCP/IP hdr */
707                 dp[0] = PPP_ALLSTATIONS; /* reconstruct PPP header */
708                 dp[1] = PPP_UI;
709                 dp[2] = PPP_IP >> 8;
710                 dp[3] = PPP_IP;
711                 bcopy((caddr_t)iphdr, (caddr_t)dp + PPP_HDRLEN, iphlen);
712                 np->b_wptr = dp + iphlen + PPP_HDRLEN;
713                 np->b_cont = mp;
714
715                 /* XXX there seems to be a bug which causes panics in strread
716                    if we make an mbuf with only the IP header in it :-( */
717                 if (mp->b_wptr - mp->b_rptr > 4) {
718                     bcopy((caddr_t)mp->b_rptr, (caddr_t)np->b_wptr, 4);
719                     mp->b_rptr += 4;
720                     np->b_wptr += 4;
721                 } else {
722                     bcopy((caddr_t)mp->b_rptr, (caddr_t)np->b_wptr,
723                           mp->b_wptr - mp->b_rptr);
724                     np->b_wptr += mp->b_wptr - mp->b_rptr;
725                     np->b_cont = mp->b_cont;
726                     freeb(mp);
727                 }
728
729                 mp = np;
730
731             } else {
732                 /*
733                  * "Decompress" a VJ-uncompressed packet.
734                  */
735                 if (!vj_uncompress_uncomp(dp, &cp->vj_comp))
736                     goto bad;
737                 mp->b_rptr[3] = PPP_IP; /* fix up the PPP protocol field */
738             }
739         }
740
741         putnext(q, mp);
742         continue;
743
744     bad:
745         if (mp != 0)
746             freemsg(mp);
747         cp->stats.ppp_ierrors++;
748         putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
749     }
750 }
751
752 /*
753  * Handle a CCP packet being sent or received.
754  * Here all the data in the packet is in a single mbuf.
755  */
756 static void
757 ppp_comp_ccp(q, mp, rcvd)
758     queue_t *q;
759     mblk_t *mp;
760     int rcvd;
761 {
762     int len, clen;
763     comp_state_t *cp;
764     unsigned char *dp;
765
766     len = msgdsize(mp);
767     if (len < PPP_HDRLEN + CCP_HDRLEN)
768         return;
769
770     cp = (comp_state_t *) q->q_ptr;
771     dp = mp->b_rptr + PPP_HDRLEN;
772     len -= PPP_HDRLEN;
773     clen = CCP_LENGTH(dp);
774     if (clen > len)
775         return;
776
777     switch (CCP_CODE(dp)) {
778     case CCP_CONFREQ:
779     case CCP_TERMREQ:
780     case CCP_TERMACK:
781         cp->flags &= ~CCP_ISUP;
782         break;
783
784     case CCP_CONFACK:
785         if ((cp->flags & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN
786             && clen >= CCP_HDRLEN + CCP_OPT_MINLEN
787             && clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
788             if (!rcvd) {
789                 if (cp->xstate != NULL
790                     && (*cp->xcomp->comp_init)
791                         (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
792                          cp->unit, 0, 0))
793                     cp->flags |= CCP_COMP_RUN;
794             } else {
795                 if (cp->rstate != NULL
796                     && (*cp->rcomp->decomp_init)
797                         (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
798                          cp->unit, 0, cp->mru, 0))
799                     cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
800             }
801         }
802         break;
803
804     case CCP_RESETACK:
805         if (cp->flags & CCP_ISUP) {
806             if (!rcvd) {
807                 if (cp->xstate && (cp->flags & CCP_COMP_RUN))
808                     (*cp->xcomp->comp_reset)(cp->xstate);
809             } else {
810                 if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
811                     (*cp->rcomp->decomp_reset)(cp->rstate);
812                     cp->flags &= ~CCP_ERROR;
813                 }
814             }
815         }
816         break;
817     }
818 }
819
820 #if DEBUG
821 dump_msg(mp)
822     mblk_t *mp;
823 {
824     dblk_t *db;
825
826     while (mp != 0) {
827         db = mp->b_datap;
828         DPRINT2("mp=%x cont=%x ", mp, mp->b_cont);
829         DPRINT3("rptr=%x wptr=%x datap=%x\n", mp->b_rptr, mp->b_wptr, db);
830         DPRINT2("  base=%x lim=%x", db->db_base, db->db_lim);
831         DPRINT2(" ref=%d type=%d\n", db->db_ref, db->db_type);
832         mp = mp->b_cont;
833     }
834 }
835 #endif
836
837 static int
838 msg_byte(mp, i)
839     mblk_t *mp;
840     unsigned int i;
841 {
842     while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
843         mp = mp->b_cont;
844     if (mp == 0)
845         return -1;
846     return mp->b_rptr[i];
847 }