debugged and working (no stats yet)
authorPaul Mackerras <paulus@samba.org>
Fri, 19 May 1995 02:18:34 +0000 (02:18 +0000)
committerPaul Mackerras <paulus@samba.org>
Fri, 19 May 1995 02:18:34 +0000 (02:18 +0000)
svr4/ppp.c
svr4/ppp_ahdlc.c
svr4/ppp_comp.c

index 4b6665819e730173904228dbc81db320d4a88806..ef748e42d5403ba7066b0526319f3992aa5b1469 100644 (file)
@@ -1,3 +1,36 @@
+/*
+ * ppp.c - STREAMS multiplexing pseudo-device driver for PPP.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp.c,v 1.2 1995/05/19 02:17:42 paulus Exp $
+ */
+
+/*
+ * This file is used under Solaris 2.
+ */
+
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/stat.h>
@@ -28,7 +61,7 @@
 #endif
 
 #ifndef PPP_MAXMTU
-#define PPP_MAXMTU     65536
+#define PPP_MAXMTU     65535
 #endif
 
 /*
@@ -40,6 +73,7 @@ struct upperstr {
     int flags;                 /* flag bits, see below */
     int state;                 /* current DLPI state */
     int sap;                   /* service access point */
+    int req_sap;               /* which SAP the DLPI client requested */
     struct upperstr *ppa;      /* control stream for our ppa */
     struct upperstr *next;     /* next stream for this ppa */
     /*
@@ -49,6 +83,8 @@ struct upperstr {
     int ppa_id;
     queue_t *lowerq;           /* write queue attached below this PPA */
     struct upperstr *nextppa;  /* next control stream */
+    int mru;
+    int mtu;
 };
 
 /* Values for flags */
@@ -77,6 +113,8 @@ static void dlpi_ok __P((queue_t *, int));
 static int send_data __P((mblk_t *, struct upperstr *));
 static void new_ppa __P((queue_t *, mblk_t *));
 static struct upperstr *find_dest __P((struct upperstr *, int));
+static int putctl2 __P((queue_t *, int, int, int));
+static int putctl4 __P((queue_t *, int, int, int));
 
 static struct module_info ppp_info = {
     0xb1a6, "ppp", 0, 512, 512, 128
@@ -255,7 +293,6 @@ pppopen(q, devp, oflag, sflag, credp)
     } else {
        mn = getminor(*devp);
     }
-    cmn_err(CE_CONT, "pppopen: minor %d\n", mn);
 
     /*
      * Construct a new minor node.
@@ -295,7 +332,6 @@ pppclose(q, flag, credp)
     qprocsoff(q);
 
     up = (struct upperstr *) q->q_ptr;
-    cmn_err(CE_CONT, "pppclose: minor %d\n", up->mn);
     if (up->flags & US_CONTROL) {
        /*
         * This stream represents a PPA:
@@ -354,7 +390,7 @@ pppuwput(q, mp)
     struct iocblk *iop;
     struct linkblk *lb;
     queue_t *lq;
-    int error;
+    int error, n;
     mblk_t *mq;
 
     us = (struct upperstr *) q->q_ptr;
@@ -365,56 +401,68 @@ pppuwput(q, mp)
        break;
 
     case M_DATA:
+       if ((us->flags & US_CONTROL) == 0
+           || msgdsize(mp) > us->mtu + PPP_HDRLEN) {
+#if DEBUG
+           cmn_err(CE_CONT, "pppuwput: junk data len=%d\n", msgdsize(mp));
+#endif
+           freemsg(mp);
+           break;
+       }
        if (!send_data(mp, us))
            putq(q, mp);
        break;
 
     case M_IOCTL:
        iop = (struct iocblk *) mp->b_rptr;
-       cmn_err(CE_CONT, "ppp%d ioctl %x count=%d\n", us->mn, iop->ioc_cmd,
-               iop->ioc_count);
+       error = EINVAL;
        switch (iop->ioc_cmd) {
        case I_LINK:
            if ((us->flags & US_CONTROL) == 0 || us->lowerq != 0)
-               goto iocnak;
+               break;
            lb = (struct linkblk *) mp->b_cont->b_rptr;
            us->lowerq = lq = lb->l_qbot;
            lq->q_ptr = us;
-           WR(lq)->q_ptr = us;
+           RD(lq)->q_ptr = us;
            iop->ioc_count = 0;
-           mp->b_datap->db_type = M_IOCACK;
-           qreply(q, mp);
+           error = 0;
            /* Unblock upper streams which now feed this lower stream. */
            qenable(lq);
+           /* Send useful information down to the modules which
+              are now linked below us. */
+           putctl2(lq, M_CTL, PPPCTL_UNIT, us->ppa_id);
+           putctl4(lq, M_CTL, PPPCTL_MRU, us->mru);
+           putctl4(lq, M_CTL, PPPCTL_MTU, us->mtu);
            break;
 
        case I_UNLINK:
            lb = (struct linkblk *) mp->b_cont->b_rptr;
+#if DEBUG
            if (us->lowerq != lb->l_qbot)
                cmn_err(CE_CONT, "ppp unlink: lowerq=%x qbot=%x\n",
                        us->lowerq, lb->l_qbot);
+#endif
            us->lowerq = 0;
            iop->ioc_count = 0;
-           mp->b_datap->db_type = M_IOCACK;
-           qreply(q, mp);
+           error = 0;
            /* Unblock streams which now feed back up the control stream. */
            qenable(us->q);
            break;
 
        case PPPIO_NEWPPA:
            if (us->flags & US_CONTROL)
