2 * ppp_comp.c - STREAMS module for kernel-level CCP support.
4 * Copyright (c) 1994 The Australian National University.
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
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
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,
27 * $Id: ppp_comp.c,v 1.1 1995/12/18 23:45:09 paulus Exp $
31 * This file is used under SunOS 4.x, and OSF/1 on DEC Alpha.
33 * Beware that under OSF/1, the ioctl constants (SIOC*) end up
34 * as 64-bit (long) values, so an ioctl constant should be cast to
35 * int (32 bits) before being compared with the ioc_cmd field of
36 * an iocblk structure.
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/errno.h>
43 #include <sys/stream.h>
44 #include <sys/stropts.h>
45 #include <sys/syslog.h>
46 #include <sys/socket.h>
48 #include <net/ppp_defs.h>
49 #include <net/ppp_str.h>
52 #include <kern/kalloc.h>
56 #define ALLOCATE(n) kalloc((n))
57 #define FREE(p, n) kfree((p), (n))
61 #include <sys/kmem_alloc.h>
62 #define ALLOCATE(n) kmem_alloc((n), KMEM_NOSLEEP)
63 #define FREE(p, n) kmem_free((p), (n))
66 #define PACKETPTR mblk_t *
67 #include <net/ppp-comp.h>
69 static int ppp_comp_open(), ppp_comp_close();
70 static int ppp_comp_rput(), ppp_comp_wput();
71 static void ppp_comp_ccp();
73 static struct module_info minfo = {
74 0xbadf, "ppp_compress", 0, INFPSZ, 16384, 4096,
77 static struct qinit r_init = {
78 ppp_comp_rput, NULL, ppp_comp_open, ppp_comp_close,
82 static struct qinit w_init = {
83 ppp_comp_wput, NULL, NULL, NULL, NULL, &minfo, NULL
86 struct streamtab ppp_compinfo = {
87 &r_init, &w_init, NULL, NULL
90 struct ppp_comp_state {
94 struct compressor *xcomp;
96 struct compressor *rcomp;
100 /* Bits in ccp_state are as defined in ppp_str.h. */
101 #define CCP_ERR (CCP_ERROR | CCP_FATALERROR)
104 * List of compressors we know about.
107 extern struct compressor ppp_bsd_compress;
109 struct compressor *ppp_compressors[] = {
117 ppp_comp_open(q, dev, flag, sflag)
123 struct ppp_comp_state *cp;
125 if (q->q_ptr == NULL) {
126 cp = (struct ppp_comp_state *) ALLOCATE(sizeof(struct ppp_comp_state));
131 OTHERQ(q)->q_ptr = q->q_ptr = (caddr_t) cp;
145 struct ppp_comp_state *cp;
147 cp = (struct ppp_comp_state *) q->q_ptr;
149 if (cp->xstate != NULL)
150 (*cp->xcomp->comp_free)(cp->xstate);
151 if (cp->rstate != NULL)
152 (*cp->rcomp->decomp_free)(cp->rstate);
153 FREE(cp, sizeof(struct ppp_comp_state));
155 OTHERQ(q)->q_ptr = NULL;
166 struct ppp_comp_state *cp;
168 int error, len, proto, state;
169 struct ppp_option_data *odp;
170 struct compressor **comp;
171 struct ppp_comp_stats *pcp;
173 cp = (struct ppp_comp_state *) q->q_ptr;
174 switch (mp->b_datap->db_type) {
177 switch (*(u_char *) mp->b_rptr) {
180 mp = allocb(sizeof(struct ppp_comp_stats) + sizeof(u_long),
183 mp->b_datap->db_type = M_CTL;
184 *(u_char *) mp->b_wptr = IF_CSTATS;
185 mp->b_wptr += sizeof(u_long); /* should be enough alignment */
186 pcp = (struct ppp_comp_stats *) mp->b_wptr;
187 mp->b_wptr += sizeof(struct ppp_comp_stats);
188 bzero(pcp, sizeof(struct ppp_comp_stats));
189 if (cp->xstate != NULL)
190 (*cp->xcomp->comp_stat)(cp->xstate, &pcp->c);
191 if (cp->rstate != NULL)
192 (*cp->rcomp->decomp_stat)(cp->rstate, &pcp->d);
202 /* first find out what the protocol is */
203 if (mp->b_wptr - mp->b_rptr >= PPP_HDRLEN
204 || pullupmsg(mp, PPP_HDRLEN)) {
205 proto = PPP_PROTOCOL(mp->b_rptr);
206 if (proto == PPP_CCP)
207 ppp_comp_ccp(q, mp, 0);
208 else if (proto != PPP_LCP && (cp->ccp_state & CCP_COMP_RUN)
209 && cp->xstate != NULL) {
211 (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len,
212 (cp->ccp_state & CCP_ISUP? len: 0));
213 /* XXX we really want the MTU here, not len */
224 iop = (struct iocblk *) mp->b_rptr;
226 switch (iop->ioc_cmd) {
230 if (iop->ioc_count != sizeof(int)) {
234 state = (*(int *) mp->b_cont->b_rptr) & (CCP_ISUP | CCP_ISOPEN);
235 if ((state & CCP_ISOPEN) == 0) {
236 if (cp->xstate != NULL) {
237 (*cp->xcomp->comp_free)(cp->xstate);
240 if (cp->rstate != NULL) {
241 (*cp->rcomp->decomp_free)(cp->rstate);
246 cp->ccp_state = (cp->ccp_state & ~CCP_ISUP) | state;
249 log(LOG_DEBUG, "SIOCSIFCOMP %x, state = %x\n",
250 *(int *) mp->b_cont->b_rptr, cp->ccp_state);
256 if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL) {
260 *(int *)mp->b_cont->b_wptr = cp->ccp_state;
261 mp->b_cont->b_wptr += iop->ioc_count = sizeof(int);
267 if (iop->ioc_count != sizeof(struct ppp_option_data))
269 odp = (struct ppp_option_data *) mp->b_cont->b_rptr;
270 len = mp->b_cont->b_wptr - (unsigned char *) odp->opt_data;
271 if (len > odp->length)
273 if (odp->opt_data[1] < 2 || odp->opt_data[1] > len)
275 for (comp = ppp_compressors; *comp != NULL; ++comp)
276 if ((*comp)->compress_proto == odp->opt_data[0]) {
277 /* here's the handler! */
280 if (cp->xstate != NULL)
281 (*cp->xcomp->comp_free)(cp->xstate);
283 cp->xstate = (*comp)->comp_alloc(odp->opt_data, len);
284 if (cp->xstate == NULL)
287 if (cp->rstate != NULL)
288 (*cp->rcomp->decomp_free)(cp->rstate);
290 cp->rstate = (*comp)->decomp_alloc(odp->opt_data, len);
291 if (cp->rstate == NULL)
295 log(LOG_DEBUG, "SIOCSCOMPRESS %s len=%d\n",
296 odp->transmit? "xmit": "recv", len);
303 /* set our debug flag from this */
304 if (iop->ioc_count == sizeof(int)) {
305 cp->debug = *(int *) mp->b_cont->b_rptr & 1;
310 /* remember this value */
311 if (iop->ioc_count == sizeof(int)) {
312 cp->mru = *(int *) mp->b_cont->b_rptr;
320 else if (error == 0) {
321 mp->b_datap->db_type = M_IOCACK;
324 mp->b_datap->db_type = M_IOCNAK;
342 struct ppp_comp_state *cp;
344 cp = (struct ppp_comp_state *) q->q_ptr;
345 switch (mp->b_datap->db_type) {
348 /* possibly a compressed packet to decompress,
349 or a CCP packet to take notice of. */
350 if (mp->b_wptr - mp->b_rptr >= PPP_HDRLEN
351 || pullupmsg(mp, PPP_HDRLEN)) {
352 proto = PPP_PROTOCOL(mp->b_rptr);
353 if (proto == PPP_CCP)
354 ppp_comp_ccp(q, mp, 1);
355 else if (proto == PPP_COMP) {
356 if ((cp->ccp_state & CCP_ISUP)
357 && (cp->ccp_state & CCP_DECOMP_RUN) && cp->rstate
358 && (cp->ccp_state & CCP_ERR) == 0) {
359 rv = (*cp->rcomp->decompress)(cp->rstate, mp, &dmp);
364 /* if mp is now NULL, then there was no error,
365 but no packet returned either. */
368 cp->ccp_state |= CCP_ERROR;
370 case DECOMP_FATALERROR:
371 cp->ccp_state |= CCP_FATALERROR;
375 } else if (cp->rstate && (cp->ccp_state & CCP_DECOMP_RUN)) {
376 (*cp->rcomp->incomp)(cp->rstate, mp);
389 ppp_comp_ccp(q, mp, rcvd)
395 struct ppp_comp_state *cp;
399 if (len < PPP_HDRLEN + CCP_HDRLEN || !pullupmsg(mp, len))
401 cp = (struct ppp_comp_state *) q->q_ptr;
402 dp = mp->b_rptr + PPP_HDRLEN;
404 clen = CCP_LENGTH(dp);
408 log(LOG_DEBUG, "CCP %s: code=%x len=%d\n", rcvd? "rcvd": "sent",
411 switch (CCP_CODE(dp)) {
415 cp->ccp_state &= ~CCP_ISUP;
419 if ((cp->ccp_state & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN
420 && clen >= CCP_HDRLEN + CCP_OPT_MINLEN
421 && clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
423 if (cp->xstate != NULL
424 && (*cp->xcomp->comp_init)
425 (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
426 0, /* XXX: should be unit */ 0,
428 cp->ccp_state |= CCP_COMP_RUN;
430 if (cp->rstate != NULL
431 && (*cp->rcomp->decomp_init)
432 (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
433 0/* unit */, 0, cp->mru, cp->debug))
434 cp->ccp_state = (cp->ccp_state & ~CCP_ERR)
441 if (cp->ccp_state & CCP_ISUP) {
443 if (cp->xstate && (cp->ccp_state & CCP_COMP_RUN))
444 (*cp->xcomp->comp_reset)(cp->xstate);
446 if (cp->rstate && (cp->ccp_state & CCP_DECOMP_RUN)) {
447 (*cp->rcomp->decomp_reset)(cp->rstate);
448 cp->ccp_state &= ~CCP_ERROR;
456 log(LOG_DEBUG, "ccp_state = %x\n", cp->ccp_state);