2 * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC.
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 HAS 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_ahdlc.c,v 1.5 1997/03/04 03:31:51 paulus Exp $
31 * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/stream.h>
36 #include <sys/errno.h>
41 #include <sys/cmn_err.h>
47 #include <net/ppp_defs.h>
48 #include <net/pppio.h>
51 #define IFRAME_BSIZE 512 /* Block size to allocate for input */
52 #define OFRAME_BSIZE 4096 /* Don't allocb more than this for output */
54 MOD_OPEN_DECL(ahdlc_open);
55 MOD_CLOSE_DECL(ahdlc_close);
56 static int ahdlc_wput __P((queue_t *, mblk_t *));
57 static int ahdlc_rput __P((queue_t *, mblk_t *));
58 static void stuff_frame __P((queue_t *, mblk_t *));
59 static void unstuff_chars __P((queue_t *, mblk_t *));
60 static int msg_byte __P((mblk_t *, unsigned int));
62 /* Extract byte i of message mp. */
63 #define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \
66 /* Is this LCP packet one we have to transmit using LCP defaults? */
67 #define LCP_USE_DFLT(mp) (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
69 #define PPP_AHDL_ID 0x7d23
70 static struct module_info minfo = {
72 PPP_AHDL_ID, "ppp_ahdl", 0, INFPSZ, 640, 512
74 PPP_AHDL_ID, "ppp_ahdl", 0, INFPSZ, 4096, 128
78 static struct qinit rinit = {
79 ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
82 static struct qinit winit = {
83 ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
86 #if defined(SVR4) && !defined(SOL2)
88 #define ppp_ahdlcinfo phdlinfo
90 struct streamtab ppp_ahdlcinfo = {
91 &rinit, &winit, NULL, NULL
96 typedef struct ahdlc_state {
107 struct pppstat stats;
110 /* Values for flags */
111 #define ESCAPED 0x100 /* last saw escape char on input */
112 #define IFLUSH 0x200 /* flushing input due to error */
114 /* RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also. */
115 #define RCV_FLAGS (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)
118 * FCS lookup table as calculated by genfcstab.
120 static u_short fcstab[256] = {
121 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
122 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
123 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
124 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
125 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
126 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
127 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
128 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
129 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
130 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
131 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
132 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
133 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
134 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
135 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
136 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
137 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
138 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
139 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
140 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
141 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
142 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
143 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
144 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
145 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
146 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
147 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
148 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
149 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
150 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
151 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
152 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
156 * STREAMS module entry points.
163 sp = (ahdlc_state_t *) ALLOC_SLEEP(sizeof(ahdlc_state_t));
166 bzero((caddr_t) sp, sizeof(ahdlc_state_t));
167 q->q_ptr = (caddr_t) sp;
168 WR(q)->q_ptr = (caddr_t) sp;
170 sp->xaccm[3] = 0x60000000;
178 MOD_CLOSE(ahdlc_close)
180 ahdlc_state_t *state;
184 state = (ahdlc_state_t *) q->q_ptr;
185 if (state->cur_frame != 0) {
186 freemsg(state->cur_frame);
187 state->cur_frame = 0;
189 FREE(q->q_ptr, sizeof(ahdlc_state_t));
200 ahdlc_state_t *state;
204 struct ppp_stats *psp;
206 state = (ahdlc_state_t *) q->q_ptr;
207 switch (mp->b_datap->db_type) {
210 * A data packet - do character-stuffing and FCS, and
218 iop = (struct iocblk *) mp->b_rptr;
220 switch (iop->ioc_cmd) {
222 if (iop->ioc_count < sizeof(u_int32_t)
223 || iop->ioc_count > sizeof(ext_accm))
225 bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
227 state->xaccm[2] &= ~0x40000000; /* don't escape 0x5e */
228 state->xaccm[3] |= 0x60000000; /* do escape 0x7d, 0x7e */
234 if (iop->ioc_count != sizeof(u_int32_t))
236 bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
243 np = allocb(sizeof(int), BPRI_HI);
251 *(int *)np->b_wptr = state->flags & RCV_FLAGS;
252 np->b_wptr += sizeof(int);
253 iop->ioc_count = sizeof(int);
258 np = allocb(sizeof(struct ppp_stats), BPRI_HI);
266 psp = (struct ppp_stats *) np->b_wptr;
267 np->b_wptr += sizeof(struct ppp_stats);
268 bzero((caddr_t)psp, sizeof(struct ppp_stats));
269 psp->p = state->stats;
270 iop->ioc_count = sizeof(struct ppp_stats);
275 /* we knew this anyway */
286 else if (error == 0) {
287 mp->b_datap->db_type = M_IOCACK;
290 mp->b_datap->db_type = M_IOCNAK;
292 iop->ioc_error = error;
298 switch (*mp->b_rptr) {
300 state->mtu = ((unsigned short *)mp->b_rptr)[1];
304 state->mru = ((unsigned short *)mp->b_rptr)[1];
308 state->unit = mp->b_rptr[1];
328 ahdlc_state_t *state;
330 switch (mp->b_datap->db_type) {
332 unstuff_chars(q, mp);
337 state = (ahdlc_state_t *) q->q_ptr;
338 if (state->cur_frame != 0) {
339 /* XXX would like to send this up for debugging */
340 freemsg(state->cur_frame);
341 state->cur_frame = 0;
345 state->flags = IFLUSH;
355 /* Extract bit c from map m, to determine if c needs to be escaped. */
356 #define ESCAPE(c, m) ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
363 ahdlc_state_t *state;
364 int ilen, olen, c, extra, i, code;
365 mblk_t *omsg, *op, *np;
366 uchar_t *sp, *sp0, *dp, *dp0, *spend;
368 u_int32_t *xaccm, lcp_xaccm[8];
369 static uchar_t lcphdr[PPP_HDRLEN] = { 0xff, 0x03, 0xc0, 0x21 };
370 uchar_t ppphdr[PPP_HDRLEN];
372 state = (ahdlc_state_t *) q->q_ptr;
376 * We estimate the length of the output packet as
377 * 1.25 * input length + 16 (for initial flag, FCS, final flag, slop).
379 olen = ilen + (ilen >> 2) + 16;
380 if (olen > OFRAME_BSIZE)
382 omsg = op = allocb(olen, BPRI_MED);
387 * Put in an initial flag for now. We'll remove it later
388 * if we decide we don't need it.
395 * For LCP packets with code values between 1 and 7 (Conf-Req
396 * to Code-Rej), we must escape all control characters.
398 xaccm = state->xaccm;
399 if (MSG_BYTE(mp, 0) == PPP_ALLSTATIONS
400 && MSG_BYTE(mp, 1) == PPP_UI
401 && MSG_BYTE(mp, 2) == (PPP_LCP >> 8)
402 && MSG_BYTE(mp, 3) == (PPP_LCP & 0xFF)
403 && LCP_USE_DFLT(mp)) {
404 bcopy((caddr_t) state->xaccm, (caddr_t) lcp_xaccm, sizeof(lcp_xaccm));
413 extra = sp + olen - spend;
419 * We can safely process the input up to `spend'
420 * without overrunning the output, provided we don't
421 * hit more than `extra' characters which need to be escaped.
427 if (ESCAPE(c, xaccm)) {
430 else if (sp < spend - 1)
434 fcs = PPP_FCS(fcs, c);
438 fcs = PPP_FCS(fcs, c);
446 * At this point, we have emptied an input block
447 * and/or filled an output block.
449 if (sp >= mp->b_wptr) {
451 * We've emptied an input block. Advance to the next.
455 break; /* all done */
460 * The output block is full. Allocate a new one.
464 if (olen > OFRAME_BSIZE)
466 np = allocb(olen, BPRI_MED);
476 * Append the FCS and closing flag.
477 * This could require up to 5 characters.
480 /* Sigh. Need another block. */
482 np = allocb(5, BPRI_MED);
490 if (ESCAPE(c, xaccm)) {
495 c = (~fcs >> 8) & 0xff;
496 if (ESCAPE(c, xaccm)) {
505 * Remove the initial flag, if possible.
507 if (qsize(q->q_next) > 0)
513 state->stats.ppp_obytes += msgdsize(omsg);
514 state->stats.ppp_opackets++;
525 state->stats.ppp_oerrors++;
526 putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
529 #define UPDATE_FLAGS(c) { \
531 state->flags |= RCV_B7_1; \
533 state->flags |= RCV_B7_0; \
534 if (0x6996 & (1 << ((((c) >> 4) ^ (c)) & 0xf))) \
535 state->flags |= RCV_ODDP; \
537 state->flags |= RCV_EVNP; \
541 * Process received characters.
548 ahdlc_state_t *state;
550 uchar_t *cp, *cpend, *dp, *dp0;
551 int c, len, extra, offset;
554 state = (ahdlc_state_t *) q->q_ptr;
555 state->stats.ppp_ibytes += msgdsize(mp);
559 * Advance to next input block if necessary.
561 if (cp >= mp->b_wptr) {
569 if ((state->flags & (IFLUSH|ESCAPED)) == 0
570 && state->inlen > 0 && (om = state->cur_blk) != 0) {
572 * Process bulk chars as quickly as possible.
575 len = om->b_datap->db_lim - dp; /* max # output bytes */
576 extra = (mp->b_wptr - cp) - len;/* #input chars - #output bytes */
578 len += extra; /* we'll run out of input first */
590 if (c == PPP_ESCAPE) {
595 if (cp >= cpend || (c = *cp) == PPP_FLAG) {
596 state->flags |= ESCAPED;
604 fcs = PPP_FCS(fcs, c);
606 state->inlen += dp - dp0;
609 if (cp >= mp->b_wptr)
610 continue; /* advance to the next mblk */
618 * If the ESCAPE flag is set, the frame ended with
619 * the frame abort sequence "}~".
621 om = state->cur_frame;
623 state->cur_frame = 0;
625 if (len == 0 && (state->flags & IFLUSH) == 0)
627 state->stats.ppp_ipackets++;
628 if (om != 0 && (state->flags & (IFLUSH|ESCAPED)) == 0
629 && len > PPP_FCSLEN) {
630 if (state->infcs == PPP_GOODFCS) {
631 adjmsg(om, -PPP_FCSLEN); /* chop off fcs */
632 putnext(q, om); /* bombs away! */
635 DPRINT2("ppp%d: bad fcs (len=%d)\n", state->unit, len);
639 state->flags &= ~(IFLUSH|ESCAPED);
640 state->stats.ppp_ierrors++;
641 putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
645 if (state->flags & IFLUSH)
647 if (state->flags & ESCAPED) {
649 state->flags &= ~ESCAPED;
650 } else if (c == PPP_ESCAPE) {
651 state->flags |= ESCAPED;
654 if (state->inlen == 0) {
656 * First byte of the frame: allocate the first message block.
658 om = allocb(IFRAME_BSIZE, BPRI_MED);
660 state->flags |= IFLUSH;
663 state->cur_frame = om;
665 state->infcs = PPP_INITFCS;
668 if (om->b_wptr >= om->b_datap->db_lim) {
670 * Current message block is full. Allocate another one,
671 * unless we have run out of MRU.
673 if (state->inlen >= state->mru + PPP_HDRLEN + PPP_FCSLEN) {
674 state->flags |= IFLUSH;
675 DPRINT2("ppp%d: frame too long (%d)\n",
676 state->unit, state->inlen);
679 om = allocb(IFRAME_BSIZE, BPRI_MED);
681 state->flags |= IFLUSH;
684 state->cur_blk->b_cont = om;
689 if (state->inlen == 0) {
691 * We don't do address/control & protocol decompression here,
692 * but we try to put the first byte at an offset such that
693 * the info field starts on a word boundary. The code here
694 * will do this except for packets with protocol compression
695 * but not address/control compression.
697 if (c != PPP_ALLSTATIONS) {
701 om->b_rptr = om->b_wptr;
707 state->infcs = PPP_FCS(state->infcs, c);
716 while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
720 return mp->b_rptr[i];