-               goto iocnak;
+               break;
            if ((us->flags & US_PRIV) == 0) {
-               iop->ioc_error = EPERM;
-               goto iocnak;
+               error = EPERM;
+               break;
            }
            /* Arrange to return an int */
            if ((mq = mp->b_cont) == 0
                || mq->b_datap->db_lim - mq->b_rptr < sizeof(int)) {
                mq = allocb(sizeof(int), BPRI_HI);
                if (mq == 0) {
-                   iop->ioc_error = ENOSR;
-                   goto iocnak;
+                   error = ENOSR;
+                   break;
                }
                if (mp->b_cont != 0)
                    freemsg(mp->b_cont);
@@ -424,28 +472,67 @@ pppuwput(q, mp)
            iop->ioc_count = sizeof(int);
            mq->b_wptr = mq->b_rptr + sizeof(int);
            qwriter(q, mp, new_ppa, PERIM_OUTER);
+           error = -1;
+           break;
+
+       case PPPIO_MRU:
+           if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
+               break;
+           n = *(int *)mp->b_cont->b_rptr;
+           if (n <= 0 || n > PPP_MAXMTU)
+               break;
+           if (n < PPP_MRU)
+               n = PPP_MRU;
+           us->mru = n;
+           if (us->lowerq)
+               putctl4(us->lowerq, M_CTL, PPPCTL_MRU, n);
+           error = 0;
+           iop->ioc_count = 0;
+           break;
+
+       case PPPIO_MTU:
+           if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
+               break;
+           n = *(int *)mp->b_cont->b_rptr;
+           if (n <= 0 || n > PPP_MAXMTU)
+               break;
+           if (n < PPP_MRU)
+               n = PPP_MRU;
+           us->mtu = n;
+           if (us->lowerq)
+               putctl4(us->lowerq, M_CTL, PPPCTL_MTU, n);
+           error = 0;
+           iop->ioc_count = 0;
            break;
 
        default:
            if (us->ppa == 0 || us->ppa->lowerq == 0)
-               goto iocnak;
+               break;
+           error = -1;
            switch (iop->ioc_cmd) {
            case PPPIO_GETSTAT:
            case PPPIO_GETCSTAT:
+               putnext(us->ppa->lowerq, mp);
                break;
            default:
-               if ((us->flags & US_PRIV) == 0) {
-                   iop->ioc_error = EPERM;
-                   goto iocnak;
+               if (us->flags & US_PRIV)
+                   putnext(us->ppa->lowerq, mp);
+               else {
+                   cmn_err(CE_CONT, "ppp ioctl %x rejected\n", iop->ioc_cmd);
+                   error = EPERM;
                }
+               break;
            }
-           putnext(us->ppa->lowerq, mp);
            break;
+       }
 
-       iocnak:
+       if (error > 0) {
+           iop->ioc_error = error;
            mp->b_datap->db_type = M_IOCNAK;
            qreply(q, mp);
-           break;
+       } else if (error == 0) {
+           mp->b_datap->db_type = M_IOCACK;
+           qreply(q, mp);
        }
        break;
 
@@ -476,13 +563,12 @@ dlpi_request(q, mp, us)
     int size = mp->b_wptr - mp->b_rptr;
     mblk_t *reply, *np;
     struct upperstr *t, *ppa;
-    int sap;
+    int sap, *ip;
     dl_info_ack_t *info;
     dl_bind_ack_t *ackp;
     dl_phys_addr_ack_t *adrp;
+    dl_get_statistics_ack_t *statsp;
 
-    cmn_err(CE_CONT, "ppp%d dlpi prim %x, state=%x\n", us->mn,
-           d->dl_primitive, us->state);
     switch (d->dl_primitive) {
     case DL_INFO_REQ:
        if (size < sizeof(dl_info_req_t))
@@ -560,7 +646,10 @@ dlpi_request(q, mp, us)
        }
        /* saps must be valid PPP network protocol numbers */
        sap = d->bind_req.dl_sap;
+       us->req_sap = sap;
+#if DEBUG
        cmn_err(CE_CONT, "ppp bind %x\n", sap);
+#endif
        if (sap == ETHERTYPE_IP)
            sap = PPP_IP;
        if (sap < 0x21 || sap > 0x3fff
@@ -604,6 +693,14 @@ dlpi_request(q, mp, us)
            dlpi_error(q, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
            break;
        }
+       if (mp->b_cont != 0 && us->ppa != 0
+           && msgdsize(mp->b_cont) > us->ppa->mtu) {
+#if DEBUG
+           cmn_err(CE_CONT, "dlpi data too large (%d > %d)\n",
+                   msgdsize(mp->b_cont), us->mtu);
+#endif
+           break;
+       }
        /* this assumes PPP_HDRLEN <= sizeof(dl_unitdata_req_t) */
        if (mp->b_datap->db_ref > 1) {
            np = allocb(PPP_HDRLEN, BPRI_HI);
@@ -613,8 +710,10 @@ dlpi_request(q, mp, us)
            mp->b_cont = 0;
            freeb(mp);
            mp = np;
-       }
-       /* XXX should use dl_dest_addr_offset/length here */
+       } else
+           mp->b_datap->db_type = M_DATA;
+       /* XXX should use dl_dest_addr_offset/length here,
+          but we would have to translate ETHERTYPE_IP -> PPP_IP */
        mp->b_wptr = mp->b_rptr + PPP_HDRLEN;
        mp->b_rptr[0] = PPP_ALLSTATIONS;
        mp->b_rptr[1] = PPP_UI;
@@ -624,6 +723,29 @@ dlpi_request(q, mp, us)
            putq(q, mp);
        return;
 
+#if 0
+    case DL_GET_STATISTICS_REQ:
+       if (size < sizeof(dl_get_statistics_req_t))
+           goto badprim;
+       if ((reply = allocb(sizeof(dl_get_statistics_ack_t) + 5 * sizeof(int),
+                           BPRI_HI)) == 0)
+           break;              /* XXX should do bufcall */
+       statsp = (dl_get_statistics_ack_t *) reply->b_wptr;
+       reply->b_wptr += sizeof(dl_get_statistics_ack_t) + 5 * sizeof(int);
+       reply->b_datap->db_type = M_PCPROTO;
+       statsp->dl_primitive = DL_GET_STATISTICS_ACK;
+       statsp->dl_stat_length = 5 * sizeof(int);
+       statsp->dl_stat_offset = sizeof(dl_get_statistics_ack_t);
+       ip = (int *) (statsp + 1);
+       ip[0] = 1;
+       ip[1] = 2;
+       ip[2] = 3;
+       ip[3] = 4;
+       ip[4] = 5;
+       qreply(q, reply);
+       break;
+#endif
+
     case DL_SUBS_BIND_REQ:
     case DL_SUBS_UNBIND_REQ:
     case DL_ENABMULTI_REQ:
@@ -637,7 +759,6 @@ dlpi_request(q, mp, us)
     case DL_CONNECT_REQ:
     case DL_TOKEN_REQ:
     case DL_REPLY_UPDATE_REQ:
-    case DL_GET_STATISTICS_REQ:
     case DL_REPLY_REQ:
     case DL_DATA_ACK_REQ:
        dlpi_error(q, d->dl_primitive, DL_NOTSUPPORTED, 0);
@@ -659,6 +780,8 @@ dlpi_request(q, mp, us)
        break;
 
     default:
+       cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive);
+       /* fall through */
     badprim:
        dlpi_error(q, d->dl_primitive, DL_BADPRIM, 0);
        break;
