📄 ppp_comp.c
字号:
/* * ppp_comp.c - STREAMS module for kernel-level compression and CCP support. * * 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 HAS 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_comp.c,v 1.12 1999/09/15 23:49:06 masputra Exp $ *//* * This file is used under SVR4, Solaris 2, SunOS 4, and Digital UNIX. */#include <sys/types.h>#include <sys/param.h>#include <sys/errno.h>#include <sys/stream.h>#ifdef SVR4#include <sys/conf.h>#include <sys/cmn_err.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>#include <net/vjcompress.h>#define PACKETPTR mblk_t *#include <net/ppp-comp.h>MOD_OPEN_DECL(ppp_comp_open);MOD_CLOSE_DECL(ppp_comp_close);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 int msg_byte __P((mblk_t *, unsigned int));/* Extract byte i of message mp. */#define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \ msg_byte((mp), (i)))/* 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 0xbadfstatic struct module_info minfo = {#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 = { ppp_comp_rput, ppp_comp_rsrv, ppp_comp_open, ppp_comp_close, NULL, &minfo, NULL};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#endifstruct 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;#endiftypedef struct comp_state { int flags; int mru; int mtu; int unit; struct compressor *xcomp; void *xstate; struct compressor *rcomp; void *rstate; 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 (?) */#undef MIN /* just in case */#define MIN(a, b) ((a) < (b)? (a): (b))/* * List of compressors we know about. */#if DO_BSD_COMPRESSextern struct compressor ppp_bsd_compress;#endif#if DO_DEFLATEextern struct compressor ppp_deflate, ppp_deflate_draft;#endifstruct compressor *ppp_compressors[] = {#if DO_BSD_COMPRESS &ppp_bsd_compress,#endif#if DO_DEFLATE &ppp_deflate, &ppp_deflate_draft,#endif NULL};/* * STREAMS module entry points. */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)); if (cp == NULL) OPEN_ERROR(ENOSR); bzero((caddr_t)cp, sizeof(comp_state_t)); WR(q)->q_ptr = q->q_ptr = (caddr_t) cp; cp->mru = PPP_MRU; cp->mtu = PPP_MTU; cp->xstate = NULL; cp->rstate = NULL; vj_compress_init(&cp->vj_comp, -1);#ifdef __osf__ if (!(thread = kernel_thread_w_arg(first_task, ppp_comp_alloc, (void *)cp))) OPEN_ERROR(ENOSR); cp->thread = thread;#endif ++ppp_comp_count; qprocson(q); } return 0;}MOD_CLOSE(ppp_comp_close){ comp_state_t *cp; qprocsoff(q); cp = (comp_state_t *) q->q_ptr; if (cp != NULL) { if (cp->xstate != NULL) (*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; --ppp_comp_count; } 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 voidppp_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 intppp_comp_wput(q, mp) queue_t *q; mblk_t *mp;{ struct iocblk *iop; comp_state_t *cp; int error, len, n; int flags, mask; mblk_t *np; struct compressor **comp; struct ppp_stats *psp; struct ppp_comp_stats *csp; unsigned char *opt_data; int nxslots, nrslots; cp = (comp_state_t *) q->q_ptr; if (cp == 0) { DPRINT("cp == 0 in ppp_comp_wput\n"); freemsg(mp); return 0; } 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; if (mp->b_cont == 0) { DPRINT1("ppp_comp_wput/%d: PPPIO_CFLAGS b_cont = 0!\n", cp->unit); 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; if (mp->b_cont == 0) { DPRINT1("ppp_comp_wput/%d: PPPIO_VJINIT b_cont = 0!\n", cp->unit); 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->stats.ppp_ierrors; error = 0; iop->ioc_count = 0; break; case PPPIO_XCOMP: case PPPIO_RCOMP: if (iop->ioc_count <= 0) break; if (mp->b_cont == 0) { DPRINT1("ppp_comp_wput/%d: PPPIO_[XR]COMP b_cont = 0!\n", cp->unit); 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;#ifndef __osf__ if (iop->ioc_cmd == PPPIO_XCOMP) { /* 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) { (*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; break; case PPPIO_GETSTAT: if ((cp->flags & LAST_MOD) == 0) { error = -1; /* let the ppp_ahdl module handle it */ break; } np = allocb(sizeof(struct ppp_stats), BPRI_HI); if (np == 0) { error = ENOSR; break; } if (mp->b_cont != 0) freemsg(mp->b_cont); mp->b_cont = np; psp = (struct ppp_stats *) np->b_wptr; np->b_wptr += sizeof(struct ppp_stats); iop->ioc_count = sizeof(struct ppp_stats); psp->p = cp->stats; psp->vj = cp->vj_comp.stats; error = 0; break; case PPPIO_GETCSTAT: np = allocb(sizeof(struct ppp_comp_stats), BPRI_HI); if (np == 0) { error = ENOSR; break; } if (mp->b_cont != 0) freemsg(mp->b_cont); mp->b_cont = np; csp = (struct ppp_comp_stats *) np->b_wptr; np->b_wptr += sizeof(struct ppp_comp_stats); iop->ioc_count = sizeof(struct ppp_comp_stats); bzero((caddr_t)csp, sizeof(struct ppp_comp_stats)); if (cp->xstate != 0) (*cp->xcomp->comp_stat)(cp->xstate, &csp->c); if (cp->rstate != 0) (*cp->rcomp->decomp_stat)(cp->rstate, &csp->d); error = 0; break; case PPPIO_DEBUG: if (iop->ioc_count != sizeof(int)) break; if (mp->b_cont == 0) { DPRINT1("ppp_comp_wput/%d: PPPIO_DEBUG b_cont = 0!\n", cp->unit); 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; break; default: error = -1; break; } if (error < 0) putnext(q, mp); else if (error == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -