2 * ppp_comp.c - STREAMS module for kernel-level CCP support.
4 * Copyright (c) 1994 Paul Mackerras. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
18 * 3. The name(s) of the authors of this software must not be used to
19 * endorse or promote products derived from this software without
20 * prior written permission.
22 * 4. Redistributions of any form whatsoever must retain the following
24 * "This product includes software developed by Paul Mackerras
25 * <paulus@samba.org>".
27 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
28 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
29 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
30 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
31 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
32 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
33 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 * $Id: ppp_comp.c,v 1.7 2002/12/06 09:49:15 paulus Exp $
38 #include <net/net_globals.h>
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/strconf.h>
46 #include <sys/device.h>
47 #include <sys/syslog.h>
48 #include <sys/socket.h>
50 #include <net/ppp_defs.h>
51 #include <net/ppp_str.h>
53 #define PACKETPTR mblk_t *
54 #include <net/ppp-comp.h>
56 static int ppp_comp_open(), ppp_comp_close();
57 static int ppp_comp_rput(), ppp_comp_wput();
58 static void ppp_comp_ccp();
60 static struct module_info minfo
= {
61 0xbadf, "ppp_compress", 0, INFPSZ
, 16384, 4096,
64 static struct qinit r_init
= {
65 ppp_comp_rput
, NULL
, ppp_comp_open
, ppp_comp_close
,
69 static struct qinit w_init
= {
70 ppp_comp_wput
, NULL
, NULL
, NULL
, NULL
, &minfo
, NULL
73 struct streamtab ppp_compinfo
= {
74 &r_init
, &w_init
, NULL
, NULL
77 struct ppp_comp_state
{
81 struct compressor
*xcomp
;
83 struct compressor
*rcomp
;
87 /* Bits in ccp_state are as defined in ppp_str.h. */
88 #define CCP_ERR (CCP_ERROR | CCP_FATALERROR)
91 * List of compressors we know about.
94 extern struct compressor ppp_bsd_compress
;
96 struct compressor
*ppp_compressors
[] = {
103 strconf_t pppcompconf
= {
104 "pppcomp", &ppp_compinfo
, STR_NEW_OPEN
, 0, SQLVL_DEFAULT
, (void *) 0
107 int pppcomp_load(int cmd
, struct uio
*uiop
)
113 rc
= str_install(STR_LOAD_MOD
, &pppcompconf
);
116 rc
= str_install(STR_UNLOAD_MOD
, &pppcompconf
);
126 ppp_comp_open(q
, dev
, flag
, sflag
)
132 struct ppp_comp_state
*cp
;
134 if (q
->q_ptr
== NULL
) {
135 cp
= (struct ppp_comp_state
*)
136 xmalloc(sizeof(struct ppp_comp_state
), 0, pinned_heap
);
140 bzero(cp
, sizeof(struct ppp_comp_state
));
141 OTHERQ(q
)->q_ptr
= q
->q_ptr
= (caddr_t
) cp
;
155 struct ppp_comp_state
*cp
;
157 cp
= (struct ppp_comp_state
*) q
->q_ptr
;
159 if (cp
->xstate
!= NULL
)
160 (*cp
->xcomp
->comp_free
)(cp
->xstate
);
161 if (cp
->rstate
!= NULL
)
162 (*cp
->rcomp
->decomp_free
)(cp
->rstate
);
163 xmfree(cp
, pinned_heap
);
165 OTHERQ(q
)->q_ptr
= NULL
;
176 struct ppp_comp_state
*cp
;
178 int error
, len
, proto
, state
;
179 struct ppp_option_data
*odp
;
180 struct compressor
**comp
;
181 struct ppp_comp_stats
*pcp
;
183 cp
= (struct ppp_comp_state
*) q
->q_ptr
;
184 switch (mp
->b_datap
->db_type
) {
187 switch (*(u_char
*) mp
->b_rptr
) {
190 mp
= allocb(sizeof(struct ppp_comp_stats
) + sizeof(u_long
),
193 mp
->b_datap
->db_type
= M_CTL
;
194 *(u_char
*) mp
->b_wptr
= IF_CSTATS
;
195 mp
->b_wptr
+= sizeof(u_long
); /* should be enough alignment */
196 pcp
= (struct ppp_comp_stats
*) mp
->b_wptr
;
197 mp
->b_wptr
+= sizeof(struct ppp_comp_stats
);
198 bzero(pcp
, sizeof(struct ppp_comp_stats
));
199 if (cp
->xstate
!= NULL
)
200 (*cp
->xcomp
->comp_stat
)(cp
->xstate
, &pcp
->c
);
201 if (cp
->rstate
!= NULL
)
202 (*cp
->rcomp
->decomp_stat
)(cp
->rstate
, &pcp
->d
);
212 /* first find out what the protocol is */
213 if (mp
->b_wptr
- mp
->b_rptr
>= PPP_HDRLEN
214 || pullupmsg(mp
, PPP_HDRLEN
)) {
215 proto
= PPP_PROTOCOL(mp
->b_rptr
);
216 if (proto
== PPP_CCP
)
217 ppp_comp_ccp(q
, mp
, 0);
218 else if (proto
!= PPP_LCP
&& (cp
->ccp_state
& CCP_COMP_RUN
)
219 && cp
->xstate
!= NULL
) {
221 (*cp
->xcomp
->compress
)(cp
->xstate
, &cmp
, mp
, len
,
222 (cp
->ccp_state
& CCP_ISUP
? len
: 0));
223 /* XXX we really want the MTU here, not len */
234 iop
= (struct iocblk
*) mp
->b_rptr
;
236 switch ((unsigned int)iop
->ioc_cmd
) {
240 if ((iop
->ioc_count
!= sizeof(int)) &&
241 (iop
->ioc_count
!= TRANSPARENT
)) {
245 state
= (*(int *) mp
->b_cont
->b_rptr
) & (CCP_ISUP
| CCP_ISOPEN
);
246 if ((state
& CCP_ISOPEN
) == 0) {
247 if (cp
->xstate
!= NULL
) {
248 (*cp
->xcomp
->comp_free
)(cp
->xstate
);
251 if (cp
->rstate
!= NULL
) {
252 (*cp
->rcomp
->decomp_free
)(cp
->rstate
);
257 cp
->ccp_state
= (cp
->ccp_state
& ~CCP_ISUP
) | state
;
260 bsdlog(LOG_INFO
, "SIOCSIFCOMP %x, state = %x\n",
261 *(int *) mp
->b_cont
->b_rptr
, cp
->ccp_state
);
267 if ((mp
->b_cont
= allocb(sizeof(int), BPRI_MED
)) == NULL
) {
271 *(int *)mp
->b_cont
->b_wptr
= cp
->ccp_state
;
272 mp
->b_cont
->b_wptr
+= iop
->ioc_count
= sizeof(int);
277 if (iop
->ioc_count
!= TRANSPARENT
)
279 odp
= *((struct ppp_option_data
**) mp
->b_cont
->b_rptr
);
280 len
= sizeof(odp
->opt_data
);
281 if (len
> odp
->length
)
283 if (odp
->opt_data
[1] < 2 || odp
->opt_data
[1] > len
)
285 for (comp
= ppp_compressors
; *comp
!= NULL
; ++comp
)
286 if ((*comp
)->compress_proto
== odp
->opt_data
[0]) {
287 /* here's the handler! */
290 if (cp
->xstate
!= NULL
)
291 (*cp
->xcomp
->comp_free
)(cp
->xstate
);
293 cp
->xstate
= (*comp
)->comp_alloc(odp
->opt_data
, len
);
294 if (cp
->xstate
== NULL
)
297 if (cp
->rstate
!= NULL
)
298 (*cp
->rcomp
->decomp_free
)(cp
->rstate
);
300 cp
->rstate
= (*comp
)->decomp_alloc(odp
->opt_data
, len
);
301 if (cp
->rstate
== NULL
)
305 bsdlog(LOG_INFO
, "SIOCSCOMPRESS %s len=%d\n",
306 odp
->transmit
? "xmit": "recv", len
);
313 /* set our debug flag from this */
314 if ((iop
->ioc_count
== TRANSPARENT
) ||
315 (iop
->ioc_count
== sizeof(int))) {
316 cp
->debug
= *(int *) mp
->b_cont
->b_rptr
& 1;
321 /* remember this value */
322 if ((iop
->ioc_count
== TRANSPARENT
) ||
323 (iop
->ioc_count
== sizeof(int))) {
324 cp
->mru
= *(int *) mp
->b_cont
->b_rptr
;
332 else if (error
== 0) {
333 mp
->b_datap
->db_type
= M_IOCACK
;
336 mp
->b_datap
->db_type
= M_IOCNAK
;
354 struct ppp_comp_state
*cp
;
356 cp
= (struct ppp_comp_state
*) q
->q_ptr
;
357 switch (mp
->b_datap
->db_type
) {
360 /* possibly a compressed packet to decompress,
361 or a CCP packet to take notice of. */
362 if (mp
->b_wptr
- mp
->b_rptr
>= PPP_HDRLEN
363 || pullupmsg(mp
, PPP_HDRLEN
)) {
364 proto
= PPP_PROTOCOL(mp
->b_rptr
);
365 if (proto
== PPP_CCP
)
366 ppp_comp_ccp(q
, mp
, 1);
367 else if (proto
== PPP_COMP
) {
368 if ((cp
->ccp_state
& CCP_ISUP
)
369 && (cp
->ccp_state
& CCP_DECOMP_RUN
) && cp
->rstate
370 && (cp
->ccp_state
& CCP_ERR
) == 0) {
371 rv
= (*cp
->rcomp
->decompress
)(cp
->rstate
, mp
, &dmp
);
378 /* no error, but no packet returned */
383 cp
->ccp_state
|= CCP_ERROR
;
385 case DECOMP_FATALERROR
:
386 cp
->ccp_state
|= CCP_FATALERROR
;
391 } else if (cp
->rstate
&& (cp
->ccp_state
& CCP_DECOMP_RUN
)) {
392 (*cp
->rcomp
->incomp
)(cp
->rstate
, mp
);
405 ppp_comp_ccp(q
, mp
, rcvd
)
411 struct ppp_comp_state
*cp
;
415 if (len
< PPP_HDRLEN
+ CCP_HDRLEN
|| !pullupmsg(mp
, len
))
417 cp
= (struct ppp_comp_state
*) q
->q_ptr
;
418 dp
= mp
->b_rptr
+ PPP_HDRLEN
;
420 clen
= CCP_LENGTH(dp
);
424 bsdlog(LOG_INFO
, "CCP %s: code=%x len=%d\n", rcvd
? "rcvd": "sent",
427 switch (CCP_CODE(dp
)) {
431 cp
->ccp_state
&= ~CCP_ISUP
;
435 if ((cp
->ccp_state
& (CCP_ISOPEN
| CCP_ISUP
)) == CCP_ISOPEN
436 && clen
>= CCP_HDRLEN
+ CCP_OPT_MINLEN
437 && clen
>= CCP_HDRLEN
+ CCP_OPT_LENGTH(dp
+ CCP_HDRLEN
)) {
439 if (cp
->xstate
!= NULL
440 && (*cp
->xcomp
->comp_init
)
441 (cp
->xstate
, dp
+ CCP_HDRLEN
, clen
- CCP_HDRLEN
,
442 0, /* XXX: should be unit */ 0,
444 cp
->ccp_state
|= CCP_COMP_RUN
;
446 if (cp
->rstate
!= NULL
447 && (*cp
->rcomp
->decomp_init
)
448 (cp
->rstate
, dp
+ CCP_HDRLEN
, clen
- CCP_HDRLEN
,
449 0/* unit */, 0, cp
->mru
, cp
->debug
))
450 cp
->ccp_state
= (cp
->ccp_state
& ~CCP_ERR
)
457 if (cp
->ccp_state
& CCP_ISUP
) {
459 if (cp
->xstate
&& (cp
->ccp_state
& CCP_COMP_RUN
))
460 (*cp
->xcomp
->comp_reset
)(cp
->xstate
);
462 if (cp
->rstate
&& (cp
->ccp_state
& CCP_DECOMP_RUN
)) {
463 (*cp
->rcomp
->decomp_reset
)(cp
->rstate
);
464 cp
->ccp_state
&= ~CCP_ERROR
;
472 bsdlog(LOG_INFO
, "ccp_state = %x\n", cp
->ccp_state
);