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.6 1997/04/30 05:44:58 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>
46 #include <sys/cmn_err.h>
50 #include <net/ppp_defs.h>
51 #include <net/pppio.h>
54 #define IFRAME_BSIZE 512 /* Block size to allocate for input */
55 #define OFRAME_BSIZE 4096 /* Don't allocb more than this for output */
57 MOD_OPEN_DECL(ahdlc_open);
58 MOD_CLOSE_DECL(ahdlc_close);
59 static int ahdlc_wput __P((queue_t *, mblk_t *));
60 static int ahdlc_rput __P((queue_t *, mblk_t *));
61 static void stuff_frame __P((queue_t *, mblk_t *));
62 static void unstuff_chars __P((queue_t *, mblk_t *));
63 static int msg_byte __P((mblk_t *, unsigned int));
65 /* Extract byte i of message mp. */
66 #define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \
69 /* Is this LCP packet one we have to transmit using LCP defaults? */
70 #define LCP_USE_DFLT(mp) (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
72 #define PPP_AHDL_ID 0x7d23
73 static struct module_info minfo = {
75 PPP_AHDL_ID, "ppp_ahdl", 0, INFPSZ, 640, 512
77 PPP_AHDL_ID, "ppp_ahdl", 0, INFPSZ, 4096, 128
81 static struct qinit rinit = {
82 ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
85 static struct qinit winit = {
86 ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
89 #if defined(SVR4) && !defined(SOL2)
91 #define ppp_ahdlcinfo phdlinfo
93 struct streamtab ppp_ahdlcinfo = {
94 &rinit, &winit, NULL, NULL
99 typedef struct ahdlc_state {
110 struct pppstat stats;
113 /* Values for flags */
114 #define ESCAPED 0x100 /* last saw escape char on input */
115 #define IFLUSH 0x200 /* flushing input due to error */
117 /* RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also. */
118 #define RCV_FLAGS (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)
121 * FCS lookup table as calculated by genfcstab.
123 static u_short fcstab[256] = {
124 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
125 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
126 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
127 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
128 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
129 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
130 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
131 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
132 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
133 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
134 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
135 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
136 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
137 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
138 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
139 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
140 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
141 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
142 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
143 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
144 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
145 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
146 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
147 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
148 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
149 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
150 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
151 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
152 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
153 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
154 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
155 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
159 * STREAMS module entry points.
166 sp = (ahdlc_state_t *) ALLOC_SLEEP(sizeof(ahdlc_state_t));
169 bzero((caddr_t) sp, sizeof(ahdlc_state_t));
170 q->q_ptr = (caddr_t) sp;
171 WR(q)->q_ptr = (caddr_t) sp;
173 sp->xaccm[3] = 0x60000000;
181 MOD_CLOSE(ahdlc_close)
183 ahdlc_state_t *state;
187 state = (ahdlc_state_t *) q->q_ptr;
188 if (state->cur_frame != 0) {
189 freemsg(state->cur_frame);
190 state->cur_frame = 0;
192 FREE(q->q_ptr, sizeof(ahdlc_state_t));
203 ahdlc_state_t *state;
207 struct ppp_stats *psp;
209 state = (ahdlc_state_t *) q->q_ptr;
210 switch (mp->b_datap->db_type) {
213 * A data packet - do character-stuffing and FCS, and
221 iop = (struct iocblk *) mp->b_rptr;
223 switch (iop->ioc_cmd) {
225 if (iop->ioc_count < sizeof(u_int32_t)
226 || iop->ioc_count > sizeof(ext_accm))
228 bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
230 state->xaccm[2] &= ~0x40000000; /* don't escape 0x5e */
231 state->xaccm[3] |= 0x60000000; /* do escape 0x7d, 0x7e */
237 if (iop->ioc_count != sizeof(u_int32_t))
239 bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
246 np = allocb(sizeof(int), BPRI_HI);
254 *(int *)np->b_wptr = state->flags & RCV_FLAGS;
255 np->b_wptr += sizeof(int);
256 iop->ioc_count = sizeof(int);
261 np = allocb(sizeof(struct ppp_stats), BPRI_HI);
269 psp = (struct ppp_stats *) np->b_wptr;
270 np->b_wptr += sizeof(struct ppp_stats);
271 bzero((caddr_t)psp, sizeof(struct ppp_stats));
272 psp->p = state->stats;
273 iop->ioc_count = sizeof(struct ppp_stats);
278 /* we knew this anyway */
289 else if (error == 0) {
290 mp->b_datap->db_type = M_IOCACK;
293 mp->b_datap->db_type = M_IOCNAK;
295 iop->ioc_error = error;
301 switch (*mp->b_rptr) {
303 state->mtu = ((unsigned short *)mp->b_rptr)[1];
307 state->mru = ((unsigned short *)mp->b_rptr)[1];
311 state->unit = mp->b_rptr[1];
331 ahdlc_state_t *state;
333 switch (mp->b_datap->db_type) {
335 unstuff_chars(q, mp);
340 state = (ahdlc_state_t *) q->q_ptr;
341 if (state->cur_frame != 0) {
342 /* XXX would like to send this up for debugging */
343 freemsg(state->cur_frame);
344 state->cur_frame = 0;
348 state->flags = IFLUSH;
358 /* Extract bit c from map m, to determine if c needs to be escaped. */
359 #define ESCAPE(c, m) ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
366 ahdlc_state_t *state;
367 int ilen, olen, c, extra, i, code;
368 mblk_t *omsg, *op, *np;
369 uchar_t *sp, *sp0, *dp, *dp0, *spend;
371 u_int32_t *xaccm, lcp_xaccm[8];
372 static uchar_t lcphdr[PPP_HDRLEN] = { 0xff, 0x03, 0xc0, 0x21 };
373 uchar_t ppphdr[PPP_HDRLEN];
375 state = (ahdlc_state_t *) q->q_ptr;
379 * We estimate the length of the output packet as
380 * 1.25 * input length + 16 (for initial flag, FCS, final flag, slop).
382 olen = ilen + (ilen >> 2) + 16;
383 if (olen > OFRAME_BSIZE)
385 omsg = op = allocb(olen, BPRI_MED);
390 * Put in an initial flag for now. We'll remove it later
391 * if we decide we don't need it.
398 * For LCP packets with code values between 1 and 7 (Conf-Req
399 * to Code-Rej), we must escape all control characters.
401 xaccm = state->xaccm;
402 if (MSG_BYTE(mp, 0) == PPP_ALLSTATIONS
403 && MSG_BYTE(mp, 1) == PPP_UI
404 && MSG_BYTE(mp, 2) == (PPP_LCP >> 8)
405 && MSG_BYTE(mp, 3) == (PPP_LCP & 0xFF)
406 && LCP_USE_DFLT(mp)) {
407 bcopy((caddr_t) state->xaccm, (caddr_t) lcp_xaccm, sizeof(lcp_xaccm));
416 extra = sp + olen - spend;
422 * We can safely process the input up to `spend'
423 * without overrunning the output, provided we don't
424 * hit more than `extra' characters which need to be escaped.
430 if (ESCAPE(c, xaccm)) {
433 else if (sp < spend - 1)
437 fcs = PPP_FCS(fcs, c);
441 fcs = PPP_FCS(fcs, c);
449 * At this point, we have emptied an input block
450 * and/or filled an output block.
452 if (sp >= mp->b_wptr) {
454 * We've emptied an input block. Advance to the next.
458 break; /* all done */
463 * The output block is full. Allocate a new one.
467 if (olen > OFRAME_BSIZE)
469 np = allocb(olen, BPRI_MED);
479 * Append the FCS and closing flag.
480 * This could require up to 5 characters.
483 /* Sigh. Need another block. */
485 np = allocb(5, BPRI_MED);
493 if (ESCAPE(c, xaccm)) {
498 c = (~fcs >> 8) & 0xff;
499 if (ESCAPE(c, xaccm)) {
508 * Remove the initial flag, if possible.
510 if (qsize(q->q_next) > 0)
516 state->stats.ppp_obytes += msgdsize(omsg);
517 state->stats.ppp_opackets++;
528 state->stats.ppp_oerrors++;
529 putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
532 #define UPDATE_FLAGS(c) { \
534 state->flags |= RCV_B7_1; \
536 state->flags |= RCV_B7_0; \
537 if (0x6996 & (1 << ((((c) >> 4) ^ (c)) & 0xf))) \
538 state->flags |= RCV_ODDP; \
540 state->flags |= RCV_EVNP; \
544 * Process received characters.
551 ahdlc_state_t *state;
553 uchar_t *cp, *cpend, *dp, *dp0;
554 int c, len, extra, offset;
557 state = (ahdlc_state_t *) q->q_ptr;
558 state->stats.ppp_ibytes += msgdsize(mp);
562 * Advance to next input block if necessary.
564 if (cp >= mp->b_wptr) {
572 if ((state->flags & (IFLUSH|ESCAPED)) == 0
573 && state->inlen > 0 && (om = state->cur_blk) != 0) {
575 * Process bulk chars as quickly as possible.
578 len = om->b_datap->db_lim - dp; /* max # output bytes */
579 extra = (mp->b_wptr - cp) - len;/* #input chars - #output bytes */
581 len += extra; /* we'll run out of input first */
593 if (c == PPP_ESCAPE) {
598 if (cp >= cpend || (c = *cp) == PPP_FLAG) {
599 state->flags |= ESCAPED;
607 fcs = PPP_FCS(fcs, c);
609 state->inlen += dp - dp0;
612 if (cp >= mp->b_wptr)
613 continue; /* advance to the next mblk */
621 * If the ESCAPE flag is set, the frame ended with
622 * the frame abort sequence "}~".
624 om = state->cur_frame;
626 state->cur_frame = 0;
628 if (len == 0 && (state->flags & IFLUSH) == 0)
630 state->stats.ppp_ipackets++;
631 if (om != 0 && (state->flags & (IFLUSH|ESCAPED)) == 0
632 && len > PPP_FCSLEN) {
633 if (state->infcs == PPP_GOODFCS) {
634 adjmsg(om, -PPP_FCSLEN); /* chop off fcs */
635 putnext(q, om); /* bombs away! */
638 DPRINT2("ppp%d: bad fcs (len=%d)\n", state->unit, len);
642 state->flags &= ~(IFLUSH|ESCAPED);
643 state->stats.ppp_ierrors++;
644 putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
648 if (state->flags & IFLUSH)
650 if (state->flags & ESCAPED) {
652 state->flags &= ~ESCAPED;
653 } else if (c == PPP_ESCAPE) {
654 state->flags |= ESCAPED;
657 if (state->inlen == 0) {
659 * First byte of the frame: allocate the first message block.
661 om = allocb(IFRAME_BSIZE, BPRI_MED);
663 state->flags |= IFLUSH;
666 state->cur_frame = om;
668 state->infcs = PPP_INITFCS;
671 if (om->b_wptr >= om->b_datap->db_lim) {
673 * Current message block is full. Allocate another one,
674 * unless we have run out of MRU.
676 if (state->inlen >= state->mru + PPP_HDRLEN + PPP_FCSLEN) {
677 state->flags |= IFLUSH;
678 DPRINT2("ppp%d: frame too long (%d)\n",
679 state->unit, state->inlen);
682 om = allocb(IFRAME_BSIZE, BPRI_MED);
684 state->flags |= IFLUSH;
687 state->cur_blk->b_cont = om;
692 if (state->inlen == 0) {
694 * We don't do address/control & protocol decompression here,
695 * but we try to put the first byte at an offset such that
696 * the info field starts on a word boundary. The code here
697 * will do this except for packets with protocol compression
698 * but not address/control compression.
700 if (c != PPP_ALLSTATIONS) {
704 om->b_rptr = om->b_wptr;
710 state->infcs = PPP_FCS(state->infcs, c);
719 while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
723 return mp->b_rptr[i];