Don't override the user's choice of mtu/mru < 1492,
[mpls-ppp.git] / modules / ppp_ahdlc.c
blob184b535657d199a605bde2c30bac3fe8692bd079
1 /*
2 * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC.
4 * Re-written by Adi Masputra <adi.masputra@sun.com>, based on
5 * the original ppp_ahdlc.c
7 * Copyright (c) 2000 by Sun Microsystems, Inc.
8 * All rights reserved.
10 * Permission to use, copy, modify, and distribute this software and its
11 * documentation is hereby granted, provided that the above copyright
12 * notice appears in all copies.
14 * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
15 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
16 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
17 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
18 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
19 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
21 * Copyright (c) 1994 Paul Mackerras. All rights reserved.
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
30 * 2. Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in
32 * the documentation and/or other materials provided with the
33 * distribution.
35 * 3. The name(s) of the authors of this software must not be used to
36 * endorse or promote products derived from this software without
37 * prior written permission.
39 * 4. Redistributions of any form whatsoever must retain the following
40 * acknowledgment:
41 * "This product includes software developed by Paul Mackerras
42 * <paulus@samba.org>".
44 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
45 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
46 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
47 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
48 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
49 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
50 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
52 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
55 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
56 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
57 * OR MODIFICATIONS.
59 * $Id: ppp_ahdlc.c,v 1.18 2002/12/06 09:49:15 paulus Exp $
63 * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
65 #include <sys/types.h>
66 #include <sys/param.h>
67 #include <sys/stream.h>
68 #include <sys/errno.h>
70 #ifdef SVR4
71 #include <sys/conf.h>
72 #include <sys/kmem.h>
73 #include <sys/cmn_err.h>
74 #include <sys/ddi.h>
75 #else
76 #include <sys/user.h>
77 #ifdef __osf__
78 #include <sys/cmn_err.h>
79 #endif
80 #endif /* SVR4 */
82 #include <net/ppp_defs.h>
83 #include <net/pppio.h>
84 #include "ppp_mod.h"
87 * Right now, mutex is only enabled for Solaris 2.x
89 #if defined(SOL2)
90 #define USE_MUTEX
91 #endif /* SOL2 */
94 * intpointer_t and uintpointer_t are signed and unsigned integer types
95 * large enough to hold any data pointer; that is, data pointers can be
96 * assigned into or from these integer types without losing precision.
97 * On recent Solaris releases, these types are defined in sys/int_types.h,
98 * but not on SunOS 4.x or the earlier Solaris versions.
100 #if defined(_LP64) || defined(_I32LPx)
101 typedef long intpointer_t;
102 typedef unsigned long uintpointer_t;
103 #else
104 typedef int intpointer_t;
105 typedef unsigned int uintpointer_t;
106 #endif
108 MOD_OPEN_DECL(ahdlc_open);
109 MOD_CLOSE_DECL(ahdlc_close);
110 static int ahdlc_wput __P((queue_t *, mblk_t *));
111 static int ahdlc_rput __P((queue_t *, mblk_t *));
112 static void ahdlc_encode __P((queue_t *, mblk_t *));
113 static void ahdlc_decode __P((queue_t *, mblk_t *));
114 static int msg_byte __P((mblk_t *, unsigned int));
116 #if defined(SOL2)
118 * Don't send HDLC start flag is last transmit is within 1.5 seconds -
119 * FLAG_TIME is defined is microseconds
121 #define FLAG_TIME 1500
122 #define ABS(x) (x >= 0 ? x : (-x))
123 #endif /* SOL2 */
126 * Extract byte i of message mp
128 #define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \
129 msg_byte((mp), (i)))
132 * Is this LCP packet one we have to transmit using LCP defaults?
134 #define LCP_USE_DFLT(mp) (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
137 * Standard STREAMS declarations
139 static struct module_info minfo = {
140 0x7d23, "ppp_ahdl", 0, INFPSZ, 32768, 512
143 static struct qinit rinit = {
144 ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
147 static struct qinit winit = {
148 ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
151 #if defined(SVR4) && !defined(SOL2)
152 int phdldevflag = 0;
153 #define ppp_ahdlcinfo phdlinfo
154 #endif /* defined(SVR4) && !defined(SOL2) */
156 struct streamtab ppp_ahdlcinfo = {
157 &rinit, /* ptr to st_rdinit */
158 &winit, /* ptr to st_wrinit */
159 NULL, /* ptr to st_muxrinit */
160 NULL, /* ptr to st_muxwinit */
161 #if defined(SUNOS4)
162 NULL /* ptr to ptr to st_modlist */
163 #endif /* SUNOS4 */
166 #if defined(SUNOS4)
167 int ppp_ahdlc_count = 0; /* open counter */
168 #endif /* SUNOS4 */
171 * Per-stream state structure
173 typedef struct ahdlc_state {
174 #if defined(USE_MUTEX)
175 kmutex_t lock; /* lock for this structure */
176 #endif /* USE_MUTEX */
177 int flags; /* link flags */
178 mblk_t *rx_buf; /* ptr to receive buffer */
179 int rx_buf_size; /* receive buffer size */
180 ushort_t infcs; /* calculated rx HDLC FCS */
181 u_int32_t xaccm[8]; /* 256-bit xmit ACCM */
182 u_int32_t raccm; /* 32-bit rcv ACCM */
183 int mtu; /* interface MTU */
184 int mru; /* link MRU */
185 int unit; /* current PPP unit number */
186 struct pppstat stats; /* statistic structure */
187 #if defined(SOL2)
188 clock_t flag_time; /* time in usec between flags */
189 clock_t lbolt; /* last updated lbolt */
190 #endif /* SOL2 */
191 } ahdlc_state_t;
194 * Values for flags
196 #define ESCAPED 0x100 /* last saw escape char on input */
197 #define IFLUSH 0x200 /* flushing input due to error */
200 * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also.
202 #define RCV_FLAGS (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)
205 * FCS lookup table as calculated by genfcstab.
207 static u_short fcstab[256] = {
208 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
209 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
210 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
211 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
212 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
213 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
214 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
215 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
216 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
217 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
218 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
219 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
220 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
221 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
222 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
223 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
224 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
225 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
226 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
227 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
228 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
229 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
230 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
231 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
232 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
233 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
234 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
235 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
236 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
237 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
238 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
239 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
242 static u_int32_t paritytab[8] =
244 0x96696996, 0x69969669, 0x69969669, 0x96696996,
245 0x69969669, 0x96696996, 0x96696996, 0x69969669
249 * STREAMS module open (entry) point
251 MOD_OPEN(ahdlc_open)
253 ahdlc_state_t *state;
256 * Return if it's already opened
258 if (q->q_ptr) {
259 return 0;
263 * This can only be opened as a module
265 if (sflag != MODOPEN) {
266 return 0;
269 state = (ahdlc_state_t *) ALLOC_NOSLEEP(sizeof(ahdlc_state_t));
270 if (state == 0)
271 OPEN_ERROR(ENOSR);
272 bzero((caddr_t) state, sizeof(ahdlc_state_t));
274 q->q_ptr = (caddr_t) state;
275 WR(q)->q_ptr = (caddr_t) state;
277 #if defined(USE_MUTEX)
278 mutex_init(&state->lock, NULL, MUTEX_DEFAULT, NULL);
279 mutex_enter(&state->lock);
280 #endif /* USE_MUTEX */
282 state->xaccm[0] = ~0; /* escape 0x00 through 0x1f */
283 state->xaccm[3] = 0x60000000; /* escape 0x7d and 0x7e */
284 state->mru = PPP_MRU; /* default of 1500 bytes */
285 #if defined(SOL2)
286 state->flag_time = drv_usectohz(FLAG_TIME);
287 #endif /* SOL2 */
289 #if defined(USE_MUTEX)
290 mutex_exit(&state->lock);
291 #endif /* USE_MUTEX */
293 #if defined(SUNOS4)
294 ppp_ahdlc_count++;
295 #endif /* SUNOS4 */
297 qprocson(q);
299 return 0;
303 * STREAMS module close (exit) point
305 MOD_CLOSE(ahdlc_close)
307 ahdlc_state_t *state;
309 qprocsoff(q);
311 state = (ahdlc_state_t *) q->q_ptr;
313 if (state == 0) {
314 DPRINT("state == 0 in ahdlc_close\n");
315 return 0;
318 #if defined(USE_MUTEX)
319 mutex_enter(&state->lock);
320 #endif /* USE_MUTEX */
322 if (state->rx_buf != 0) {
323 freemsg(state->rx_buf);
324 state->rx_buf = 0;
327 #if defined(USE_MUTEX)
328 mutex_exit(&state->lock);
329 mutex_destroy(&state->lock);
330 #endif /* USE_MUTEX */
332 FREE(q->q_ptr, sizeof(ahdlc_state_t));
333 q->q_ptr = NULL;
334 OTHERQ(q)->q_ptr = NULL;
336 #if defined(SUNOS4)
337 if (ppp_ahdlc_count)
338 ppp_ahdlc_count--;
339 #endif /* SUNOS4 */
341 return 0;
345 * Write side put routine
347 static int
348 ahdlc_wput(q, mp)
349 queue_t *q;
350 mblk_t *mp;
352 ahdlc_state_t *state;
353 struct iocblk *iop;
354 int error;
355 mblk_t *np;
356 struct ppp_stats *psp;
358 state = (ahdlc_state_t *) q->q_ptr;
359 if (state == 0) {
360 DPRINT("state == 0 in ahdlc_wput\n");
361 freemsg(mp);
362 return 0;
365 switch (mp->b_datap->db_type) {
366 case M_DATA:
368 * A data packet - do character-stuffing and FCS, and
369 * send it onwards.
371 ahdlc_encode(q, mp);
372 freemsg(mp);
373 break;
375 case M_IOCTL:
376 iop = (struct iocblk *) mp->b_rptr;
377 error = EINVAL;
378 switch (iop->ioc_cmd) {
379 case PPPIO_XACCM:
380 if ((iop->ioc_count < sizeof(u_int32_t)) ||
381 (iop->ioc_count > sizeof(ext_accm))) {
382 break;
384 if (mp->b_cont == 0) {
385 DPRINT1("ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n", state->unit);
386 break;
388 #if defined(USE_MUTEX)
389 mutex_enter(&state->lock);
390 #endif /* USE_MUTEX */
391 bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
392 iop->ioc_count);
393 state->xaccm[2] &= ~0x40000000; /* don't escape 0x5e */
394 state->xaccm[3] |= 0x60000000; /* do escape 0x7d, 0x7e */
395 #if defined(USE_MUTEX)
396 mutex_exit(&state->lock);
397 #endif /* USE_MUTEX */
398 iop->ioc_count = 0;
399 error = 0;
400 break;
402 case PPPIO_RACCM:
403 if (iop->ioc_count != sizeof(u_int32_t))
404 break;
405 if (mp->b_cont == 0) {
406 DPRINT1("ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n", state->unit);
407 break;
409 #if defined(USE_MUTEX)
410 mutex_enter(&state->lock);
411 #endif /* USE_MUTEX */
412 bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
413 sizeof(u_int32_t));
414 #if defined(USE_MUTEX)
415 mutex_exit(&state->lock);
416 #endif /* USE_MUTEX */
417 iop->ioc_count = 0;
418 error = 0;
419 break;
421 case PPPIO_GCLEAN:
422 np = allocb(sizeof(int), BPRI_HI);
423 if (np == 0) {
424 error = ENOSR;
425 break;
427 if (mp->b_cont != 0)
428 freemsg(mp->b_cont);
429 mp->b_cont = np;
430 #if defined(USE_MUTEX)
431 mutex_enter(&state->lock);
432 #endif /* USE_MUTEX */
433 *(int *)np->b_wptr = state->flags & RCV_FLAGS;
434 #if defined(USE_MUTEX)
435 mutex_exit(&state->lock);
436 #endif /* USE_MUTEX */
437 np->b_wptr += sizeof(int);
438 iop->ioc_count = sizeof(int);
439 error = 0;
440 break;
442 case PPPIO_GETSTAT:
443 np = allocb(sizeof(struct ppp_stats), BPRI_HI);
444 if (np == 0) {
445 error = ENOSR;
446 break;
448 if (mp->b_cont != 0)
449 freemsg(mp->b_cont);
450 mp->b_cont = np;
451 psp = (struct ppp_stats *) np->b_wptr;
452 np->b_wptr += sizeof(struct ppp_stats);
453 bzero((caddr_t)psp, sizeof(struct ppp_stats));
454 psp->p = state->stats;
455 iop->ioc_count = sizeof(struct ppp_stats);
456 error = 0;
457 break;
459 case PPPIO_LASTMOD:
460 /* we knew this anyway */
461 error = 0;
462 break;
464 default:
465 error = -1;
466 break;
469 if (error < 0)
470 putnext(q, mp);
471 else if (error == 0) {
472 mp->b_datap->db_type = M_IOCACK;
473 qreply(q, mp);
474 } else {
475 mp->b_datap->db_type = M_IOCNAK;
476 iop->ioc_count = 0;
477 iop->ioc_error = error;
478 qreply(q, mp);
480 break;
482 case M_CTL:
483 switch (*mp->b_rptr) {
484 case PPPCTL_MTU:
485 #if defined(USE_MUTEX)
486 mutex_enter(&state->lock);
487 #endif /* USE_MUTEX */
488 state->mtu = ((unsigned short *)mp->b_rptr)[1];
489 #if defined(USE_MUTEX)
490 mutex_exit(&state->lock);
491 #endif /* USE_MUTEX */
492 freemsg(mp);
493 break;
494 case PPPCTL_MRU:
495 #if defined(USE_MUTEX)
496 mutex_enter(&state->lock);
497 #endif /* USE_MUTEX */
498 state->mru = ((unsigned short *)mp->b_rptr)[1];
499 #if defined(USE_MUTEX)
500 mutex_exit(&state->lock);
501 #endif /* USE_MUTEX */
502 freemsg(mp);
503 break;
504 case PPPCTL_UNIT:
505 #if defined(USE_MUTEX)
506 mutex_enter(&state->lock);
507 #endif /* USE_MUTEX */
508 state->unit = mp->b_rptr[1];
509 #if defined(USE_MUTEX)
510 mutex_exit(&state->lock);
511 #endif /* USE_MUTEX */
512 break;
513 default:
514 putnext(q, mp);
516 break;
518 default:
519 putnext(q, mp);
522 return 0;
526 * Read side put routine
528 static int
529 ahdlc_rput(q, mp)
530 queue_t *q;
531 mblk_t *mp;
533 ahdlc_state_t *state;
535 state = (ahdlc_state_t *) q->q_ptr;
536 if (state == 0) {
537 DPRINT("state == 0 in ahdlc_rput\n");
538 freemsg(mp);
539 return 0;
542 switch (mp->b_datap->db_type) {
543 case M_DATA:
544 ahdlc_decode(q, mp);
545 break;
547 case M_HANGUP:
548 #if defined(USE_MUTEX)
549 mutex_enter(&state->lock);
550 #endif /* USE_MUTEX */
551 if (state->rx_buf != 0) {
552 /* XXX would like to send this up for debugging */
553 freemsg(state->rx_buf);
554 state->rx_buf = 0;
556 state->flags = IFLUSH;
557 #if defined(USE_MUTEX)
558 mutex_exit(&state->lock);
559 #endif /* USE_MUTEX */
560 putnext(q, mp);
561 break;
563 default:
564 putnext(q, mp);
566 return 0;
570 * Extract bit c from map m, to determine if c needs to be escaped
572 #define IN_TX_MAP(c, m) ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
574 static void
575 ahdlc_encode(q, mp)
576 queue_t *q;
577 mblk_t *mp;
579 ahdlc_state_t *state;
580 u_int32_t *xaccm, loc_xaccm[8];
581 ushort_t fcs;
582 size_t outmp_len;
583 mblk_t *outmp, *tmp;
584 uchar_t *dp, fcs_val;
585 int is_lcp, code;
586 #if defined(SOL2)
587 clock_t lbolt;
588 #endif /* SOL2 */
590 if (msgdsize(mp) < 4) {
591 return;
594 state = (ahdlc_state_t *)q->q_ptr;
595 #if defined(USE_MUTEX)
596 mutex_enter(&state->lock);
597 #endif /* USE_MUTEX */
600 * Allocate an output buffer large enough to handle a case where all
601 * characters need to be escaped
603 outmp_len = (msgdsize(mp) << 1) + /* input block x 2 */
604 (sizeof(fcs) << 2) + /* HDLC FCS x 4 */
605 (sizeof(uchar_t) << 1); /* HDLC flags x 2 */
607 outmp = allocb(outmp_len, BPRI_MED);
608 if (outmp == NULL) {
609 state->stats.ppp_oerrors++;
610 #if defined(USE_MUTEX)
611 mutex_exit(&state->lock);
612 #endif /* USE_MUTEX */
613 putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
614 return;
617 #if defined(SOL2)
619 * Check if our last transmit happenned within flag_time, using
620 * the system's LBOLT value in clock ticks
622 if (drv_getparm(LBOLT, &lbolt) != -1) {
623 if (ABS((clock_t)lbolt - state->lbolt) > state->flag_time) {
624 *outmp->b_wptr++ = PPP_FLAG;
626 state->lbolt = lbolt;
627 } else {
628 *outmp->b_wptr++ = PPP_FLAG;
630 #else
632 * If the driver below still has a message to process, skip the
633 * HDLC flag, otherwise, put one in the beginning
635 if (qsize(q->q_next) == 0) {
636 *outmp->b_wptr++ = PPP_FLAG;
638 #endif
641 * All control characters must be escaped for LCP packets with code
642 * values between 1 (Conf-Req) and 7 (Code-Rej).
644 is_lcp = ((MSG_BYTE(mp, 0) == PPP_ALLSTATIONS) &&
645 (MSG_BYTE(mp, 1) == PPP_UI) &&
646 (MSG_BYTE(mp, 2) == (PPP_LCP >> 8)) &&
647 (MSG_BYTE(mp, 3) == (PPP_LCP & 0xff)) &&
648 LCP_USE_DFLT(mp));
650 xaccm = state->xaccm;
651 if (is_lcp) {
652 bcopy((caddr_t)state->xaccm, (caddr_t)loc_xaccm, sizeof(loc_xaccm));
653 loc_xaccm[0] = ~0; /* force escape on 0x00 through 0x1f */
654 xaccm = loc_xaccm;
657 fcs = PPP_INITFCS; /* Initial FCS is 0xffff */
660 * Process this block and the rest (if any) attached to the this one
662 for (tmp = mp; tmp; tmp = tmp->b_cont) {
663 if (tmp->b_datap->db_type == M_DATA) {
664 for (dp = tmp->b_rptr; dp < tmp->b_wptr; dp++) {
665 fcs = PPP_FCS(fcs, *dp);
666 if (IN_TX_MAP(*dp, xaccm)) {
667 *outmp->b_wptr++ = PPP_ESCAPE;
668 *outmp->b_wptr++ = *dp ^ PPP_TRANS;
669 } else {
670 *outmp->b_wptr++ = *dp;
673 } else {
674 continue; /* skip if db_type is something other than M_DATA */
679 * Append the HDLC FCS, making sure that escaping is done on any
680 * necessary bytes
682 fcs_val = (fcs ^ 0xffff) & 0xff;
683 if (IN_TX_MAP(fcs_val, xaccm)) {
684 *outmp->b_wptr++ = PPP_ESCAPE;
685 *outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
686 } else {
687 *outmp->b_wptr++ = fcs_val;
690 fcs_val = ((fcs ^ 0xffff) >> 8) & 0xff;
691 if (IN_TX_MAP(fcs_val, xaccm)) {
692 *outmp->b_wptr++ = PPP_ESCAPE;
693 *outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
694 } else {
695 *outmp->b_wptr++ = fcs_val;
699 * And finally, append the HDLC flag, and send it away
701 *outmp->b_wptr++ = PPP_FLAG;
703 state->stats.ppp_obytes += msgdsize(outmp);
704 state->stats.ppp_opackets++;
706 #if defined(USE_MUTEX)
707 mutex_exit(&state->lock);
708 #endif /* USE_MUTEX */
710 putnext(q, outmp);
711 return;
715 * Checks the 32-bit receive ACCM to see if the byte needs un-escaping
717 #define IN_RX_MAP(c, m) ((((unsigned int) (uchar_t) (c)) < 0x20) && \
718 (m) & (1 << (c)))
722 * Process received characters.
724 static void
725 ahdlc_decode(q, mp)
726 queue_t *q;
727 mblk_t *mp;
729 ahdlc_state_t *state;
730 mblk_t *om;
731 uchar_t *dp;
733 state = (ahdlc_state_t *) q->q_ptr;
735 #if defined(USE_MUTEX)
736 mutex_enter(&state->lock);
737 #endif /* USE_MUTEX */
739 state->stats.ppp_ibytes += msgdsize(mp);
741 for (; mp != 0; om = mp->b_cont, freeb(mp), mp = om)
742 for (dp = mp->b_rptr; dp < mp->b_wptr; dp++) {
745 * This should detect the lack of 8-bit communication channel
746 * which is necessary for PPP to work. In addition, it also
747 * checks on the parity.
749 if (*dp & 0x80)
750 state->flags |= RCV_B7_1;
751 else
752 state->flags |= RCV_B7_0;
754 if (paritytab[*dp >> 5] & (1 << (*dp & 0x1f)))
755 state->flags |= RCV_ODDP;
756 else
757 state->flags |= RCV_EVNP;
760 * So we have a HDLC flag ...
762 if (*dp == PPP_FLAG) {
765 * If we think that it marks the beginning of the frame,
766 * then continue to process the next octects
768 if ((state->flags & IFLUSH) ||
769 (state->rx_buf == 0) ||
770 (msgdsize(state->rx_buf) == 0)) {
772 state->flags &= ~IFLUSH;
773 continue;
777 * We get here because the above condition isn't true,
778 * in which case the HDLC flag was there to mark the end
779 * of the frame (or so we think)
781 om = state->rx_buf;
783 if (state->infcs == PPP_GOODFCS) {
784 state->stats.ppp_ipackets++;
785 adjmsg(om, -PPP_FCSLEN);
786 putnext(q, om);
787 } else {
788 DPRINT2("ppp%d: bad fcs (len=%d)\n",
789 state->unit, msgdsize(state->rx_buf));
790 freemsg(state->rx_buf);
791 state->flags &= ~(IFLUSH | ESCAPED);
792 state->stats.ppp_ierrors++;
793 putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
796 state->rx_buf = 0;
797 continue;
800 if (state->flags & IFLUSH) {
801 continue;
805 * Allocate a receive buffer, large enough to store a frame (after
806 * un-escaping) of at least 1500 octets. If MRU is negotiated to
807 * be more than the default, then allocate that much. In addition,
808 * we add an extra 32-bytes for a fudge factor
810 if (state->rx_buf == 0) {
811 state->rx_buf_size = (state->mru < PPP_MRU ? PPP_MRU : state->mru);
812 state->rx_buf_size += (sizeof(u_int32_t) << 3);
813 state->rx_buf = allocb(state->rx_buf_size, BPRI_MED);
816 * If allocation fails, try again on the next frame
818 if (state->rx_buf == 0) {
819 state->flags |= IFLUSH;
820 continue;
822 state->flags &= ~(IFLUSH | ESCAPED);
823 state->infcs = PPP_INITFCS;
826 if (*dp == PPP_ESCAPE) {
827 state->flags |= ESCAPED;
828 continue;
832 * Make sure we un-escape the necessary characters, as well as the
833 * ones in our receive async control character map
835 if (state->flags & ESCAPED) {
836 *dp ^= PPP_TRANS;
837 state->flags &= ~ESCAPED;
838 } else if (IN_RX_MAP(*dp, state->raccm))
839 continue;
842 * Unless the peer lied to us about the negotiated MRU, we should
843 * never get a frame which is too long. If it happens, toss it away
844 * and grab the next incoming one
846 if (msgdsize(state->rx_buf) < state->rx_buf_size) {
847 state->infcs = PPP_FCS(state->infcs, *dp);
848 *state->rx_buf->b_wptr++ = *dp;
849 } else {
850 DPRINT2("ppp%d: frame too long (%d)\n",
851 state->unit, msgdsize(state->rx_buf));
852 freemsg(state->rx_buf);
853 state->rx_buf = 0;
854 state->flags |= IFLUSH;
858 #if defined(USE_MUTEX)
859 mutex_exit(&state->lock);
860 #endif /* USE_MUTEX */
863 static int
864 msg_byte(mp, i)
865 mblk_t *mp;
866 unsigned int i;
868 while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
869 mp = mp->b_cont;
870 if (mp == 0)
871 return -1;
872 return mp->b_rptr[i];