Fix a couple of errors pointed out by Andrew Benham <adsb@adsb.co.uk>.
[mpls-ppp.git] / aix4 / ppp_comp.c
blob2d0c440432c41c161303278c510cb238f0dfc291
1 /*
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
8 * are met:
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
16 * distribution.
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
23 * acknowledgment:
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>
42 #include <sys/user.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>
49 #include <net/if.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,
66 NULL, &minfo, NULL
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 {
78 int ccp_state;
79 int debug;
80 int mru;
81 struct compressor *xcomp;
82 void *xstate;
83 struct compressor *rcomp;
84 void *rstate;
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[] = {
97 #if DO_BSD_COMPRESS
98 &ppp_bsd_compress,
99 #endif
100 NULL
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)
109 int rc = 0;
111 switch (cmd) {
112 case CFG_INIT:
113 rc = str_install(STR_LOAD_MOD, &pppcompconf);
114 break;
115 case CFG_TERM:
116 rc = str_install(STR_UNLOAD_MOD, &pppcompconf);
117 break;
118 default:
119 rc = EINVAL;
120 break;
122 return(rc);
125 static int
126 ppp_comp_open(q, dev, flag, sflag)
127 queue_t *q;
128 dev_t dev;
129 int flag;
130 int 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);
137 if (cp == NULL) {
138 return(ENOSR);
140 bzero(cp, sizeof(struct ppp_comp_state));
141 OTHERQ(q)->q_ptr = q->q_ptr = (caddr_t) cp;
142 cp->ccp_state = 0;
143 cp->debug = 0;
144 cp->mru = PPP_MRU;
145 cp->xstate = NULL;
146 cp->rstate = NULL;
148 return 0;
151 static int
152 ppp_comp_close(q)
153 queue_t *q;
155 struct ppp_comp_state *cp;
157 cp = (struct ppp_comp_state *) q->q_ptr;
158 if (cp != NULL) {
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);
164 q->q_ptr = NULL;
165 OTHERQ(q)->q_ptr = NULL;
167 return 0;
170 static int
171 ppp_comp_wput(q, mp)
172 queue_t *q;
173 mblk_t *mp;
175 struct iocblk *iop;
176 struct ppp_comp_state *cp;
177 mblk_t *cmp;
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) {
186 case M_CTL:
187 switch (*(u_char *) mp->b_rptr) {
188 case IF_GET_CSTATS:
189 freemsg(mp);
190 mp = allocb(sizeof(struct ppp_comp_stats) + sizeof(u_long),
191 BPRI_HI);
192 if (mp != NULL) {
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);
203 qreply(q, mp);
205 break;
206 default:
207 putnext(q, mp);
209 break;
211 case M_DATA:
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) {
220 len = msgdsize(mp);
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 */
224 if (cmp != NULL) {
225 freemsg(mp);
226 mp = cmp;
230 putnext(q, mp);
231 break;
233 case M_IOCTL:
234 iop = (struct iocblk *) mp->b_rptr;
235 error = -1;
236 switch ((unsigned int)iop->ioc_cmd) {
238 case SIOCSIFCOMP:
239 /* set CCP state */
240 if ((iop->ioc_count != sizeof(int)) &&
241 (iop->ioc_count != TRANSPARENT)) {
242 error = EINVAL;
243 break;
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);
249 cp->xstate = NULL;
251 if (cp->rstate != NULL) {
252 (*cp->rcomp->decomp_free)(cp->rstate);
253 cp->rstate = NULL;
255 cp->ccp_state = 0;
256 } else {
257 cp->ccp_state = (cp->ccp_state & ~CCP_ISUP) | state;
259 if (cp->debug)
260 bsdlog(LOG_INFO, "SIOCSIFCOMP %x, state = %x\n",
261 *(int *) mp->b_cont->b_rptr, cp->ccp_state);
262 error = 0;
263 iop->ioc_count = 0;
264 break;
266 case SIOCGIFCOMP:
267 if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL) {
268 error = ENOSR;
269 break;
271 *(int *)mp->b_cont->b_wptr = cp->ccp_state;
272 mp->b_cont->b_wptr += iop->ioc_count = sizeof(int);
273 break;
275 case SIOCSCOMPRESS:
276 error = EINVAL;
277 if (iop->ioc_count != TRANSPARENT)
278 break;
279 odp = *((struct ppp_option_data **) mp->b_cont->b_rptr);
280 len = sizeof(odp->opt_data);
281 if (len > odp->length)
282 len = odp->length;
283 if (odp->opt_data[1] < 2 || odp->opt_data[1] > len)
284 break;
285 for (comp = ppp_compressors; *comp != NULL; ++comp)
286 if ((*comp)->compress_proto == odp->opt_data[0]) {
287 /* here's the handler! */
288 error = 0;
289 if (odp->transmit) {
290 if (cp->xstate != NULL)
291 (*cp->xcomp->comp_free)(cp->xstate);
292 cp->xcomp = *comp;
293 cp->xstate = (*comp)->comp_alloc(odp->opt_data, len);
294 if (cp->xstate == NULL)
295 error = ENOSR;
296 } else {
297 if (cp->rstate != NULL)
298 (*cp->rcomp->decomp_free)(cp->rstate);
299 cp->rcomp = *comp;
300 cp->rstate = (*comp)->decomp_alloc(odp->opt_data, len);
301 if (cp->rstate == NULL)
302 error = ENOSR;
304 if (cp->debug)
305 bsdlog(LOG_INFO, "SIOCSCOMPRESS %s len=%d\n",
306 odp->transmit? "xmit": "recv", len);
307 break;
309 iop->ioc_count = 0;
310 break;
312 case SIOCSIFDEBUG:
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;
318 break;
320 case SIOCSIFMRU:
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;
326 break;
330 if (error < 0)
331 putnext(q, mp);
332 else if (error == 0) {
333 mp->b_datap->db_type = M_IOCACK;
334 qreply(q, mp);
335 } else {
336 mp->b_datap->db_type = M_IOCNAK;
337 iop->ioc_count = 0;
338 qreply(q, mp);
340 break;
342 default:
343 putnext(q, mp);
347 static int
348 ppp_comp_rput(q, mp)
349 queue_t *q;
350 mblk_t *mp;
352 int proto, rv;
353 mblk_t *dmp;
354 struct ppp_comp_state *cp;
356 cp = (struct ppp_comp_state *) q->q_ptr;
357 switch (mp->b_datap->db_type) {
359 case M_DATA:
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);
372 if (dmp != NULL) {
373 freemsg(mp);
374 mp = dmp;
375 } else {
376 switch (rv) {
377 case DECOMP_OK:
378 /* no error, but no packet returned */
379 freemsg(mp);
380 mp = NULL;
381 break;
382 case DECOMP_ERROR:
383 cp->ccp_state |= CCP_ERROR;
384 break;
385 case DECOMP_FATALERROR:
386 cp->ccp_state |= CCP_FATALERROR;
387 break;
391 } else if (cp->rstate && (cp->ccp_state & CCP_DECOMP_RUN)) {
392 (*cp->rcomp->incomp)(cp->rstate, mp);
395 if (mp != NULL)
396 putnext(q, mp);
397 break;
399 default:
400 putnext(q, mp);
404 static void
405 ppp_comp_ccp(q, mp, rcvd)
406 queue_t *q;
407 mblk_t *mp;
408 int rcvd;
410 int len, clen;
411 struct ppp_comp_state *cp;
412 unsigned char *dp;
414 len = msgdsize(mp);
415 if (len < PPP_HDRLEN + CCP_HDRLEN || !pullupmsg(mp, len))
416 return;
417 cp = (struct ppp_comp_state *) q->q_ptr;
418 dp = mp->b_rptr + PPP_HDRLEN;
419 len -= PPP_HDRLEN;
420 clen = CCP_LENGTH(dp);
421 if (clen > len)
422 return;
423 if (cp->debug)
424 bsdlog(LOG_INFO, "CCP %s: code=%x len=%d\n", rcvd? "rcvd": "sent",
425 CCP_CODE(dp), clen);
427 switch (CCP_CODE(dp)) {
428 case CCP_CONFREQ:
429 case CCP_TERMREQ:
430 case CCP_TERMACK:
431 cp->ccp_state &= ~CCP_ISUP;
432 break;
434 case CCP_CONFACK:
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)) {
438 if (!rcvd) {
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,
443 cp->debug))
444 cp->ccp_state |= CCP_COMP_RUN;
445 } else {
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)
451 | CCP_DECOMP_RUN;
454 break;
456 case CCP_RESETACK:
457 if (cp->ccp_state & CCP_ISUP) {
458 if (!rcvd) {
459 if (cp->xstate && (cp->ccp_state & CCP_COMP_RUN))
460 (*cp->xcomp->comp_reset)(cp->xstate);
461 } else {
462 if (cp->rstate && (cp->ccp_state & CCP_DECOMP_RUN)) {
463 (*cp->rcomp->decomp_reset)(cp->rstate);
464 cp->ccp_state &= ~CCP_ERROR;
468 break;
471 if (cp->debug)
472 bsdlog(LOG_INFO, "ccp_state = %x\n", cp->ccp_state);