@@ -759,6 +882,9 @@ new_ppa(q, mp)
     *usp = us;
     us->flags |= US_CONTROL;
 
+    us->mtu = PPP_MRU;
+    us->mru = PPP_MRU;
+
     *(int *)mp->b_cont->b_rptr = ppa_id;
     mp->b_datap->db_type = M_IOCACK;
     qreply(q, mp);
@@ -780,6 +906,8 @@ pppuwsrv(q)
            break;
        }
     }
+    if (mp == 0)
+       us->flags &= ~US_BLOCKED;
     return 0;
 }
 
@@ -856,8 +984,11 @@ pppursrv(q)
            ud->dl_src_addr_length = sizeof(ulong);
            ud->dl_src_addr_offset = ud->dl_dest_addr_offset + sizeof(ulong);
            ud->dl_group_address = 0;
-           ((ulong *)(ud + 1))[0] = proto;     /* dest SAP */
-           ((ulong *)(ud + 1))[1] = proto;     /* src SAP */
+           /* Send the DLPI client the data with the SAP they requested,
+              (e.g. ETHERTYPE_IP) rather than the PPP protocol number
+              (e.g. PPP_IP) */
+           ((ulong *)(ud + 1))[0] = us->req_sap;       /* dest SAP */
+           ((ulong *)(ud + 1))[1] = us->req_sap;       /* src SAP */
            putnext(q, mp);
        }
     }
@@ -887,6 +1018,13 @@ ppplrput(q, mp)
     int proto;
 
     ppa = (struct upperstr *) q->q_ptr;
+    if (ppa == 0) {
+#if DEBUG
+       cmn_err(CE_CONT, "ppplrput: q = %x, ppa = 0??\n", q);
+#endif
+       freemsg(mp);
+       return 0;
+    }
     switch (mp->b_datap->db_type) {
     case M_FLUSH:
        if (*mp->b_rptr & FLUSHW) {
@@ -896,30 +1034,42 @@ ppplrput(q, mp)
            freemsg(mp);
        break;
 
+    case M_CTL:
+       freemsg(mp);
+       break;
+
     default:
-       if (mp->b_datap->db_type == M_DATA
-           && (proto = PPP_PROTOCOL(mp->b_rptr)) < 0x8000
-           && (us = find_dest(ppa, proto)) != 0) {
-           /*
-            * A data packet for some network protocol.
-            * Queue it on the upper stream for that protocol.
-            */
-           if (canput(us->q))
-               putq(us->q, mp);
-           else
-               putq(q, mp);
-           break;
-       } else {
-           /*
-            * A control frame, a frame for an unknown protocol,
-            * or some other message type.
-            * Send it up to pppd via the control stream.
-            */
-           if (mp->b_datap->db_type >= QPCTL || canputnext(ppa->q))
-               putnext(ppa->q, mp);
-           else
-               putq(q, mp);
+       if (mp->b_datap->db_type == M_DATA) {
+           if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN
+               && !pullupmsg(mp, PPP_HDRLEN)) {
+#if DEBUG
+               cmn_err(CE_CONT, "ppp_lrput: pullupmsg failed\n");
+#endif
+               freemsg(mp);
+               break;
+           }
+           proto = PPP_PROTOCOL(mp->b_rptr);
+           if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) {
+               /*
+                * A data packet for some network protocol.
+                * Queue it on the upper stream for that protocol.
+                */
+               if (canput(us->q))
+                   putq(us->q, mp);
+               else
+                   putq(q, mp);
+               break;
+           }
        }
+       /*
+        * A control frame, a frame for an unknown protocol,
+        * or some other message type.
+        * Send it up to pppd via the control stream.
+        */
+       if (mp->b_datap->db_type >= QPCTL || canputnext(ppa->q))
+           putnext(ppa->q, mp);
+       else
+           putq(q, mp);
        break;
     }
 
@@ -959,3 +1109,39 @@ ppplrsrv(q)
     }
     return 0;
 }
+
+static int
+putctl2(q, type, code, val)
+    queue_t *q;
+    int type, code, val;
+{
+    mblk_t *mp;
+
+    mp = allocb(2, BPRI_HI);
+    if (mp == 0)
+       return 0;
+    mp->b_datap->db_type = type;
+    mp->b_wptr[0] = code;
+    mp->b_wptr[1] = val;
+    mp->b_wptr += 2;
+    putnext(q, mp);
+    return 1;
+}
+
+static int
+putctl4(q, type, code, val)
+    queue_t *q;
+    int type, code, val;
+{
+    mblk_t *mp;
+
+    mp = allocb(4, BPRI_HI);
+    if (mp == 0)
+       return 0;
+    mp->b_datap->db_type = type;
+    mp->b_wptr[0] = code;
+    ((short *)mp->b_wptr)[1] = val;
+    mp->b_wptr += 4;
+    putnext(q, mp);
+    return 1;
+}
index 2e62d21b88f5a1d9b0ff320dc3f0a340ffa1d556..b483276bd9f39939b48ece071cdafc1cc5568518 100644 (file)
@@ -1,3 +1,36 @@
+/*
+ * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp_ahdlc.c,v 1.2 1995/05/19 02:18:34 paulus Exp $
+ */
+
+/*
+ * This file is used under Solaris 2.
+ */
+
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/stream.h>
@@ -6,6 +39,8 @@
 #include <sys/kmem.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
+#include <sys/errno.h>
+#include <sys/cmn_err.h>
 #include <net/ppp_defs.h>
 #include <net/pppio.h>
 
@@ -65,6 +100,7 @@ struct ahdlc_state {
     u_int32_t raccm;
     int mtu;
     int mru;
+    int unit;
 };
 
 /* Values for flags */
