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/05/10 01:38:47 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>
42 #include <sys/stream.h>
43 #include <sys/modctl.h>
47 #include <sys/sunddi.h>
48 #include <net/ppp_defs.h>
49 #include <net/ppp_str.h>
51 #define ALLOCATE(n) kmem_zalloc((n), KM_NOSLEEP)
52 #define FREE(p, n) kmem_free((p), (n))
54 #define PACKETPTR mblk_t *
55 #include <net/ppp-comp.h>
57 static int ppp_comp_open __P((queue_t *, dev_t *, int, int, cred_t *));
58 static int ppp_comp_close __P((queue_t *, int, cred_t *));
59 static int ppp_comp_rput __P((queue_t *, mblk_t *));
60 static int ppp_comp_wput __P((queue_t *, mblk_t *));
61 static void ppp_comp_ccp __P((queue_t *, mblk_t *, int));
63 static struct module_info minfo = {
64 0xbadf, "ppp_compress", 0, INFPSZ, 16384, 4096,
67 static struct qinit r_init = {
68 ppp_comp_rput, NULL, ppp_comp_open, ppp_comp_close,
72 static struct qinit w_init = {
73 ppp_comp_wput, NULL, NULL, NULL, NULL, &minfo, NULL
76 static struct streamtab ppp_compinfo = {
77 &r_init, &w_init, NULL, NULL
80 static struct fmodsw fsw = {
83 D_NEW | D_MP | D_MTQPAIR
86 extern struct mod_ops mod_strmodops;
88 static struct modlstrmod modlstrmod = {
90 "PPP compression module",
94 static struct modlinkage modlinkage = {
100 struct ppp_comp_state {
104 struct compressor *xcomp;
106 struct compressor *rcomp;
108 struct vjcompress vj_comp;
111 /* Bits in flags are as defined in pppio.h. */
112 #define CCP_ERR (CCP_ERROR | CCP_FATALERROR)
114 #define MAX_IPHDR 128 /* max TCP/IP header size */
115 #define MAX_VJHDR 20 /* max VJ compressed header size (?) */
118 * List of compressors we know about.
121 extern struct compressor ppp_bsd_compress;
123 struct compressor *ppp_compressors[] = {
131 * Entry points for modloading.
136 return mod_install(&modlinkage);
142 return mod_remove(&modlinkage);
149 return mod_info(&modlinkage, mip);
153 * STREAMS module entry points.
156 ppp_comp_open(q, dev, flag, sflag, credp)
162 struct ppp_comp_state *cp;
164 if (q->q_ptr == NULL) {
165 cp = (struct ppp_comp_state *) ALLOCATE(sizeof(struct ppp_comp_state));
168 OTHERQ(q)->q_ptr = q->q_ptr = cp;
181 struct ppp_comp_state *cp;
183 cp = (struct ppp_comp_state *) q->q_ptr;
185 if (cp->xstate != NULL)
186 (*cp->xcomp->comp_free)(cp->xstate);
187 if (cp->rstate != NULL)
188 (*cp->rcomp->decomp_free)(cp->rstate);
189 FREE(cp, sizeof(struct ppp_comp_state));
191 OTHERQ(q)->q_ptr = NULL;
202 struct ppp_comp_state *cp;
204 int error, len, proto, state;
205 struct ppp_option_data *odp;
206 struct compressor **comp;
207 struct ppp_comp_stats *pcp;
209 cp = (struct ppp_comp_state *) q->q_ptr;
210 switch (mp->b_datap->db_type) {
213 /* first find out what the protocol is */
214 if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN
215 && !pullupmsg(mp, PPP_HDRLEN)) {
216 freemsg(mp); /* give up on it */
219 proto = PPP_PROTOCOL(mp->b_rptr);
222 * Do VJ compression if requested.
224 if (proto == PPP_IP && (cp->flags & COMP_VJC)) {
226 if (len > MAX_IPHDR + PPP_HDRLEN)
227 len = MAX_IPHDR + PPP_HDRLEN;
228 if (mp->b_wptr - mp->b_rptr >= len || pullupmsg(mp, len)) {
229 ip = (struct ip *) (mp->b_rptr + PPP_HDRLEN);
230 if (ip->ip_p == IPPROTO_TCP) {
231 type = vj_compress_tcp(ip, len - PPP_HDRLEN,
232 cp->vj_comp, (cp->flags & COMP_VJCCID),
235 case TYPE_UNCOMPRESSED_TCP:
236 mp->b_rptr[3] = proto = PPP_VJC_UNCOMP;
238 case TYPE_COMPRESSED_TCP:
239 dp = vjhdr - PPP_HDRLEN;
240 dp[1] = mp->b_rptr[1]; /* copy control field */
241 dp[0] = mp->b_rptr[0]; /* copy address field */
242 dp[2] = 0; /* set protocol field */
243 dp[3] = proto = PPP_VJC_COMP;
252 * Do packet compression if enabled.
254 if (proto == PPP_CCP)
255 ppp_comp_ccp(q, mp, 0);
256 else if (proto != PPP_LCP && (cp->flags & CCP_COMP_RUN)
257 && cp->xstate != NULL) {
259 (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len,
260 (cp->flags & CCP_ISUP? cp->mtu: 0));
268 * Do address/control and protocol compression if enabled.
270 if (proto != PPP_LCP && (cp->flags & COMP_AC)) {
271 mp->b_rptr += 2; /* drop the address & ctrl fields */
272 if (proto < 0x100 && (cp->flags & COMP_PROT))
273 ++mp->b_rptr; /* drop the high protocol byte */
274 } else if (proto < 0x100 && (cp->flags & COMP_PROT)) {
275 /* shuffle up the address & ctrl fields */
276 mp->b_rptr[2] = mp->b_rptr[1];
277 mp->b_rptr[1] = mp->b_rptr[0];
285 iop = (struct iocblk *) mp->b_rptr;
287 switch (iop->ioc_cmd) {
291 if (iop->ioc_count != sizeof(int)) {
295 state = (*(int *) mp->b_cont->b_rptr) & (CCP_ISUP | CCP_ISOPEN);
296 if ((state & CCP_ISOPEN) == 0) {
297 if (cp->xstate != NULL) {
298 (*cp->xcomp->comp_free)(cp->xstate);
301 if (cp->rstate != NULL) {
302 (*cp->rcomp->decomp_free)(cp->rstate);
307 cp->flags = (cp->flags & ~CCP_ISUP) | state;
314 if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL) {
318 *(int *)mp->b_cont->b_wptr = cp->flags;
319 mp->b_cont->b_wptr += iop->ioc_count = sizeof(int);
324 if (iop->ioc_count != sizeof(struct ppp_option_data))
326 odp = (struct ppp_option_data *) mp->b_cont->b_rptr;
327 len = mp->b_cont->b_wptr - (unsigned char *) odp->opt_data;
328 if (len > odp->length)
330 if (odp->opt_data[1] < 2 || odp->opt_data[1] > len)
332 for (comp = ppp_compressors; *comp != NULL; ++comp)
333 if ((*comp)->compress_proto == odp->opt_data[0]) {
334 /* here's the handler! */
337 if (cp->xstate != NULL)
338 (*cp->xcomp->comp_free)(cp->xstate);
340 cp->xstate = (*comp)->comp_alloc(odp->opt_data, len);
341 if (cp->xstate == NULL)
344 if (cp->rstate != NULL)
345 (*cp->rcomp->decomp_free)(cp->rstate);
347 cp->rstate = (*comp)->decomp_alloc(odp->opt_data, len);
348 if (cp->rstate == NULL)
357 /* remember this value */
358 if (iop->ioc_count == sizeof(int)) {
359 cp->mru = *(int *) mp->b_cont->b_rptr;
367 else if (error == 0) {
368 mp->b_datap->db_type = M_IOCACK;
371 mp->b_datap->db_type = M_IOCNAK;
389 struct ppp_comp_state *cp;
391 cp = (struct ppp_comp_state *) q->q_ptr;
392 switch (mp->b_datap->db_type) {
396 * First do address/control and protocol "decompression".
399 if (len > PPP_HDRLEN)
401 if (mp->b_wptr - mp->b_rptr < len && !pullupmsg(mp, len)) {
407 if (PPP_ADDRESS(dp) == PPP_ALLSTATIONS && PPP_CONTROL(dp) == PPP_UI)
408 dp += 2; /* skip address/control */
410 if ((dp[0] & 1) == 0)
411 proto = *dp++ << 8; /* grab high byte of protocol */
412 proto += *dp++; /* grab low byte of protocol */
413 if (dp > mp->b_wptr) {
414 freemsg(mp); /* short/bogus packet */
417 if ((dp -= PPP_HDRLEN) < mp->b_datap->db_base) {
418 /* yucko, need a new message block */
420 np = allocb(PPP_HDRLEN, BPRI_MED);
428 mp->b_wptr = dp + PPP_HDRLEN;
431 dp[0] = PPP_ALLSTATIONS;
437 * Now see if we have a compressed packet to decompress,
438 * or a CCP packet to take notice of.
440 proto = PPP_PROTOCOL(mp->b_rptr);
441 if (proto == PPP_CCP)
442 ppp_comp_ccp(q, mp, 1);
443 else if (proto == PPP_COMP) {
444 if ((cp->flags & CCP_ISUP)
445 && (cp->flags & CCP_DECOMP_RUN) && cp->rstate
446 && (cp->flags & CCP_ERR) == 0) {
447 rv = (*cp->rcomp->decompress)(cp->rstate, mp, &dmp);
454 /* no error, but no packet returned */
459 cp->flags |= CCP_ERROR;
461 case DECOMP_FATALERROR:
462 cp->flags |= CCP_FATALERROR;
467 } else if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
468 (*cp->rcomp->incomp)(cp->rstate, mp);
472 * Now do VJ decompression.
485 * Handle a CCP packet being sent or received.
488 ppp_comp_ccp(q, mp, rcvd)
494 struct ppp_comp_state *cp;
498 if (len < PPP_HDRLEN + CCP_HDRLEN || !pullupmsg(mp, len))
500 cp = (struct ppp_comp_state *) q->q_ptr;
501 dp = mp->b_rptr + PPP_HDRLEN;
503 clen = CCP_LENGTH(dp);
507 switch (CCP_CODE(dp)) {
511 cp->flags &= ~CCP_ISUP;
515 if ((cp->flags & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN
516 && clen >= CCP_HDRLEN + CCP_OPT_MINLEN
517 && clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
519 if (cp->xstate != NULL
520 && (*cp->xcomp->comp_init)
521 (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
522 0, /* XXX: should be unit */ 0, 0))
523 cp->flags |= CCP_COMP_RUN;
525 if (cp->rstate != NULL
526 && (*cp->rcomp->decomp_init)
527 (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
528 0/* unit */, 0, cp->mru, 0))
529 cp->flags = (cp->flags & ~CCP_ERR)
536 if (cp->flags & CCP_ISUP) {
538 if (cp->xstate && (cp->flags & CCP_COMP_RUN))
539 (*cp->xcomp->comp_reset)(cp->xstate);
541 if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
542 (*cp->rcomp->decomp_reset)(cp->rstate);
543 cp->flags &= ~CCP_ERROR;