]> git.ozlabs.org Git - ppp.git/blobdiff - modules/ppp_comp.c
fixes from Farrell
[ppp.git] / modules / ppp_comp.c
index 3795647c3d94c7f6c975fb142d296fb3e1096e2c..c3badd3698c54c5266a8260a8965e5507e29593e 100644 (file)
  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
  * OR MODIFICATIONS.
  *
- * $Id: ppp_comp.c,v 1.1 1995/12/11 05:06:43 paulus Exp $
+ * $Id: ppp_comp.c,v 1.8 1997/04/30 05:45:15 paulus Exp $
  */
 
 /*
- * This file is used under SVR4, Solaris 2, SunOS 4, and OSF/1.
+ * This file is used under SVR4, Solaris 2, SunOS 4, and Digital UNIX.
  */
 
 #include <sys/types.h>
 #include <sys/ddi.h>
 #else
 #include <sys/user.h>
+#ifdef __osf__
+#include <sys/cmn_err.h>
+#endif
 #endif /* SVR4 */
 
 #include <net/ppp_defs.h>
 #include <net/pppio.h>
 #include "ppp_mod.h"
 
+#ifdef __osf__
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#endif
+
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
@@ -72,8 +80,13 @@ static int msg_byte __P((mblk_t *, unsigned int));
 /* Is this LCP packet one we have to transmit using LCP defaults? */
 #define LCP_USE_DFLT(mp)       (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
 