@@ -185,6 +221,7 @@ ahdlc_wput(q, mp)
 {
     struct ahdlc_state *state;
     struct iocblk *iop;
+    int error;
 
     state = (struct ahdlc_state *) q->q_ptr;
     switch (mp->b_datap->db_type) {
@@ -199,36 +236,63 @@ ahdlc_wput(q, mp)
 
     case M_IOCTL:
        iop = (struct iocblk *) mp->b_rptr;
+       error = EINVAL;
        switch (iop->ioc_cmd) {
        case PPPIO_XACCM:
-           if (iop->ioc_count != sizeof(ext_accm))
-               goto iocnak;
-           bcopy(mp->b_cont->b_rptr, (caddr_t)state->xaccm, sizeof(ext_accm));
+           if (iop->ioc_count < sizeof(u_int32_t)
+               || iop->ioc_count > sizeof(ext_accm))
+               break;
+           bcopy(mp->b_cont->b_rptr, (caddr_t)state->xaccm, iop->ioc_count);
            state->xaccm[2] &= 0x40000000;      /* don't escape 0x5e */
            state->xaccm[3] |= 0x60000000;      /* do escape 0x7d, 0x7e */
-           goto iocack;
+           iop->ioc_count = 0;
+           error = 0;
+           break;
 
        case PPPIO_RACCM:
            if (iop->ioc_count != sizeof(u_int32_t))
-               goto iocnak;
-           state->raccm = *(u_int32_t *)mp->b_cont->b_rptr;
-           goto iocack;
+               break;
+           bcopy(mp->b_cont->b_rptr, (caddr_t)&state->raccm,
+                 sizeof(u_int32_t));
+           iop->ioc_count = 0;
+           error = 0;
+           break;
 
        default:
-           putnext(q, mp);
+           error = -1;
            break;
+       }
 
-       iocack:
-           iop->ioc_count = 0;
+       if (error < 0)
+           putnext(q, mp);
+       else if (error == 0) {
            mp->b_datap->db_type = M_IOCACK;
            qreply(q, mp);
-           break;
-
-       iocnak:
+       } else {
            mp->b_datap->db_type = M_IOCNAK;
+           iop->ioc_count = 0;
+           iop->ioc_error = error;
            qreply(q, mp);
+       }
+       break;
+
+    case M_CTL:
+       switch (*mp->b_rptr) {
+       case PPPCTL_MTU:
+           state->mtu = ((unsigned short *)mp->b_rptr)[1];
+           freemsg(mp);
+           break;
+       case PPPCTL_MRU:
+           state->mru = ((unsigned short *)mp->b_rptr)[1];
+           freemsg(mp);
+           break;
+       case PPPCTL_UNIT:
+           state->unit = mp->b_rptr[1];
            break;
+       default:
+           putnext(q, mp);
        }
+       break;
 
     default:
        putnext(q, mp);
@@ -308,13 +372,22 @@ stuff_frame(q, mp)
 
     /*
      * For LCP packets, we must escape all control characters.
+     * LCP packets must not be A/C or protocol compressed.
      */
-    if (proto == PPP_LCP) {
-       bcopy(state->xaccm, lcp_xaccm, sizeof(lcp_xaccm));
-       lcp_xaccm[0] = ~0;
-       xaccm = lcp_xaccm;
-    } else
-       xaccm = state->xaccm;
+    xaccm = state->xaccm;
+    if (ilen >= PPP_HDRLEN) {
+       if (mp->b_wptr - mp->b_rptr >= PPP_HDRLEN
+           || pullupmsg(mp, PPP_HDRLEN)) {
+           if (PPP_ADDRESS(mp->b_rptr) == PPP_ALLSTATIONS
+               && PPP_CONTROL(mp->b_rptr) == PPP_UI
+               && PPP_PROTOCOL(mp->b_rptr) == PPP_LCP) {
+               bcopy((caddr_t) state->xaccm, (caddr_t) lcp_xaccm,
+                     sizeof(lcp_xaccm));
+               lcp_xaccm[0] = ~0;
+               xaccm = lcp_xaccm;
+           }
+       }
+    }
 
     sp = mp->b_rptr;
     fcs = PPP_INITFCS;
@@ -457,7 +530,7 @@ unstuff_chars(q, mp)
             */
            dp = om->b_wptr;
            len = om->b_datap->db_lim - dp; /* max # output bytes */
-           extra = (cpend - cp) - len;     /* #input chars - #output bytes */
+           extra = (mp->b_wptr - cp) - len;/* #input chars - #output bytes */
            if (extra < 0) {
                len += extra;               /* we'll run out of input first */
                extra = 0;
@@ -471,11 +544,10 @@ unstuff_chars(q, mp)
                    break;
                ++cp;
                if (c == PPP_ESCAPE) {
-                   if (extra > 0)
+                   if (extra > 0) {
                        --extra;
-                   else if (len > 1)
-                       --len;
-                   else {
+                       ++cpend;
+                   } else if (cp >= cpend) {
                        state->flags |= ESCAPED;
                        break;
                    }
@@ -491,7 +563,7 @@ unstuff_chars(q, mp)
            state->inlen += dp - dp0;
            state->infcs = fcs;
            om->b_wptr = dp;
-           if (len <= 0)
+           if (cp >= cpend)
                continue;       /* go back and check cp again */
        }
 
@@ -508,20 +580,19 @@ unstuff_chars(q, mp)
            state->inlen = 0;
            if (om == 0)
                continue;
-           if (state->flags & (IFLUSH|ESCAPED) || len < PPP_FCSLEN) {
-               /* XXX should send up ctl message to notify VJ decomp */
-               freemsg(om);
-               continue;
-           }
-           if (state->infcs != PPP_GOODFCS) {
+           if (!(state->flags & (IFLUSH|ESCAPED) || len < PPP_FCSLEN)) {
+               if (state->infcs == PPP_GOODFCS) {
+                   adjmsg(om, -PPP_FCSLEN);    /* chop off fcs */
+                   putnext(q, om);             /* bombs away! */
+                   continue;
+               }
                /* incr bad fcs stats */
-               /* would like to be able to pass this up for debugging */
-               /* XXX should send up ctl message to notify VJ decomp */
-               freemsg(om);
-               continue;
+#if DEBUG
+               cmn_err(CE_CONT, "ppp_ahdl: bad fcs %x\n", state->infcs);
+#endif
            }
-           adjmsg(om, -PPP_FCSLEN);    /* chop off fcs */
-           putnext(q, om);             /* bombs away! */
+           freemsg(om);
+           putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
            continue;
        }
 
@@ -529,6 +600,7 @@ unstuff_chars(q, mp)
            continue;
        if (state->flags & ESCAPED) {
            c ^= PPP_TRANS;
+           state->flags &= ~ESCAPED;
        } else if (c == PPP_ESCAPE) {
            state->flags |= ESCAPED;
            continue;
@@ -549,11 +621,19 @@ unstuff_chars(q, mp)
            om = state->cur_blk;
            if (om->b_wptr >= om->b_datap->db_lim) {
                /*
-                * Current message block is full.  Allocate another one.
+                * Current message block is full.  Allocate another one,
+                * unless we have run out of MRU.
                 */
+               if (state->inlen >= state->mru + PPP_HDRLEN + PPP_FCSLEN) {
+#if DEBUG
+                   cmn_err(CE_CONT, "ppp_ahdl: frame too long (%d)\n",
+                           state->inlen);
+#endif
+                   state->flags |= IFLUSH;
+                   continue;
+               }
                om = allocb(IFRAME_BSIZE, BPRI_MED);
                if (om == 0) {
-                   freemsg(state->cur_frame);
                    state->flags |= IFLUSH;
                    continue;
                }
@@ -571,18 +651,20 @@ unstuff_chars(q, mp)
             * but we do leave space for the decompressed fields and
             * arrange for the info field to start on a word boundary.
             */
-           cp = om->b_rptr;
-           if (*cp == PPP_ALLSTATIONS)
-               cp += 2;
-           if ((*cp & 1) == 0)
-               ++cp;
-           /* cp is now pointing at the last byte of the ppp protocol field */
-           offset = 3 - ((unsigned)cp & 3);
+           dp = om->b_rptr;
+           if (PPP_ADDRESS(dp) == PPP_ALLSTATIONS
+               && PPP_CONTROL(dp) == PPP_UI)
+               dp += 2;
+           if ((*dp & 1) == 0)
+               ++dp;
+           /* dp is now pointing at the last byte of the ppp protocol field */
+           offset = 3 - ((unsigned)dp & 3);
            if (offset > 0) {
+               dp = om->b_wptr;
                do {
-                   cp[offset] = cp[0];
-                   --cp;
-               } while (cp >= om->b_rptr);
+                   --dp;
+                   dp[offset] = dp[0];
+               } while (dp > om->b_rptr);
                om->b_rptr += offset;
                om->b_wptr += offset;
            }
index 254a9358890fb00279cc2448ef62199786ecc8d1..7eb54ec7cc182ddb70ac97d2ca4a620ce3bb2dd9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * ppp_comp.c - STREAMS module for kernel-level CCP support.
+ * ppp_comp.c - STREAMS module for kernel-level compression and CCP support.
  *
  * Copyright (c) 1994 The Australian National University.
  * All rights reserved.
  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
  * OR MODIFICATIONS.
  *
- * $Id: ppp_comp.c,v 1.1 1995/05/10 01:38:47 paulus Exp $
+ * $Id: ppp_comp.c,v 1.2 1995/05/19 02:18:11 paulus Exp $
  */
 
 /*
- * This file is used under SunOS 4.x, and OSF/1 on DEC Alpha.
- *
- * Beware that under OSF/1, the ioctl constants (SIOC*) end up
- * as 64-bit (long) values, so an ioctl constant should be cast to
- * int (32 bits) before being compared with the ioc_cmd field of
- * an iocblk structure.
+ * This file is used under Solaris 2.
  */
 
 #include <sys/types.h>
 #include <sys/kmem.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
+#include <sys/cmn_err.h>
 #include <net/ppp_defs.h>
-#include <net/ppp_str.h>
+#include <net/pppio.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <net/vjcompress.h>
 
-#define ALLOCATE(n)    kmem_zalloc((n), KM_NOSLEEP)
+#define ALLOCATE(n)    kmem_alloc((n), KM_NOSLEEP)
 #define FREE(p, n)     kmem_free((p), (n))
 
 #define PACKETPTR      mblk_t *
 static int ppp_comp_open __P((queue_t *, dev_t *, int, int, cred_t *));
 static int ppp_comp_close __P((queue_t *, int, cred_t *));
 static int ppp_comp_rput __P((queue_t *, mblk_t *));
+static int ppp_comp_rsrv __P((queue_t *));
 static int ppp_comp_wput __P((queue_t *, mblk_t *));
+static int ppp_comp_wsrv __P((queue_t *));
 static void ppp_comp_ccp __P((queue_t *, mblk_t *, int));
 
 static struct module_info minfo = {
-    0xbadf, "ppp_compress", 0, INFPSZ, 16384, 4096,
+    0xbadf, "ppp_comp", 0, INFPSZ, 16384, 4096,
 };
 
 static struct qinit r_init = {
-    ppp_comp_rput, NULL, ppp_comp_open, ppp_comp_close,
+    ppp_comp_rput, ppp_comp_rsrv, ppp_comp_open, ppp_comp_close,
     NULL, &minfo, NULL
 };
 
 static struct qinit w_init = {
-    ppp_comp_wput, NULL, NULL, NULL, NULL, &minfo, NULL
+    ppp_comp_wput, ppp_comp_wsrv, NULL, NULL, NULL, &minfo, NULL
 };
 
 static struct streamtab ppp_compinfo = {
@@ -101,11 +103,14 @@ struct ppp_comp_state {
     int                flags;
     int                mru;
     int                mtu;
+    int                unit;
+    int                ierrors;
     struct compressor *xcomp;
     void       *xstate;
     struct compressor *rcomp;
     void       *rstate;
     struct vjcompress vj_comp;
+    int                vj_last_ierrors;
 };
 
 /* Bits in flags are as defined in pppio.h. */
@@ -153,9 +158,9 @@ _info(mip)
  * STREAMS module entry points.
  */
 static int
-ppp_comp_open(q, dev, flag, sflag, credp)
+ppp_comp_open(q, devp, flag, sflag, credp)
     queue_t *q;
-    dev_t dev;
+    dev_t *devp;
     int flag, sflag;
     cred_t *credp;
 {
@@ -165,21 +170,27 @@ ppp_comp_open(q, dev, flag, sflag, credp)
        cp = (struct ppp_comp_state *) ALLOCATE(sizeof(struct ppp_comp_state));
        if (cp == NULL)
            return ENOSR;
-       OTHERQ(q)->q_ptr = q->q_ptr = cp;
-       cp->flags = 0;
+       WR(q)->q_ptr = q->q_ptr = cp;
+       bzero((caddr_t)cp, sizeof(struct ppp_comp_state));
        cp->mru = PPP_MRU;
+       cp->mtu = PPP_MRU;
        cp->xstate = NULL;
        cp->rstate = NULL;
+       vj_compress_init(&cp->vj_comp, -1);
+       qprocson(q);
     }
     return 0;
 }
 
 static int
-ppp_comp_close(q)
+ppp_comp_close(q, flag, credp)
     queue_t *q;
+    int flag;
+    cred_t *credp;
 {
     struct ppp_comp_state *cp;
 
+    qprocsoff(q);
     cp = (struct ppp_comp_state *) q->q_ptr;
     if (cp != NULL) {
        if (cp->xstate != NULL)
@@ -200,21 +211,168 @@ ppp_comp_wput(q, mp)
 {
     struct iocblk *iop;
     struct ppp_comp_state *cp;
-    mblk_t *cmp;
-    int error, len, proto, state;
-    struct ppp_option_data *odp;
+    int error, len;
+    int flags, mask;
     struct compressor **comp;
     struct ppp_comp_stats *pcp;
+    unsigned char *opt_data;
+    int nxslots, nrslots;
 
     cp = (struct ppp_comp_state *) q->q_ptr;
     switch (mp->b_datap->db_type) {
 
     case M_DATA:
+       putq(q, mp);
+       break;
+
+    case M_IOCTL:
+       iop = (struct iocblk *) mp->b_rptr;
+       error = EINVAL;
+       switch (iop->ioc_cmd) {
+
+       case PPPIO_CFLAGS:
+           /* set/get CCP state */
+           if (iop->ioc_count != 2 * sizeof(int))
+               break;
+           flags = ((int *) mp->b_cont->b_rptr)[0];
+           mask = ((int *) mp->b_cont->b_rptr)[1];
+           cp->flags = (cp->flags & ~mask) | (flags & mask);
+           if ((mask & CCP_ISOPEN) && (flags & CCP_ISOPEN) == 0) {
+               if (cp->xstate != NULL) {
+                   (*cp->xcomp->comp_free)(cp->xstate);
+                   cp->xstate = NULL;
+               }
+               if (cp->rstate != NULL) {
+                   (*cp->rcomp->decomp_free)(cp->rstate);
+                   cp->rstate = NULL;
+               }
+               cp->flags &= ~CCP_ISUP;
+           }
+           error = 0;
+           iop->ioc_count = sizeof(int);
+           ((int *) mp->b_cont->b_rptr)[0] = cp->flags;
+           mp->b_cont->b_wptr = mp->b_cont->b_rptr + sizeof(int);
+           break;
+
+       case PPPIO_VJINIT:
+           /*
+            * Initialize VJ compressor/decompressor
+            */
+           if (iop->ioc_count != 2)
+               break;
+           nxslots = mp->b_cont->b_rptr[0] + 1;
+           nrslots = mp->b_cont->b_rptr[1] + 1;
+           if (nxslots > MAX_STATES || nrslots > MAX_STATES)
+               break;
+           vj_compress_init(&cp->vj_comp, nxslots);
+           cp->vj_last_ierrors = cp->ierrors;
+           error = 0;
+           iop->ioc_count = 0;
+           break;
+
+       case PPPIO_XCOMP:
+       case PPPIO_RCOMP:
+           if (iop->ioc_count <= 0)
+               break;
+           opt_data = mp->b_cont->b_rptr;
+           len = mp->b_cont->b_wptr - opt_data;
+           if (len > iop->ioc_count)
+               len = iop->ioc_count;
+           if (opt_data[1] < 2 || opt_data[1] > len)
+               break;
+           for (comp = ppp_compressors; *comp != NULL; ++comp)
+               if ((*comp)->compress_proto == opt_data[0]) {
+                   /* here's the handler! */
+                   error = 0;
+                   if (iop->ioc_cmd == PPPIO_XCOMP) {
+                       if (cp->xstate != NULL)
+                           (*cp->xcomp->comp_free)(cp->xstate);
+                       cp->xcomp = *comp;
+                       cp->xstate = (*comp)->comp_alloc(opt_data, len);
+                       if (cp->xstate == NULL)
+                           error = ENOSR;
+                   } else {
+                       if (cp->rstate != NULL)
+                           (*cp->rcomp->decomp_free)(cp->rstate);
+                       cp->rcomp = *comp;
+                       cp->rstate = (*comp)->decomp_alloc(opt_data, len);
+                       if (cp->rstate == NULL)
+                           error = ENOSR;
+                   }
+                   break;
+               }
+           iop->ioc_count = 0;
+           break;
+
+       case PPPIO_MRU:
+           /* remember this value */
+           if (iop->ioc_count == sizeof(int)) {
+               cp->mru = *(int *) mp->b_cont->b_rptr;
+           }
+           error = -1;
+           break;
+
+       default:
+           error = -1;
+           break;
+       }
+
+       if (error < 0)
+           putnext(q, mp);
+       else if (error == 0) {
+           mp->b_datap->db_type = M_IOCACK;
+           qreply(q, mp);
+       } else {
+           mp->b_datap->db_type = M_IOCNAK;
+           iop->ioc_error = error;
+           iop->ioc_count = 0;
+           qreply(q, mp);
+       }
+       break;
+
+    case M_CTL:
+       switch (*mp->b_rptr) {
+       case PPPCTL_MTU:
+           cp->mtu = ((unsigned short *)mp->b_rptr)[1];
+           break;
+       case PPPCTL_MRU:
+           cp->mru = ((unsigned short *)mp->b_rptr)[1];
+           break;
+       case PPPCTL_UNIT:
+           cp->unit = mp->b_rptr[1];
+           break;
+       }
+       putnext(q, mp);
+       break;
+
+    default:
+       putnext(q, mp);
+    }
+}
+
+static int
+ppp_comp_wsrv(q)
+    queue_t *q;
+{
+    mblk_t *mp, *cmp;
+    struct ppp_comp_state *cp;
+    int len, proto, type;
+    struct ip *ip;
+    unsigned char *vjhdr, *dp;
+
+    cp = (struct ppp_comp_state *) q->q_ptr;
+    while ((mp = getq(q)) != 0) {
+       /* assert(mp->b_datap->db_type == M_DATA) */
+       if (!canputnext(q)) {
+           putbq(q, mp);
+           return;
+       }
+
        /* first find out what the protocol is */
        if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN
            && !pullupmsg(mp, PPP_HDRLEN)) {
            freemsg(mp);        /* give up on it */
-           break;
+           continue;
        }
        proto = PPP_PROTOCOL(mp->b_rptr);
 
@@ -229,7 +387,7 @@ ppp_comp_wput(q, mp)
                ip = (struct ip *) (mp->b_rptr + PPP_HDRLEN);
                if (ip->ip_p == IPPROTO_TCP) {
                    type = vj_compress_tcp(ip, len - PPP_HDRLEN,
-                               cp->vj_comp, (cp->flags & COMP_VJCCID),
+                               &cp->vj_comp, (cp->flags & COMP_VJCCID),
                                &vjhdr);
                    switch (type) {
                    case TYPE_UNCOMPRESSED_TCP:
@@ -279,99 +437,30 @@ ppp_comp_wput(q, mp)
        }
 
        putnext(q, mp);
-       break;
-
-    case M_IOCTL:
-       iop = (struct iocblk *) mp->b_rptr;
-       error = -1;
-       switch (iop->ioc_cmd) {
+    }
+}
 
-       case PPPIO_CFLAGS:
-           /* set CCP state */
-           if (iop->ioc_count != sizeof(int)) {
-               error = EINVAL;
-               break;
-           }
-           state = (*(int *) mp->b_cont->b_rptr) & (CCP_ISUP | CCP_ISOPEN);
-           if ((state & CCP_ISOPEN) == 0) {
-               if (cp->xstate != NULL) {
-                   (*cp->xcomp->comp_free)(cp->xstate);
-                   cp->xstate = NULL;
-               }
-               if (cp->rstate != NULL) {
-                   (*cp->rcomp->decomp_free)(cp->rstate);
-                   cp->rstate = NULL;
-               }
-               cp->flags = 0;
-           } else {
-               cp->flags = (cp->flags & ~CCP_ISUP) | state;
-           }
-           error = 0;
-           iop->ioc_count = 0;
-           break;
+static int
+ppp_comp_rput(q, mp)
+    queue_t *q;
+    mblk_t *mp;
+{
+    struct ppp_comp_state *cp;
 
-       case SIOCGIFCOMP:
-           if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL) {
-               error = ENOSR;
-               break;
-           }
-           *(int *)mp->b_cont->b_wptr = cp->flags;
-           mp->b_cont->b_wptr += iop->ioc_count = sizeof(int);
-           break;
+    cp = (struct ppp_comp_state *) q->q_ptr;
+    switch (mp->b_datap->db_type) {
 
-       case PPPIO_COMPRESS:
-           error = EINVAL;
-           if (iop->ioc_count != sizeof(struct ppp_option_data))
-               break;
-           odp = (struct ppp_option_data *) mp->b_cont->b_rptr;
-           len = mp->b_cont->b_wptr - (unsigned char *) odp->opt_data;
-           if (len > odp->length)
-               len = odp->length;
-           if (odp->opt_data[1] < 2 || odp->opt_data[1] > len)
-               break;
-           for (comp = ppp_compressors; *comp != NULL; ++comp)
-               if ((*comp)->compress_proto == odp->opt_data[0]) {
-                   /* here's the handler! */
-                   error = 0;
-                   if (odp->transmit) {
-                       if (cp->xstate != NULL)
-                           (*cp->xcomp->comp_free)(cp->xstate);
-                       cp->xcomp = *comp;
-                       cp->xstate = (*comp)->comp_alloc(odp->opt_data, len);
-                       if (cp->xstate == NULL)
-                           error = ENOSR;
-                   } else {
-                       if (cp->rstate != NULL)
-                           (*cp->rcomp->decomp_free)(cp->rstate);
-                       cp->rcomp = *comp;
-                       cp->rstate = (*comp)->decomp_alloc(odp->opt_data, len);
-                       if (cp->rstate == NULL)
-                           error = ENOSR;
-                   }
-                   break;
-               }
-           iop->ioc_count = 0;
-           break;
+    case M_DATA:
+       putq(q, mp);
+       break;
 
-       case PPPIO_MRU:
-           /* remember this value */
-           if (iop->ioc_count == sizeof(int)) {
-               cp->mru = *(int *) mp->b_cont->b_rptr;
-           }
+    case M_CTL:
+       switch (mp->b_rptr[0]) {
+       case PPPCTL_IERROR:
+           ++cp->ierrors;
            break;
-
-       }
-
-       if (error < 0)
-           putnext(q, mp);
-       else if (error == 0) {
-           mp->b_datap->db_type = M_IOCACK;
-           qreply(q, mp);
-       } else {
-           mp->b_datap->db_type = M_IOCNAK;
-           iop->ioc_count = 0;
-           qreply(q, mp);
        }
+       putnext(q, mp);
        break;
 
     default:
@@ -380,18 +469,25 @@ ppp_comp_wput(q, mp)
 }
 
 static int
-ppp_comp_rput(q, mp)
+ppp_comp_rsrv(q)
     queue_t *q;
-    mblk_t *mp;
 {
     int proto, rv;
-    mblk_t *dmp;
+    mblk_t *mp, *dmp, *np;
+    unsigned char *dp, *iphdr;
     struct ppp_comp_state *cp;
+    int len, hlen, vjlen, iphlen;
+    int oldierrors;
 
     cp = (struct ppp_comp_state *) q->q_ptr;
-    switch (mp->b_datap->db_type) {
+    oldierrors = cp->ierrors;
+    while ((mp = getq(q)) != 0) {
+       /* assert(mp->b_datap->db_type == M_DATA) */
+       if (!canputnext(q)) {
+           putbq(q, mp);
+           return;
+       }
 
-    case M_DATA:
        /*
         * First do address/control and protocol "decompression".
         */
@@ -399,9 +495,9 @@ ppp_comp_rput(q, mp)
        if (len > PPP_HDRLEN)
            len = PPP_HDRLEN;
        if (mp->b_wptr - mp->b_rptr < len && !pullupmsg(mp, len)) {
-           /* XXX reset VJ */
+           ++cp->ierrors;
            freemsg(mp);
-           break;
+           continue;
        }
        dp = mp->b_rptr;
        if (PPP_ADDRESS(dp) == PPP_ALLSTATIONS && PPP_CONTROL(dp) == PPP_UI)
@@ -411,16 +507,18 @@ ppp_comp_rput(q, mp)
            proto = *dp++ << 8;         /* grab high byte of protocol */
        proto += *dp++;                 /* grab low byte of protocol */
        if (dp > mp->b_wptr) {
-           freemsg(mp);        /* short/bogus packet */
-           break;
+           ++cp->ierrors;              /* short/bogus packet */
+           freemsg(mp);
+           continue;
        }
        if ((dp -= PPP_HDRLEN) < mp->b_datap->db_base) {
            /* yucko, need a new message block */
            mp->b_rptr = dp;
            np = allocb(PPP_HDRLEN, BPRI_MED);
            if (np == 0) {
+               ++cp->ierrors;
                freemsg(mp);
-               break;
+               continue;
            }
            linkb(np, mp);
            mp = np;
@@ -453,13 +551,14 @@ ppp_comp_rput(q, mp)
                    case DECOMP_OK:
                        /* no error, but no packet returned */
                        freemsg(mp);
-                       mp = NULL;
-                       break;
+                       continue;
                    case DECOMP_ERROR:
                        cp->flags |= CCP_ERROR;
+                       ++cp->ierrors;
                        break;
                    case DECOMP_FATALERROR:
                        cp->flags |= CCP_FATALERROR;
+                       ++cp->ierrors;
                        break;
                    }
                }
@@ -471,14 +570,81 @@ ppp_comp_rput(q, mp)
        /*
         * Now do VJ decompression.
         */
+       proto = PPP_PROTOCOL(mp->b_rptr);
+       if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
+           if ((cp->flags & DECOMP_VJC) == 0) {
+               ++cp->ierrors;  /* ? */
+               freemsg(mp);
+               continue;
+           }
+           if (cp->ierrors != cp->vj_last_ierrors) {
+               vj_uncompress_err(&cp->vj_comp);
+               cp->vj_last_ierrors = cp->ierrors;
+           }
+           len = msgdsize(mp);
+           hlen = (proto == PPP_VJC_COMP? MAX_VJHDR: MAX_IPHDR) + PPP_HDRLEN;
+           if (hlen > len)
+               hlen = len;
+           if (mp->b_wptr - mp->b_rptr < hlen && !pullupmsg(mp, hlen)) {
+               ++cp->ierrors;
+               freemsg(mp);
+               continue;
+           }
 
-       if (mp != NULL)
-           putnext(q, mp);
-       break;
+           if (proto == PPP_VJC_COMP) {
+               mp->b_rptr += PPP_HDRLEN;
+               vjlen = vj_uncompress_tcp(mp->b_rptr, mp->b_wptr - mp->b_rptr,
+                                         len - PPP_HDRLEN, &cp->vj_comp,
+                                         &iphdr, &iphlen);
+               if (vjlen < 0
+                   || (np = allocb(iphlen + PPP_HDRLEN + 4, BPRI_MED)) == 0) {
+                   ++cp->ierrors;
+                   freemsg(mp);
+                   continue;
+               }
+
+               mp->b_rptr += vjlen;    /* drop off VJ header */
+               dp = np->b_rptr;        /* prepend mblk with TCP/IP hdr */
+               dp[0] = PPP_ALLSTATIONS; /* reconstruct PPP header */
+               dp[1] = PPP_UI;
+               dp[2] = PPP_IP >> 8;
+               dp[3] = PPP_IP;
+               bcopy(iphdr, dp + PPP_HDRLEN, iphlen);
+               np->b_wptr = dp + iphlen + PPP_HDRLEN;
+               np->b_cont = mp;
+
+               /* XXX there seems to be a bug which causes panics in strread
+                  if we make an mbuf with only the IP header in it :-( */
+               if (mp->b_wptr - mp->b_rptr > 4) {
+                   bcopy(mp->b_rptr, np->b_wptr, 4);
+                   mp->b_rptr += 4;
+                   np->b_wptr += 4;
+               } else {
+                   bcopy(mp->b_rptr, np->b_wptr, mp->b_wptr - mp->b_rptr);
+                   np->b_wptr += mp->b_wptr - mp->b_rptr;
+                   np->b_cont = mp->b_cont;
+                   freeb(mp);
+               }
+
+               mp = np;
+
+           } else {
+               if (!vj_uncompress_uncomp(mp->b_rptr + PPP_HDRLEN,
+                                         &cp->vj_comp)) {
+                   ++cp->ierrors;
+                   freemsg(mp);
+                   continue;
+               }
+               mp->b_rptr[3] = PPP_IP; /* fix up the PPP protocol field */
+           }
+       }
 
-    default:
        putnext(q, mp);
     }
+#if DEBUG
+    if (cp->ierrors != oldierrors)
+       cmn_err(CE_CONT, "ppp_comp_rsrv ierrors now %d\n", cp->ierrors);
+#endif
 }
 
 /*
@@ -519,13 +685,13 @@ ppp_comp_ccp(q, mp, rcvd)
                if (cp->xstate != NULL
                    && (*cp->xcomp->comp_init)
                        (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
-                        0, /* XXX: should be unit */ 0, 0))
+                        cp->unit, 0, 0))
                    cp->flags |= CCP_COMP_RUN;
            } else {
                if (cp->rstate != NULL
                    && (*cp->rcomp->decomp_init)
                        (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
-                        0/* unit */, 0, cp->mru, 0))
+                        cp->unit, 0, cp->mru, 0))
                    cp->flags = (cp->flags & ~CCP_ERR)
                        | CCP_DECOMP_RUN;
            }
@@ -548,3 +714,21 @@ ppp_comp_ccp(q, mp, rcvd)
     }
 
 }
+
+#if DEBUG
+dump_msg(mp)
+    mblk_t *mp;
+{
+    dblk_t *db;
+
+    while (mp != 0) {
+       db = mp->b_datap;
+       cmn_err(CE_CONT, "mp=%x cont=%x rptr=%x wptr=%x datap=%x\n",
+               mp, mp->b_cont, mp->b_rptr, mp->b_wptr, db);
+       cmn_err(CE_CONT, "  base=%x lim=%x ref=%d type=%d struioflag=%d\n",
+               db->db_base, db->db_lim, db->db_ref, db->db_type,
+               db->db_struioflag);
+       mp = mp->b_cont;
+    }
+}
+#endif