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