Rest of IPV6 merge which got lost somehow, plus some minor fixes.
[mpls-ppp.git] / aix4 / ppp_comp.c
blob7032d9af1b25c4ef3c092cc991b081aa82819eb7
1 /*
2 * ppp_comp.c - STREAMS module for kernel-level CCP support.
4 * Copyright (c) 1994 The Australian National University.
5 * All rights reserved.
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
12 * any purpose.
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
18 * OF SUCH DAMAGE.
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,
25 * OR MODIFICATIONS.
27 * $Id: ppp_comp.c,v 1.6 1995/06/23 01:42:54 paulus Exp $
30 #include <net/net_globals.h>
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/errno.h>
34 #include <sys/user.h>
35 #include <sys/stream.h>
36 #include <sys/stropts.h>
37 #include <sys/strconf.h>
38 #include <sys/device.h>
39 #include <sys/syslog.h>
40 #include <sys/socket.h>
41 #include <net/if.h>
42 #include <net/ppp_defs.h>
43 #include <net/ppp_str.h>
45 #define PACKETPTR mblk_t *
46 #include <net/ppp-comp.h>
48 static int ppp_comp_open(), ppp_comp_close();
49 static int ppp_comp_rput(), ppp_comp_wput();
50 static void ppp_comp_ccp();
52 static struct module_info minfo = {
53 0xbadf, "ppp_compress", 0, INFPSZ, 16384, 4096,
56 static struct qinit r_init = {
57 ppp_comp_rput, NULL, ppp_comp_open, ppp_comp_close,
58 NULL, &minfo, NULL
61 static struct qinit w_init = {
62 ppp_comp_wput, NULL, NULL, NULL, NULL, &minfo, NULL
65 struct streamtab ppp_compinfo = {
66 &r_init, &w_init, NULL, NULL
69 struct ppp_comp_state {
70 int ccp_state;
71 int debug;
72 int mru;
73 struct compressor *xcomp;
74 void *xstate;
75 struct compressor *rcomp;
76 void *rstate;
79 /* Bits in ccp_state are as defined in ppp_str.h. */
80 #define CCP_ERR (CCP_ERROR | CCP_FATALERROR)
83 * List of compressors we know about.
86 extern struct compressor ppp_bsd_compress;
88 struct compressor *ppp_compressors[] = {
89 #if DO_BSD_COMPRESS
90 &ppp_bsd_compress,
91 #endif
92 NULL
95 strconf_t pppcompconf = {
96 "pppcomp", &ppp_compinfo, STR_NEW_OPEN, 0, SQLVL_DEFAULT, (void *) 0
99 int pppcomp_load(int cmd, struct uio *uiop)
101 int rc = 0;
103 switch (cmd) {
104 case CFG_INIT:
105 rc = str_install(STR_LOAD_MOD, &pppcompconf);
106 break;
107 case CFG_TERM:
108 rc = str_install(STR_UNLOAD_MOD, &pppcompconf);
109 break;
110 default:
111 rc = EINVAL;
112 break;
114 return(rc);
117 static int
118 ppp_comp_open(q, dev, flag, sflag)
119 queue_t *q;
120 dev_t dev;
121 int flag;
122 int sflag;
124 struct ppp_comp_state *cp;
126 if (q->q_ptr == NULL) {
127 cp = (struct ppp_comp_state *)
128 xmalloc(sizeof(struct ppp_comp_state), 0, pinned_heap);
129 if (cp == NULL) {
130 return(ENOSR);
132 bzero(cp, sizeof(struct ppp_comp_state));
133 OTHERQ(q)->q_ptr = q->q_ptr = (caddr_t) cp;
134 cp->ccp_state = 0;
135 cp->debug = 0;
136 cp->mru = PPP_MRU;
137 cp->xstate = NULL;
138 cp->rstate = NULL;
140 return 0;
143 static int
144 ppp_comp_close(q)
145 queue_t *q;
147 struct ppp_comp_state *cp;
149 cp = (struct ppp_comp_state *) q->q_ptr;
150 if (cp != NULL) {
151 if (cp->xstate != NULL)
152 (*cp->xcomp->comp_free)(cp->xstate);
153 if (cp->rstate != NULL)
154 (*cp->rcomp->decomp_free)(cp->rstate);
155 xmfree(cp, pinned_heap);
156 q->q_ptr = NULL;
157 OTHERQ(q)->q_ptr = NULL;
159 return 0;
162 static int
163 ppp_comp_wput(q, mp)
164 queue_t *q;
165 mblk_t *mp;
167 struct iocblk *iop;
168 struct ppp_comp_state *cp;
169 mblk_t *cmp;
170 int error, len, proto, state;
171 struct ppp_option_data *odp;
172 struct compressor **comp;
173 struct ppp_comp_stats *pcp;
175 cp = (struct ppp_comp_state *) q->q_ptr;
176 switch (mp->b_datap->db_type) {
178 case M_CTL:
179 switch (*(u_char *) mp->b_rptr) {
180 case IF_GET_CSTATS:
181 freemsg(mp);
182 mp = allocb(sizeof(struct ppp_comp_stats) + sizeof(u_long),
183 BPRI_HI);
184 if (mp != NULL) {
185 mp->b_datap->db_type = M_CTL;
186 *(u_char *) mp->b_wptr = IF_CSTATS;
187 mp->b_wptr += sizeof(u_long); /* should be enough alignment */
188 pcp = (struct ppp_comp_stats *) mp->b_wptr;
189 mp->b_wptr += sizeof(struct ppp_comp_stats);
190 bzero(pcp, sizeof(struct ppp_comp_stats));
191 if (cp->xstate != NULL)
192 (*cp->xcomp->comp_stat)(cp->xstate, &pcp->c);
193 if (cp->rstate != NULL)
194 (*cp->rcomp->decomp_stat)(cp->rstate, &pcp->d);
195 qreply(q, mp);
197 break;
198 default:
199 putnext(q, mp);
201 break;
203 case M_DATA:
204 /* first find out what the protocol is */
205 if (mp->b_wptr - mp->b_rptr >= PPP_HDRLEN
206 || pullupmsg(mp, PPP_HDRLEN)) {
207 proto = PPP_PROTOCOL(mp->b_rptr);
208 if (proto == PPP_CCP)
209 ppp_comp_ccp(q, mp, 0);
210 else if (proto != PPP_LCP && (cp->ccp_state & CCP_COMP_RUN)
211 && cp->xstate != NULL) {
212 len = msgdsize(mp);
213 (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len,
214 (cp->ccp_state & CCP_ISUP? len: 0));
215 /* XXX we really want the MTU here, not len */
216 if (cmp != NULL) {
217 freemsg(mp);
218 mp = cmp;
222 putnext(q, mp);
223 break;
225 case M_IOCTL:
226 iop = (struct iocblk *) mp->b_rptr;
227 error = -1;
228 switch ((unsigned int)iop->ioc_cmd) {
230 case SIOCSIFCOMP:
231 /* set CCP state */
232 if ((iop->ioc_count != sizeof(int)) &&
233 (iop->ioc_count != TRANSPARENT)) {
234 error = EINVAL;
235 break;
237 state = (*(int *) mp->b_cont->b_rptr) & (CCP_ISUP | CCP_ISOPEN);
238 if ((state & CCP_ISOPEN) == 0) {
239 if (cp->xstate != NULL) {
240 (*cp->xcomp->comp_free)(cp->xstate);
241 cp->xstate = NULL;
243 if (cp->rstate != NULL) {
244 (*cp->rcomp->decomp_free)(cp->rstate);
245 cp->rstate = NULL;
247 cp->ccp_state = 0;
248 } else {
249 cp->ccp_state = (cp->ccp_state & ~CCP_ISUP) | state;
251 if (cp->debug)
252 bsdlog(LOG_INFO, "SIOCSIFCOMP %x, state = %x\n",
253 *(int *) mp->b_cont->b_rptr, cp->ccp_state);
254 error = 0;
255 iop->ioc_count = 0;
256 break;
258 case SIOCGIFCOMP:
259 if ((mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL) {
260 error = ENOSR;
261 break;
263 *(int *)mp->b_cont->b_wptr = cp->ccp_state;
264 mp->b_cont->b_wptr += iop->ioc_count = sizeof(int);
265 break;
267 case SIOCSCOMPRESS:
268 error = EINVAL;
269 if (iop->ioc_count != TRANSPARENT)
270 break;
271 odp = *((struct ppp_option_data **) mp->b_cont->b_rptr);
272 len = sizeof(odp->opt_data);
273 if (len > odp->length)
274 len = odp->length;
275 if (odp->opt_data[1] < 2 || odp->opt_data[1] > len)
276 break;
277 for (comp = ppp_compressors; *comp != NULL; ++comp)
278 if ((*comp)->compress_proto == odp->opt_data[0]) {
279 /* here's the handler! */
280 error = 0;
281 if (odp->transmit) {
282 if (cp->xstate != NULL)
283 (*cp->xcomp->comp_free)(cp->xstate);
284 cp->xcomp = *comp;
285 cp->xstate = (*comp)->comp_alloc(odp->opt_data, len);
286 if (cp->xstate == NULL)
287 error = ENOSR;
288 } else {
289 if (cp->rstate != NULL)
290 (*cp->rcomp->decomp_free)(cp->rstate);
291 cp->rcomp = *comp;
292 cp->rstate = (*comp)->decomp_alloc(odp->opt_data, len);
293 if (cp->rstate == NULL)
294 error = ENOSR;
296 if (cp->debug)
297 bsdlog(LOG_INFO, "SIOCSCOMPRESS %s len=%d\n",
298 odp->transmit? "xmit": "recv", len);
299 break;
301 iop->ioc_count = 0;
302 break;
304 case SIOCSIFDEBUG:
305 /* set our debug flag from this */
306 if ((iop->ioc_count == TRANSPARENT) ||
307 (iop->ioc_count == sizeof(int))) {
308 cp->debug = *(int *) mp->b_cont->b_rptr & 1;
310 break;
312 case SIOCSIFMRU:
313 /* remember this value */
314 if ((iop->ioc_count == TRANSPARENT) ||
315 (iop->ioc_count == sizeof(int))) {
316 cp->mru = *(int *) mp->b_cont->b_rptr;
318 break;
322 if (error < 0)
323 putnext(q, mp);
324 else if (error == 0) {
325 mp->b_datap->db_type = M_IOCACK;
326 qreply(q, mp);
327 } else {
328 mp->b_datap->db_type = M_IOCNAK;
329 iop->ioc_count = 0;
330 qreply(q, mp);
332 break;
334 default:
335 putnext(q, mp);
339 static int
340 ppp_comp_rput(q, mp)
341 queue_t *q;
342 mblk_t *mp;
344 int proto, rv;
345 mblk_t *dmp;
346 struct ppp_comp_state *cp;
348 cp = (struct ppp_comp_state *) q->q_ptr;
349 switch (mp->b_datap->db_type) {
351 case M_DATA:
352 /* possibly a compressed packet to decompress,
353 or a CCP packet to take notice of. */
354 if (mp->b_wptr - mp->b_rptr >= PPP_HDRLEN
355 || pullupmsg(mp, PPP_HDRLEN)) {
356 proto = PPP_PROTOCOL(mp->b_rptr);
357 if (proto == PPP_CCP)
358 ppp_comp_ccp(q, mp, 1);
359 else if (proto == PPP_COMP) {
360 if ((cp->ccp_state & CCP_ISUP)
361 && (cp->ccp_state & CCP_DECOMP_RUN) && cp->rstate
362 && (cp->ccp_state & CCP_ERR) == 0) {
363 rv = (*cp->rcomp->decompress)(cp->rstate, mp, &dmp);
364 if (dmp != NULL) {
365 freemsg(mp);
366 mp = dmp;
367 } else {
368 switch (rv) {
369 case DECOMP_OK:
370 /* no error, but no packet returned */
371 freemsg(mp);
372 mp = NULL;
373 break;
374 case DECOMP_ERROR:
375 cp->ccp_state |= CCP_ERROR;
376 break;
377 case DECOMP_FATALERROR:
378 cp->ccp_state |= CCP_FATALERROR;
379 break;
383 } else if (cp->rstate && (cp->ccp_state & CCP_DECOMP_RUN)) {
384 (*cp->rcomp->incomp)(cp->rstate, mp);
387 if (mp != NULL)
388 putnext(q, mp);
389 break;
391 default:
392 putnext(q, mp);
396 static void
397 ppp_comp_ccp(q, mp, rcvd)
398 queue_t *q;
399 mblk_t *mp;
400 int rcvd;
402 int len, clen;
403 struct ppp_comp_state *cp;
404 unsigned char *dp;
406 len = msgdsize(mp);
407 if (len < PPP_HDRLEN + CCP_HDRLEN || !pullupmsg(mp, len))
408 return;
409 cp = (struct ppp_comp_state *) q->q_ptr;
410 dp = mp->b_rptr + PPP_HDRLEN;
411 len -= PPP_HDRLEN;
412 clen = CCP_LENGTH(dp);
413 if (clen > len)
414 return;
415 if (cp->debug)
416 bsdlog(LOG_INFO, "CCP %s: code=%x len=%d\n", rcvd? "rcvd": "sent",
417 CCP_CODE(dp), clen);
419 switch (CCP_CODE(dp)) {
420 case CCP_CONFREQ:
421 case CCP_TERMREQ:
422 case CCP_TERMACK:
423 cp->ccp_state &= ~CCP_ISUP;
424 break;
426 case CCP_CONFACK:
427 if ((cp->ccp_state & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN
428 && clen >= CCP_HDRLEN + CCP_OPT_MINLEN
429 && clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
430 if (!rcvd) {
431 if (cp->xstate != NULL
432 && (*cp->xcomp->comp_init)
433 (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
434 0, /* XXX: should be unit */ 0,
435 cp->debug))
436 cp->ccp_state |= CCP_COMP_RUN;
437 } else {
438 if (cp->rstate != NULL
439 && (*cp->rcomp->decomp_init)
440 (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
441 0/* unit */, 0, cp->mru, cp->debug))
442 cp->ccp_state = (cp->ccp_state & ~CCP_ERR)
443 | CCP_DECOMP_RUN;
446 break;
448 case CCP_RESETACK:
449 if (cp->ccp_state & CCP_ISUP) {
450 if (!rcvd) {
451 if (cp->xstate && (cp->ccp_state & CCP_COMP_RUN))
452 (*cp->xcomp->comp_reset)(cp->xstate);
453 } else {
454 if (cp->rstate && (cp->ccp_state & CCP_DECOMP_RUN)) {
455 (*cp->rcomp->decomp_reset)(cp->rstate);
456 cp->ccp_state &= ~CCP_ERROR;
460 break;
463 if (cp->debug)
464 bsdlog(LOG_INFO, "ccp_state = %x\n", cp->ccp_state);