+#define PPP_COMP_ID 0xbadf
 static struct module_info minfo = {
-    0xbadf, "ppp_comp", 0, INFPSZ, 16384, 4096,
+#ifdef PRIOQ
+    PPP_COMP_ID, "ppp_comp", 0, INFPSZ, 16512, 16384,
+#else
+    PPP_COMP_ID, "ppp_comp", 0, INFPSZ, 16384, 4096,
+#endif
 };
 
 static struct qinit r_init = {
@@ -85,12 +98,28 @@ static struct qinit w_init = {
     ppp_comp_wput, ppp_comp_wsrv, NULL, NULL, NULL, &minfo, NULL
 };
 
+#if defined(SVR4) && !defined(SOL2)
+int pcmpdevflag = 0;
+#define ppp_compinfo pcmpinfo
+#endif
 struct streamtab ppp_compinfo = {
     &r_init, &w_init, NULL, NULL
 };
 
 int ppp_comp_count;            /* number of module instances in use */
 
+#ifdef __osf__
+
+static void ppp_comp_alloc __P((comp_state_t *));
+typedef struct memreq {
+    unsigned char comp_opts[20];
+    int cmd;
+    int thread_status;
+    char *returned_mem;
+} memreq_t;
+
+#endif
+
 typedef struct comp_state {
     int                flags;
     int                mru;
@@ -103,11 +132,21 @@ typedef struct comp_state {
     struct vjcompress vj_comp;
     int                vj_last_ierrors;
     struct pppstat stats;
+#ifdef __osf__
+    memreq_t   memreq;
+    thread_t   thread;
+#endif
 } comp_state_t;
 
+
+#ifdef __osf__
+extern task_t first_task;
+#endif
+
 /* Bits in flags are as defined in pppio.h. */
 #define CCP_ERR                (CCP_ERROR | CCP_FATALERROR)
 #define LAST_MOD       0x1000000       /* no ppp modules below us */
+#define DBGLOG         0x2000000       /* log debugging stuff */
 
 #define MAX_IPHDR      128     /* max TCP/IP header size */
 #define MAX_VJHDR      20      /* max VJ compressed header size (?) */
@@ -119,11 +158,19 @@ typedef struct comp_state {
  * List of compressors we know about.
  */
 
+#if DO_BSD_COMPRESS
 extern struct compressor ppp_bsd_compress;
+#endif
+#if DO_DEFLATE
+extern struct compressor ppp_deflate;
+#endif
 
 struct compressor *ppp_compressors[] = {
 #if DO_BSD_COMPRESS
     &ppp_bsd_compress,
+#endif
+#if DO_DEFLATE
+    &ppp_deflate,
 #endif
     NULL
 };
@@ -134,6 +181,9 @@ struct compressor *ppp_compressors[] = {
 MOD_OPEN(ppp_comp_open)
 {
     comp_state_t *cp;
+#ifdef __osf__
+    thread_t thread;
+#endif
 
     if (q->q_ptr == NULL) {
        cp = (comp_state_t *) ALLOC_SLEEP(sizeof(comp_state_t));
@@ -142,12 +192,17 @@ MOD_OPEN(ppp_comp_open)
        WR(q)->q_ptr = q->q_ptr = (caddr_t) cp;
        bzero((caddr_t)cp, sizeof(comp_state_t));
        cp->mru = PPP_MRU;
-       cp->mtu = PPP_MRU;
+       cp->mtu = PPP_MTU;
        cp->xstate = NULL;
        cp->rstate = NULL;
        vj_compress_init(&cp->vj_comp, -1);
        ++ppp_comp_count;
        qprocson(q);
+#ifdef __osf__
+       if (!(thread = kernel_thread_w_arg(first_task, ppp_comp_alloc, (void *)cp)))
+               OPEN_ERROR(ENOSR);
+       cp->thread = thread;
+#endif
     }
     return 0;
 }
@@ -163,6 +218,12 @@ MOD_CLOSE(ppp_comp_close)
            (*cp->xcomp->comp_free)(cp->xstate);
        if (cp->rstate != NULL)
            (*cp->rcomp->decomp_free)(cp->rstate);
+#ifdef __osf__
+       if (!cp->thread)
+           printf("ppp_comp_close: NULL thread!\n");
+       else
+           thread_terminate(cp->thread);
+#endif
        FREE(cp, sizeof(comp_state_t));
        q->q_ptr = NULL;
        OTHERQ(q)->q_ptr = NULL;
@@ -171,6 +232,82 @@ MOD_CLOSE(ppp_comp_close)
     return 0;
 }
 
+#ifdef __osf__
+
+/* thread for calling back to a compressor's memory allocator
+ * Needed for Digital UNIX since it's VM can't handle requests
+ * for large amounts of memory without blocking.  The thread
+ * provides a context in which we can call a memory allocator
+ * that may block.
+ */
+static void
+ppp_comp_alloc(comp_state_t *cp)
+{
+    int len, cmd;
+    unsigned char *compressor_options;
+    thread_t thread;
+    void *(*comp_allocator)();
+
+
+#if defined(MAJOR_VERSION) && (MAJOR_VERSION <= 2)
+
+    /* In 2.x and earlier the argument gets passed
+     * in the thread structure itself.  Yuck.
+     */
+    thread = current_thread();
+    cp = thread->reply_port;
+    thread->reply_port = PORT_NULL;
+
+#endif
+
+    for (;;) {
+       assert_wait((vm_offset_t)&cp->memreq.thread_status, TRUE);
+       thread_block();
+
+       if (thread_should_halt(current_thread()))
+           thread_halt_self();
+       cmd = cp->memreq.cmd;
+       compressor_options = &cp->memreq.comp_opts[0];
+       len = compressor_options[1];
+       if (cmd == PPPIO_XCOMP) {
+           cp->memreq.returned_mem = cp->xcomp->comp_alloc(compressor_options, len);
+           if (!cp->memreq.returned_mem) {
+               cp->memreq.thread_status = ENOSR;
+           } else {
+               cp->memreq.thread_status = 0;
+           }
+       } else {
+           cp->memreq.returned_mem = cp->rcomp->decomp_alloc(compressor_options, len);
+           if (!cp->memreq.returned_mem) {
+               cp->memreq.thread_status = ENOSR;
+           } else {
+               cp->memreq.thread_status = 0;
+           }
+       }
+    }
+}
+
+#endif /* __osf__ */
+
+/* here's the deal with memory allocation under Digital UNIX.
+ * Some other may also benefit from this...
+ * We can't ask for huge chunks of memory in a context where
+ * the caller can't be put to sleep (like, here.)  The alloc
+ * is likely to fail.  Instead we do this: the first time we
+ * get called, kick off a thread to do the allocation.  Return
+ * immediately to the caller with EAGAIN, as an indication that
+ * they should send down the ioctl again.  By the time the
+ * second call comes in it's likely that the memory allocation
+ * thread will have returned with the requested memory.  We will
+ * continue to return EAGAIN however until the thread has completed.
+ * When it has, we return zero (and the memory) if the allocator
+ * was successful and ENOSR otherwise.
+ *
+ * Callers of the RCOMP and XCOMP ioctls are encouraged (but not
+ * required) to loop for some number of iterations with a small
+ * delay in the loop body (for instance a 1/10-th second "sleep"
+ * via select.)
+ */
 static int
 ppp_comp_wput(q, mp)
     queue_t *q;
@@ -178,7 +315,7 @@ ppp_comp_wput(q, mp)
 {
     struct iocblk *iop;
     comp_state_t *cp;
-    int error, len;
+    int error, len, n;
     int flags, mask;
     mblk_t *np;
     struct compressor **comp;
@@ -253,21 +390,82 @@ ppp_comp_wput(q, mp)
                if ((*comp)->compress_proto == opt_data[0]) {
                    /* here's the handler! */
                    error = 0;
+#ifndef __osf__
                    if (iop->ioc_cmd == PPPIO_XCOMP) {
-                       if (cp->xstate != NULL)
+                       /* A previous call may have fetched memory for a compressor
+                        * that's now being retired or reset.  Free it using it's
+                        * mechanism for freeing stuff.
+                        */
+                       if (cp->xstate != NULL) {
                            (*cp->xcomp->comp_free)(cp->xstate);
+                           cp->xstate = NULL;
+                       }
                        cp->xcomp = *comp;
                        cp->xstate = (*comp)->comp_alloc(opt_data, len);
                        if (cp->xstate == NULL)
                            error = ENOSR;
                    } else {
-                       if (cp->rstate != NULL)
+                       if (cp->rstate != NULL) {
                            (*cp->rcomp->decomp_free)(cp->rstate);
+                           cp->rstate = NULL;
+                       }
                        cp->rcomp = *comp;
                        cp->rstate = (*comp)->decomp_alloc(opt_data, len);
                        if (cp->rstate == NULL)
                            error = ENOSR;
                    }
+#else
+                   if ((error = cp->memreq.thread_status) != EAGAIN)
+                   if (iop->ioc_cmd == PPPIO_XCOMP) {
+                       if (cp->xstate) {
+                           (*cp->xcomp->comp_free)(cp->xstate);
+                           cp->xstate = 0;
+                       }
+                       /* sanity check for compressor options
+                        */
+                       if (sizeof (cp->memreq.comp_opts) < len) {
+                           printf("can't handle options for compressor %d (%d)\n", opt_data[0],
+                               opt_data[1]);
+                           cp->memreq.thread_status = ENOSR;
+                           cp->memreq.returned_mem = 0;
+                       }
+                       /* fill in request for the thread and kick it off
+                        */
+                       if (cp->memreq.thread_status == 0 && !cp->memreq.returned_mem) {
+                           bcopy(opt_data, cp->memreq.comp_opts, len);
+                           cp->memreq.cmd = PPPIO_XCOMP;
+                           cp->xcomp = *comp;
+                           error = cp->memreq.thread_status = EAGAIN;
+                           thread_wakeup((vm_offset_t)&cp->memreq.thread_status);
+                       } else {
+                           cp->xstate = cp->memreq.returned_mem;
+                           cp->memreq.returned_mem = 0;
+                           cp->memreq.thread_status = 0;
+                       }
+                   } else {
+                       if (cp->rstate) {
+                           (*cp->rcomp->decomp_free)(cp->rstate);
+                           cp->rstate = NULL;
+                       }
+                       if (sizeof (cp->memreq.comp_opts) < len) {
+                           printf("can't handle options for compressor %d (%d)\n", opt_data[0],
+                               opt_data[1]);
+                           cp->memreq.thread_status = ENOSR;
+                           cp->memreq.returned_mem = 0;
+                       }
+                       if (cp->memreq.thread_status == 0 && !cp->memreq.returned_mem) {
+                           bcopy(opt_data, cp->memreq.comp_opts, len);
+                           cp->memreq.cmd = PPPIO_RCOMP;
+                           cp->rcomp = *comp;
+                           error = cp->memreq.thread_status = EAGAIN;
+                           thread_wakeup((vm_offset_t)&cp->memreq.thread_status);
+                       } else {
+                           cp->rstate = cp->memreq.returned_mem;
+                           cp->memreq.returned_mem = 0;
+                           cp->memreq.thread_status = 0;
+                       }
+                   }
+#endif
                    break;
                }
            iop->ioc_count = 0;
@@ -314,6 +512,20 @@ ppp_comp_wput(q, mp)
            error = 0;
            break;
 
+       case PPPIO_DEBUG:
+           if (iop->ioc_count != sizeof(int))
+               break;
+           n = *(int *)mp->b_cont->b_rptr;
+           if (n == PPPDBG_LOG + PPPDBG_COMP) {
+               DPRINT1("ppp_comp%d: debug log enabled\n", cp->unit);
+               cp->flags |= DBGLOG;
+               error = 0;
+               iop->ioc_count = 0;
+           } else {
+               error = -1;
+           }
+           break;
+
        case PPPIO_LASTMOD:
            cp->flags |= LAST_MOD;
            error = 0;
@@ -370,7 +582,11 @@ ppp_comp_wsrv(q)
     cp = (comp_state_t *) q->q_ptr;
     while ((mp = getq(q)) != 0) {
        /* assert(mp->b_datap->db_type == M_DATA) */
-       if (!canputnext(q)) {
+#ifdef PRIOQ
+        if (!bcanputnext(q,mp->b_band)) {
+#else
+        if (!canputnext(q)) {
+#endif PRIOQ
            putbq(q, mp);
            return;
        }
@@ -392,9 +608,9 @@ ppp_comp_wsrv(q)
         * Make sure we've got enough data in the first mblk
         * and that we are its only user.
         */
-       if (proto = PPP_CCP)
+       if (proto == PPP_CCP)
            hlen = len;
-       else if (proto = PPP_IP)
+       else if (proto == PPP_IP)
            hlen = PPP_HDRLEN + MAX_IPHDR;
        else
            hlen = PPP_HDRLEN;
@@ -409,7 +625,6 @@ ppp_comp_wsrv(q)
                continue;
            }
        }
-       proto = PPP_PROTOCOL(mp->b_rptr);
 
        /*
         * Do VJ compression if requested.
@@ -446,6 +661,9 @@ ppp_comp_wsrv(q)
            (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len,
                                   (cp->flags & CCP_ISUP? cp->mtu: 0));
            if (cmp != NULL) {
+#ifdef PRIOQ
+               cmp->b_band=mp->b_band;
+#endif PRIOQ
                freemsg(mp);
                mp = cmp;
            }
@@ -684,14 +902,21 @@ ppp_comp_rsrv(q)
                 * First reset compressor if an input error has occurred.
                 */
                if (cp->stats.ppp_ierrors != cp->vj_last_ierrors) {
+                   if (cp->flags & DBGLOG)
+                       DPRINT1("ppp%d: resetting VJ\n", cp->unit);
                    vj_uncompress_err(&cp->vj_comp);
                    cp->vj_last_ierrors = cp->stats.ppp_ierrors;
                }
 
                vjlen = vj_uncompress_tcp(dp, np->b_wptr - dp, len,
                                          &cp->vj_comp, &iphdr, &iphlen);
-               if (vjlen < 0)
+               if (vjlen < 0) {
+                   if (cp->flags & DBGLOG)
+                       DPRINT2("ppp%d: vj_uncomp_tcp failed, pkt len %d\n",
+                               cp->unit, len);
+                   ++cp->vj_last_ierrors;  /* so we don't reset next time */
                    goto bad;
+               }
 
                /* drop ppp and vj headers off */
                if (mp != np) {
@@ -732,8 +957,14 @@ ppp_comp_rsrv(q)
                /*
                 * "Decompress" a VJ-uncompressed packet.
                 */
-               if (!vj_uncompress_uncomp(dp, &cp->vj_comp))
+               cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+               if (!vj_uncompress_uncomp(dp, hlen, &cp->vj_comp)) {
+                   if (cp->flags & DBGLOG)
+                       DPRINT2("ppp%d: vj_uncomp_uncomp failed, pkt len %d\n",
+                               cp->unit, len);
+                   ++cp->vj_last_ierrors;  /* don't need to reset next time */
                    goto bad;
+               }
                mp->b_rptr[3] = PPP_IP; /* fix up the PPP protocol field */
            }
        }
@@ -789,13 +1020,13 @@ ppp_comp_ccp(q, mp, rcvd)
                if (cp->xstate != NULL
                    && (*cp->xcomp->comp_init)
                        (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
-                        cp->unit, 0, 0))
+                        cp->unit, 0, ((cp->flags & DBGLOG) != 0)))
                    cp->flags |= CCP_COMP_RUN;
            } else {
                if (cp->rstate != NULL
                    && (*cp->rcomp->decomp_init)
                        (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
-                        cp->unit, 0, cp->mru, 0))
+                        cp->unit, 0, cp->mru, ((cp->flags & DBGLOG) != 0)))
                    cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
            }
        }
@@ -817,7 +1048,7 @@ ppp_comp_ccp(q, mp, rcvd)
     }
 }
 
-#if DEBUG
+#if 0
 dump_msg(mp)
     mblk_t *mp;
 {