From c40c90533a0576e1a391966319b3b1332565b89c Mon Sep 17 00:00:00 2001 From: Adi Masputra Date: Fri, 21 Jan 2000 01:04:56 +0000 Subject: [PATCH] Re-wrote async HDLC encoding/decoding algorithms, mostly due to some inconsistencies of behavior across different hardware platforms - previously this code was generating an invalid HDLC frame (bad fcs) on Solaris x86 platform. --- modules/ppp_ahdlc.c | 809 +++++++++++++++++++++++++------------------- 1 file changed, 457 insertions(+), 352 deletions(-) diff --git a/modules/ppp_ahdlc.c b/modules/ppp_ahdlc.c index 1828fe1..a55b173 100644 --- a/modules/ppp_ahdlc.c +++ b/modules/ppp_ahdlc.c @@ -1,6 +1,23 @@ /* * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC. * + * Re-written by Adi Masputra , based on + * the original ppp_ahdlc.c + * + * Copyright (c) 2000 by Sun Microsystems, Inc. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. + * + * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES + * * Copyright (c) 1994 The Australian National University. * All rights reserved. * @@ -24,7 +41,7 @@ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * - * $Id: ppp_ahdlc.c,v 1.11 1999/09/15 23:49:05 masputra Exp $ + * $Id: ppp_ahdlc.c,v 1.12 2000/01/21 01:04:56 masputra Exp $ */ /* @@ -51,31 +68,46 @@ #include #include "ppp_mod.h" -#define IFRAME_BSIZE 512 /* Block size to allocate for input */ -#define OFRAME_BSIZE 4096 /* Don't allocb more than this for output */ +/* + * Right now, mutex is only enabled for Solaris 2.x + */ +#if defined(SOL2) +#define USE_MUTEX +#endif /* SOL2 */ MOD_OPEN_DECL(ahdlc_open); MOD_CLOSE_DECL(ahdlc_close); static int ahdlc_wput __P((queue_t *, mblk_t *)); static int ahdlc_rput __P((queue_t *, mblk_t *)); -static void stuff_frame __P((queue_t *, mblk_t *)); -static void unstuff_chars __P((queue_t *, mblk_t *)); +static void ahdlc_encode __P((queue_t *, mblk_t *)); +static void ahdlc_decode __P((queue_t *, mblk_t *)); static int msg_byte __P((mblk_t *, unsigned int)); -/* Extract byte i of message mp. */ +#if defined(SOL2) +/* + * Don't send HDLC start flag is last transmit is within 1.5 seconds - + * FLAG_TIME is defined is microseconds + */ +#define FLAG_TIME 1500 +#define ABS(x) (x >= 0 ? x : (-x)) +#endif /* SOL2 */ + +/* + * Extract byte i of message mp + */ #define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \ msg_byte((mp), (i))) -/* Is this LCP packet one we have to transmit using LCP defaults? */ +/* + * Is this LCP packet one we have to transmit using LCP defaults? + */ #define LCP_USE_DFLT(mp) (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7) -#define PPP_AHDL_ID 0x7d23 +/* + * Standard STREAMS declarations + */ static struct module_info minfo = { -#ifdef PRIOQ - PPP_AHDL_ID, "ppp_ahdl", 0, INFPSZ, 640, 512 -#else - PPP_AHDL_ID, "ppp_ahdl", 0, INFPSZ, 4096, 128 -#endif PRIOQ + 0x7d23, "ppp_ahdl", 0, INFPSZ, 32768, 512 }; static struct qinit rinit = { @@ -89,32 +121,50 @@ static struct qinit winit = { #if defined(SVR4) && !defined(SOL2) int phdldevflag = 0; #define ppp_ahdlcinfo phdlinfo -#endif +#endif /* defined(SVR4) && !defined(SOL2) */ + struct streamtab ppp_ahdlcinfo = { - &rinit, &winit, NULL, NULL + &rinit, /* ptr to st_rdinit */ + &winit, /* ptr to st_wrinit */ + NULL, /* ptr to st_muxrinit */ + NULL, /* ptr to st_muxwinit */ +#ifdef _SunOS4 + NULL /* ptr to ptr to st_modlist */ +#endif /* _SunOS4 */ }; -int ppp_ahdlc_count; - +/* + * Per-stream state structure + */ typedef struct ahdlc_state { - int flags; - mblk_t *cur_frame; - mblk_t *cur_blk; - int inlen; - ushort infcs; - u_int32_t xaccm[8]; - u_int32_t raccm; - int mtu; - int mru; - int unit; - struct pppstat stats; +#if defined(USE_MUTEX) + kmutex_t lock; /* lock for this structure */ +#endif /* USE_MUTEX */ + int flags; /* link flags */ + mblk_t *rx_buf; /* ptr to receive buffer */ + int rx_buf_size; /* receive buffer size */ + ushort_t infcs; /* calculated rx HDLC FCS */ + u_int32_t xaccm[8]; /* 256-bit xmit ACCM */ + u_int32_t raccm; /* 32-bit rcv ACCM */ + int mtu; /* interface MTU */ + int mru; /* link MRU */ + int unit; /* current PPP unit number */ + struct pppstat stats; /* statistic structure */ +#if defined(SOL2) + clock_t flag_time; /* time in usec between flags */ + clock_t lbolt; /* last updated lbolt */ +#endif /* SOL2 */ } ahdlc_state_t; -/* Values for flags */ +/* + * Values for flags + */ #define ESCAPED 0x100 /* last saw escape char on input */ #define IFLUSH 0x200 /* flushing input due to error */ -/* RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also. */ +/* + * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also. + */ #define RCV_FLAGS (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP) /* @@ -155,58 +205,112 @@ static u_short fcstab[256] = { 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; +static u_int32_t paritytab[8] = +{ + 0x96696996, 0x69969669, 0x69969669, 0x96696996, + 0x69969669, 0x96696996, 0x96696996, 0x69969669 +}; + /* - * STREAMS module entry points. + * STREAMS module open (entry) point */ MOD_OPEN(ahdlc_open) { - ahdlc_state_t *sp; - - if (q->q_ptr == 0) { - sp = (ahdlc_state_t *) ALLOC_SLEEP(sizeof(ahdlc_state_t)); - if (sp == 0) - OPEN_ERROR(ENOSR); - bzero((caddr_t) sp, sizeof(ahdlc_state_t)); - q->q_ptr = (caddr_t) sp; - WR(q)->q_ptr = (caddr_t) sp; - sp->xaccm[0] = ~0; - sp->xaccm[3] = 0x60000000; - sp->mru = PPP_MRU; - ++ppp_ahdlc_count; - qprocson(q); + ahdlc_state_t *state; + + /* + * Return if it's already opened + */ + if (q->q_ptr) { + return 0; + } + + /* + * This can only be opened as a module + */ + if (sflag != MODOPEN) { + return 0; } + + state = (ahdlc_state_t *) ALLOC_NOSLEEP(sizeof(ahdlc_state_t)); + if (state == 0) + OPEN_ERROR(ENOSR); + bzero((caddr_t) state, sizeof(ahdlc_state_t)); + + q->q_ptr = (caddr_t) state; + WR(q)->q_ptr = (caddr_t) state; + +#if defined(USE_MUTEX) + mutex_init(&state->lock, NULL, MUTEX_DEFAULT, NULL); + mutex_enter(&state->lock); +#endif /* USE_MUTEX */ + + state->xaccm[0] = ~0; /* escape 0x00 through 0x1f */ + state->xaccm[3] = 0x60000000; /* escape 0x7d and 0x7e */ + state->mru = PPP_MRU; /* default of 1500 bytes */ +#if defined(SOL2) + state->flag_time = drv_usectohz(FLAG_TIME); +#endif /* SOL2 */ + +#if defined(USE_MUTEX) + mutex_exit(&state->lock); +#endif /* USE_MUTEX */ + + qprocson(q); + return 0; } +/* + * STREAMS module close (exit) point + */ MOD_CLOSE(ahdlc_close) { - ahdlc_state_t *state; + ahdlc_state_t *state; qprocsoff(q); - if (q->q_ptr != 0) { - state = (ahdlc_state_t *) q->q_ptr; - if (state->cur_frame != 0) { - freemsg(state->cur_frame); - state->cur_frame = 0; - } - FREE(q->q_ptr, sizeof(ahdlc_state_t)); - q->q_ptr = NULL; - OTHERQ(q)->q_ptr = NULL; - --ppp_ahdlc_count; + + state = (ahdlc_state_t *) q->q_ptr; + + if (state == 0) { + DPRINT("state == 0 in ahdlc_close\n"); + return 0; + } + +#if defined(USE_MUTEX) + mutex_enter(&state->lock); +#endif /* USE_MUTEX */ + + if (state->rx_buf != 0) { + freemsg(state->rx_buf); + state->rx_buf = 0; } + +#if defined(USE_MUTEX) + mutex_exit(&state->lock); + mutex_destroy(&state->lock); +#endif /* USE_MUTEX */ + + FREE(q->q_ptr, sizeof(ahdlc_state_t)); + q->q_ptr = NULL; + OTHERQ(q)->q_ptr = NULL; + return 0; } +/* + * Write side put routine + */ static int ahdlc_wput(q, mp) - queue_t *q; - mblk_t *mp; + queue_t *q; + mblk_t *mp; { - ahdlc_state_t *state; - struct iocblk *iop; - int error; - mblk_t *np; - struct ppp_stats *psp; + ahdlc_state_t *state; + struct iocblk *iop; + int error; + mblk_t *np; + struct ppp_stats *psp; state = (ahdlc_state_t *) q->q_ptr; if (state == 0) { @@ -221,7 +325,7 @@ ahdlc_wput(q, mp) * A data packet - do character-stuffing and FCS, and * send it onwards. */ - stuff_frame(q, mp); + ahdlc_encode(q, mp); freemsg(mp); break; @@ -230,17 +334,24 @@ ahdlc_wput(q, mp) error = EINVAL; switch (iop->ioc_cmd) { case PPPIO_XACCM: - if (iop->ioc_count < sizeof(u_int32_t) - || iop->ioc_count > sizeof(ext_accm)) + if ((iop->ioc_count < sizeof(u_int32_t)) || + (iop->ioc_count > sizeof(ext_accm))) { break; + } if (mp->b_cont == 0) { DPRINT1("ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n", state->unit); break; } +#if defined(USE_MUTEX) + mutex_enter(&state->lock); +#endif /* USE_MUTEX */ bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm, iop->ioc_count); state->xaccm[2] &= ~0x40000000; /* don't escape 0x5e */ state->xaccm[3] |= 0x60000000; /* do escape 0x7d, 0x7e */ +#if defined(USE_MUTEX) + mutex_exit(&state->lock); +#endif /* USE_MUTEX */ iop->ioc_count = 0; error = 0; break; @@ -252,8 +363,14 @@ ahdlc_wput(q, mp) DPRINT1("ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n", state->unit); break; } +#if defined(USE_MUTEX) + mutex_enter(&state->lock); +#endif /* USE_MUTEX */ bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm, sizeof(u_int32_t)); +#if defined(USE_MUTEX) + mutex_exit(&state->lock); +#endif /* USE_MUTEX */ iop->ioc_count = 0; error = 0; break; @@ -267,7 +384,13 @@ ahdlc_wput(q, mp) if (mp->b_cont != 0) freemsg(mp->b_cont); mp->b_cont = np; +#if defined(USE_MUTEX) + mutex_enter(&state->lock); +#endif /* USE_MUTEX */ *(int *)np->b_wptr = state->flags & RCV_FLAGS; +#if defined(USE_MUTEX) + mutex_exit(&state->lock); +#endif /* USE_MUTEX */ np->b_wptr += sizeof(int); iop->ioc_count = sizeof(int); error = 0; @@ -316,15 +439,33 @@ ahdlc_wput(q, mp) case M_CTL: switch (*mp->b_rptr) { case PPPCTL_MTU: +#if defined(USE_MUTEX) + mutex_enter(&state->lock); +#endif /* USE_MUTEX */ state->mtu = ((unsigned short *)mp->b_rptr)[1]; +#if defined(USE_MUTEX) + mutex_exit(&state->lock); +#endif /* USE_MUTEX */ freemsg(mp); break; case PPPCTL_MRU: +#if defined(USE_MUTEX) + mutex_enter(&state->lock); +#endif /* USE_MUTEX */ state->mru = ((unsigned short *)mp->b_rptr)[1]; +#if defined(USE_MUTEX) + mutex_exit(&state->lock); +#endif /* USE_MUTEX */ freemsg(mp); break; case PPPCTL_UNIT: +#if defined(USE_MUTEX) + mutex_enter(&state->lock); +#endif /* USE_MUTEX */ state->unit = mp->b_rptr[1]; +#if defined(USE_MUTEX) + mutex_exit(&state->lock); +#endif /* USE_MUTEX */ break; default: putnext(q, mp); @@ -338,10 +479,13 @@ ahdlc_wput(q, mp) return 0; } +/* + * Read side put routine + */ static int ahdlc_rput(q, mp) queue_t *q; - mblk_t *mp; + mblk_t *mp; { ahdlc_state_t *state; @@ -354,19 +498,23 @@ ahdlc_rput(q, mp) switch (mp->b_datap->db_type) { case M_DATA: - unstuff_chars(q, mp); + ahdlc_decode(q, mp); freemsg(mp); break; case M_HANGUP: - if (state->cur_frame != 0) { +#if defined(USE_MUTEX) + mutex_enter(&state->lock); +#endif /* USE_MUTEX */ + if (state->rx_buf != 0) { /* XXX would like to send this up for debugging */ - freemsg(state->cur_frame); - state->cur_frame = 0; - state->cur_blk = 0; + freemsg(state->rx_buf); + state->rx_buf = 0; } - state->inlen = 0; state->flags = IFLUSH; +#if defined(USE_MUTEX) + mutex_exit(&state->lock); +#endif /* USE_MUTEX */ putnext(q, mp); break; @@ -376,354 +524,311 @@ ahdlc_rput(q, mp) return 0; } -/* Extract bit c from map m, to determine if c needs to be escaped. */ -#define ESCAPE(c, m) ((m)[(c) >> 5] & (1 << ((c) & 0x1f))) +/* + * Extract bit c from map m, to determine if c needs to be escaped + */ +#define IN_TX_MAP(c, m) ((m)[(c) >> 5] & (1 << ((c) & 0x1f))) static void -stuff_frame(q, mp) - queue_t *q; - mblk_t *mp; +ahdlc_encode(q, mp) + queue_t *q; + mblk_t *mp; { - ahdlc_state_t *state; - int ilen, olen, c, extra, code; - mblk_t *omsg, *op, *np; - uchar_t *sp, *sp0, *dp, *dp0, *spend; - ushort_t fcs; - u_int32_t *xaccm, lcp_xaccm[8]; + ahdlc_state_t *state; + u_int32_t *xaccm, loc_xaccm[8]; + ushort_t fcs; + size_t outmp_len; + mblk_t *outmp, *tmp; + uchar_t *dp, fcs_val; + int is_lcp, code; +#if defined(SOL2) + clock_t lbolt; +#endif /* SOL2 */ + + if (msgdsize(mp) < 4) { + return; + } - state = (ahdlc_state_t *) q->q_ptr; - ilen = msgdsize(mp); + state = (ahdlc_state_t *)q->q_ptr; +#if defined(USE_MUTEX) + mutex_enter(&state->lock); +#endif /* USE_MUTEX */ /* - * We estimate the length of the output packet as - * 1.25 * input length + 16 (for initial flag, FCS, final flag, slop). + * Allocate an output buffer large enough to handle a case where all + * characters need to be escaped */ - olen = ilen + (ilen >> 2) + 16; - if (olen > OFRAME_BSIZE) - olen = OFRAME_BSIZE; - omsg = op = allocb(olen, BPRI_MED); - if (omsg == 0) - goto bomb; + outmp_len = (msgdsize(mp) << 1) + /* input block x 2 */ + (sizeof(fcs) << 2) + /* HDLC FCS x 4 */ + (sizeof(uchar_t) << 1); /* HDLC flags x 2 */ + + outmp = allocb(outmp_len, BPRI_MED); + if (outmp == NULL) { + state->stats.ppp_oerrors++; +#if defined(USE_MUTEX) + mutex_exit(&state->lock); +#endif /* USE_MUTEX */ + putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR); + return; + } +#if defined(SOL2) + /* + * Check if our last transmit happenned within flag_time, using + * the system's LBOLT value in clock ticks + */ + if (drv_getparm(LBOLT, &lbolt) != -1) { + if (ABS((clock32_t)lbolt - state->lbolt) > state->flag_time) { + *outmp->b_wptr++ = PPP_FLAG; + } + state->lbolt = lbolt; + } else { + *outmp->b_wptr++ = PPP_FLAG; + } +#else /* - * Put in an initial flag, unless the serial driver currently has - * packets still to be transmitted in its queue. + * If the driver below still has a message to process, skip the + * HDLC flag, otherwise, put one in the beginning */ - dp = op->b_wptr; if (qsize(q->q_next) == 0) { - *dp++ = PPP_FLAG; - --olen; + *outmp->b_wptr++ = PPP_FLAG; } +#endif /* - * For LCP packets with code values between 1 and 7 (Conf-Req - * to Code-Rej), we must escape all control characters. + * All control characters must be escaped for LCP packets with code + * values between 1 (Conf-Req) and 7 (Code-Rej). */ + is_lcp = ((MSG_BYTE(mp, 0) == PPP_ALLSTATIONS) && + (MSG_BYTE(mp, 1) == PPP_UI) && + (MSG_BYTE(mp, 2) == (PPP_LCP >> 8)) && + (MSG_BYTE(mp, 3) == (PPP_LCP & 0xff)) && + LCP_USE_DFLT(mp)); + xaccm = state->xaccm; - if (MSG_BYTE(mp, 0) == PPP_ALLSTATIONS - && MSG_BYTE(mp, 1) == PPP_UI - && MSG_BYTE(mp, 2) == (PPP_LCP >> 8) - && MSG_BYTE(mp, 3) == (PPP_LCP & 0xFF) - && LCP_USE_DFLT(mp)) { - bcopy((caddr_t) state->xaccm, (caddr_t) lcp_xaccm, sizeof(lcp_xaccm)); - lcp_xaccm[0] = ~0; - xaccm = lcp_xaccm; + if (is_lcp) { + bcopy((caddr_t)state->xaccm, (caddr_t)loc_xaccm, sizeof(loc_xaccm)); + loc_xaccm[0] = ~0; /* force escape on 0x00 through 0x1f */ + xaccm = loc_xaccm; } - sp = mp->b_rptr; - fcs = PPP_INITFCS; - for (;;) { - spend = mp->b_wptr; - extra = sp + olen - spend; - if (extra < 0) { - spend = sp + olen; - extra = 0; - } - /* - * We can safely process the input up to `spend' - * without overrunning the output, provided we don't - * hit more than `extra' characters which need to be escaped. - */ - sp0 = sp; - dp0 = dp; - while (sp < spend) { - c = *sp; - if (ESCAPE(c, xaccm)) { - if (extra > 0) - --extra; - else if (sp < spend - 1) - --spend; - else - break; - fcs = PPP_FCS(fcs, c); - *dp++ = PPP_ESCAPE; - c ^= PPP_TRANS; - } else - fcs = PPP_FCS(fcs, c); - *dp++ = c; - ++sp; - } - ilen -= sp - sp0; - olen -= dp - dp0; + fcs = PPP_INITFCS; /* Initial FCS is 0xffff */ - /* - * At this point, we have emptied an input block - * and/or filled an output block. - */ - if (sp >= mp->b_wptr) { - /* - * We've emptied an input block. Advance to the next. - */ - mp = mp->b_cont; - if (mp == 0) - break; /* all done */ - sp = mp->b_rptr; - } - if (olen < 2) { - /* - * The output block is full. Allocate a new one. - */ - op->b_wptr = dp; - olen = 2 * ilen + 5; - if (olen > OFRAME_BSIZE) - olen = OFRAME_BSIZE; - np = allocb(olen, BPRI_MED); - if (np == 0) - goto bomb; - op->b_cont = np; - op = np; - dp = op->b_wptr; + /* + * Process this block and the rest (if any) attached to the this one + */ + for (tmp = mp; tmp; tmp = tmp->b_cont) { + if (tmp->b_datap->db_type == M_DATA) { + for (dp = tmp->b_rptr; dp < tmp->b_wptr; dp++) { + fcs = PPP_FCS(fcs, *dp); + if (IN_TX_MAP(*dp, xaccm)) { + *outmp->b_wptr++ = PPP_ESCAPE; + *outmp->b_wptr++ = *dp ^ PPP_TRANS; + } else { + *outmp->b_wptr++ = *dp; + } + } + } else { + continue; /* skip if db_type is something other than M_DATA */ } } /* - * Append the FCS and closing flag. - * This could require up to 5 characters. + * Append the HDLC FCS, making sure that escaping is done on any + * necessary bytes */ - if (olen < 5) { - /* Sigh. Need another block. */ - op->b_wptr = dp; - np = allocb(5, BPRI_MED); - if (np == 0) - goto bomb; - op->b_cont = np; - op = np; - dp = op->b_wptr; - } - c = ~fcs & 0xff; - if (ESCAPE(c, xaccm)) { - *dp++ = PPP_ESCAPE; - c ^= PPP_TRANS; + fcs_val = (fcs ^ 0xffff) & 0xff; + if (IN_TX_MAP(fcs_val, xaccm)) { + *outmp->b_wptr++ = PPP_ESCAPE; + *outmp->b_wptr++ = fcs_val ^ PPP_TRANS; + } else { + *outmp->b_wptr++ = fcs_val; } - *dp++ = c; - c = (~fcs >> 8) & 0xff; - if (ESCAPE(c, xaccm)) { - *dp++ = PPP_ESCAPE; - c ^= PPP_TRANS; + + fcs_val = ((fcs ^ 0xffff) >> 8) & 0xff; + if (IN_TX_MAP(fcs_val, xaccm)) { + *outmp->b_wptr++ = PPP_ESCAPE; + *outmp->b_wptr++ = fcs_val ^ PPP_TRANS; + } else { + *outmp->b_wptr++ = fcs_val; } - *dp++ = c; - *dp++ = PPP_FLAG; - op->b_wptr = dp; /* - * Update statistics. + * And finally, append the HDLC flag, and send it away */ - state->stats.ppp_obytes += msgdsize(omsg); + *outmp->b_wptr++ = PPP_FLAG; + + state->stats.ppp_obytes += msgdsize(outmp); state->stats.ppp_opackets++; - /* - * Send it on. - */ - putnext(q, omsg); - return; +#if defined(USE_MUTEX) + mutex_exit(&state->lock); +#endif /* USE_MUTEX */ - bomb: - if (omsg != 0) - freemsg(omsg); - state->stats.ppp_oerrors++; - putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR); + putnext(q, outmp); + return; } -#define UPDATE_FLAGS(c) { \ - if ((c) & 0x80) \ - state->flags |= RCV_B7_1; \ - else \ - state->flags |= RCV_B7_0; \ - if (0x6996 & (1 << ((((c) >> 4) ^ (c)) & 0xf))) \ - state->flags |= RCV_ODDP; \ - else \ - state->flags |= RCV_EVNP; \ -} +/* + * Checks the 32-bit receive ACCM to see if the byte needs un-escaping + */ +#define IN_RX_MAP(c, m) ((((unsigned int) (uchar_t) (c)) < 0x20) && \ + (m) & (1 << (c))) /* * Process received characters. */ static void -unstuff_chars(q, mp) +ahdlc_decode(q, mp) queue_t *q; - mblk_t *mp; + mblk_t *mp; { - ahdlc_state_t *state; - mblk_t *om; - uchar_t *cp, *cpend, *dp, *dp0; - int c, len, extra; - ushort_t fcs; + ahdlc_state_t *state; + mblk_t *om, *zmp; + uchar_t *dp; + ushort_t fcs; + + /* + * In case the driver (or something below) doesn't send + * data upstream in one message block, concatenate everything + */ + if (!((mp->b_wptr - mp->b_rptr == msgdsize(mp)) && + ((intptr_t)mp->b_rptr % sizeof(intptr_t) == 0))) { + + zmp = msgpullup(mp, -1); + freemsg(mp); + mp = zmp; + if (mp == 0) + return; + } state = (ahdlc_state_t *) q->q_ptr; + +#if defined(USE_MUTEX) + mutex_enter(&state->lock); +#endif /* USE_MUTEX */ + state->stats.ppp_ibytes += msgdsize(mp); - cp = mp->b_rptr; - for (;;) { + + for (dp = mp->b_rptr; dp < mp->b_wptr; dp++) { + /* - * Advance to next input block if necessary. + * This should detect the lack of 8-bit communication channel + * which is necessary for PPP to work. In addition, it also + * checks on the parity. */ - if (cp >= mp->b_wptr) { - mp = mp->b_cont; - if (mp == 0) - break; - cp = mp->b_rptr; - continue; - } + if (*dp & 0x80) + state->flags |= RCV_B7_1; + else + state->flags |= RCV_B7_0; + + if (paritytab[*dp >> 5] & (1 << (*dp & 0x1f))) + state->flags |= RCV_ODDP; + else + state->flags |= RCV_EVNP; + + /* + * So we have a HDLC flag ... + */ + if (*dp == PPP_FLAG) { - if ((state->flags & (IFLUSH|ESCAPED)) == 0 - && state->inlen > 0 && (om = state->cur_blk) != 0) { /* - * Process bulk chars as quickly as possible. + * If we think that it marks the beginning of the frame, + * then continue to process the next octects */ - dp = om->b_wptr; - len = om->b_datap->db_lim - dp; /* max # output bytes */ - extra = (mp->b_wptr - cp) - len;/* #input chars - #output bytes */ - if (extra < 0) { - len += extra; /* we'll run out of input first */ - extra = 0; - } - cpend = cp + len; - dp0 = dp; - fcs = state->infcs; - while (cp < cpend) { - c = *cp; - if (c == PPP_FLAG) - break; - ++cp; - UPDATE_FLAGS(c); - if (c == PPP_ESCAPE) { - if (extra > 0) { - --extra; - ++cpend; - } - if (cp >= cpend || (c = *cp) == PPP_FLAG) { - state->flags |= ESCAPED; - break; - } - ++cp; - UPDATE_FLAGS(c); - c ^= PPP_TRANS; - } - *dp++ = c; - fcs = PPP_FCS(fcs, c); + if ((state->flags & IFLUSH) || + (state->rx_buf == 0) || + (msgdsize(state->rx_buf) == 0)) { + + state->flags &= ~IFLUSH; + continue; } - state->inlen += dp - dp0; - state->infcs = fcs; - om->b_wptr = dp; - if (cp >= mp->b_wptr) - continue; /* advance to the next mblk */ - } - c = *cp++; - UPDATE_FLAGS(c); - if (c == PPP_FLAG) { /* - * End of a frame. - * If the ESCAPE flag is set, the frame ended with - * the frame abort sequence "}~". + * We get here because the above condition isn't true, + * in which case the HDLC flag was there to mark the end + * of the frame (or so we think) */ - om = state->cur_frame; - len = state->inlen; - state->cur_frame = 0; - state->inlen = 0; - if (len == 0 && (state->flags & IFLUSH) == 0) - continue; - state->stats.ppp_ipackets++; - if (om != 0 && (state->flags & (IFLUSH|ESCAPED)) == 0 - && len > PPP_FCSLEN) { - if (state->infcs == PPP_GOODFCS) { - adjmsg(om, -PPP_FCSLEN); /* chop off fcs */ - putnext(q, om); /* bombs away! */ - continue; - } - DPRINT2("ppp%d: bad fcs (len=%d)\n", state->unit, len); + om = state->rx_buf; + + if (state->infcs == PPP_GOODFCS) { + state->stats.ppp_ipackets++; + adjmsg(om, -PPP_FCSLEN); + putnext(q, om); + } else { + DPRINT2("ppp%d: bad fcs (len=%d)\n", + state->unit, msgdsize(state->rx_buf)); + freemsg(state->rx_buf); + state->flags &= ~(IFLUSH | ESCAPED); + state->stats.ppp_ierrors++; + putctl1(q->q_next, M_CTL, PPPCTL_IERROR); } - if (om != 0) - freemsg(om); - state->flags &= ~(IFLUSH|ESCAPED); - state->stats.ppp_ierrors++; - putctl1(q->q_next, M_CTL, PPPCTL_IERROR); + + state->rx_buf = 0; continue; } - if (state->flags & IFLUSH) - continue; - if (state->flags & ESCAPED) { - c ^= PPP_TRANS; - state->flags &= ~ESCAPED; - } else if (c == PPP_ESCAPE) { - state->flags |= ESCAPED; + if (state->flags & IFLUSH) { continue; } - if (state->inlen == 0) { + + /* + * Allocate a receive buffer, large enough to store a frame (after + * un-escaping) of at least 1500 octets. If MRU is negotiated to + * be more than the default, then allocate that much. In addition, + * we add an extra 32-bytes for a fudge factor + */ + if (state->rx_buf == 0) { + state->rx_buf_size = (state->mru < PPP_MRU ? PPP_MRU : state->mru); + state->rx_buf_size += (sizeof(u_int32_t) << 3); + state->rx_buf = allocb(state->rx_buf_size, BPRI_MED); + /* - * First byte of the frame: allocate the first message block. + * If allocation fails, try again on the next frame */ - om = allocb(IFRAME_BSIZE, BPRI_MED); - if (om == 0) { + if (state->rx_buf == 0) { state->flags |= IFLUSH; continue; } - state->cur_frame = om; - state->cur_blk = om; - state->infcs = PPP_INITFCS; - } else { - om = state->cur_blk; - if (om->b_wptr >= om->b_datap->db_lim) { - /* - * Current message block is full. Allocate another one, - * unless we have run out of MRU. - */ - if (state->inlen >= state->mru + PPP_HDRLEN + PPP_FCSLEN) { - state->flags |= IFLUSH; - DPRINT2("ppp%d: frame too long (%d)\n", - state->unit, state->inlen); - continue; - } - om = allocb(IFRAME_BSIZE, BPRI_MED); - if (om == 0) { - state->flags |= IFLUSH; - continue; - } - state->cur_blk->b_cont = om; - state->cur_blk = om; - } + state->flags &= ~(IFLUSH | ESCAPED); + state->infcs = PPP_INITFCS; } - if (state->inlen == 0) { - /* - * We don't do address/control & protocol decompression here, - * but we try to put the first byte at an offset such that - * the info field starts on a word boundary. The code here - * will do this except for packets with protocol compression - * but not address/control compression. - */ - if (c != PPP_ALLSTATIONS) { - om->b_wptr += 2; - if (c & 1) - ++om->b_wptr; - om->b_rptr = om->b_wptr; - } + if (*dp == PPP_ESCAPE) { + state->flags |= ESCAPED; + continue; } - *om->b_wptr++ = c; - ++state->inlen; - state->infcs = PPP_FCS(state->infcs, c); + /* + * Make sure we un-escape the necessary characters, as well as the + * ones in our receive async control character map + */ + if (state->flags & ESCAPED) { + *dp ^= PPP_TRANS; + state->flags &= ~ESCAPED; + } else if (IN_RX_MAP(*dp, state->raccm)) + continue; + + /* + * Unless the peer lied to us about the negotiated MRU, we should + * never get a frame which is too long. If it happens, toss it away + * and grab the next incoming one + */ + if (msgdsize(state->rx_buf) < state->rx_buf_size) { + state->infcs = PPP_FCS(state->infcs, *dp); + *state->rx_buf->b_wptr++ = *dp; + } else { + DPRINT2("ppp%d: frame too long (%d)\n", + state->unit, msgdsize(state->rx_buf)); + freemsg(state->rx_buf); + state->rx_buf = 0; + state->flags |= IFLUSH; + } } + +#if defined(USE_MUTEX) + mutex_exit(&state->lock); +#endif /* USE_MUTEX */ } static int -- 2.39.2