/*
* spppasyn.c - STREAMS module for doing PPP asynchronous HDLC.
*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* 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.
*
* 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. This software is provided without any
* warranty, express or implied. The Australian National University
* makes no representations about the suitability of this software for
* any purpose.
*
* IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
* PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
* THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
* OR MODIFICATIONS.
*
* $Id: ppp_ahdlc.c,v 1.16 2000/03/06 19:38:12 masputra Exp $
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <net/ppp_defs.h>
#include "s_common.h"
#ifdef DEBUG
#define REPORT_CRC_TYPE
#endif
#include "spppasyn.h"
/*
* This is used to tag official Solaris sources. Please do not define
* "INTERNAL_BUILD" when building this software outside of Sun
* Microsystems.
*/
#ifdef INTERNAL_BUILD
/* MODINFO is limited to 32 characters. */
#else /* INTERNAL_BUILD */
/* LINTED */
#ifdef DEBUG
" DEBUG"
#endif
"\n";
#endif /* INTERNAL_BUILD */
static void spppasyn_timer(void *);
#define RESET_MUX_VALUES(x) { \
x->sa_proto = 0; \
x->sa_mqlen = 0; \
}
#define IS_XMUX_ENABLED(x) \
#define IS_RMUX_ENABLED(x) \
#define IS_COMP_AC(x) \
((x)->sa_flags & SAF_XCOMP_AC)
#define IS_COMP_PROT(x) \
((x)->sa_flags & SAF_XCOMP_PROT)
#define IS_DECOMP_PROT(x) \
((x)->sa_flags & SAF_RDECOMP_PROT)
/*
* Don't send HDLC start flag if last transmit is within 1.5 seconds -
* FLAG_TIME is defined in nanoseconds.
*/
/*
* The usual AHDLC implementation enables the default escaping for all
* LCP frames. LCP_USE_DFLT() is used in this implementation to
* modify this rule slightly. If the code number happens to be
* Echo-Request, Echo-Reply, or Discard-Request (each of which may be
* sent only when LCP is in Opened state), then one may also use the
* negotiated ACCM; the RFC is silent on this. The theory is that
* pppd can construct Echo-Request messages that are guaranteed to
* fail if the negotiated ACCM is bad.
*/
/*
* Extract bit c from map m, to determine if character c needs to be
* escaped. Map 'm' is a pointer to a 256 bit map; 8 words of 32 bits
* each.
*/
#define IN_TX_MAP(c, m) \
((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
/*
* Checks the 32-bit receive ACCM to see if the byte should have been
* escaped by peer.
*/
AHDLC_MOD_ID, /* mi_idnum */
AHDLC_MOD_NAME, /* mi_idname */
0, /* mi_minpsz */
INFPSZ, /* mi_maxpsz */
0, /* mi_hiwat */
0 /* mi_lowat */
};
spppasyn_rput, /* qi_putp */
NULL, /* qi_srvp */
spppasyn_open, /* qi_qopen */
spppasyn_close, /* qi_qclose */
NULL, /* qi_qadmin */
&spppasyn_modinfo, /* qi_minfo */
NULL /* qi_mstat */
};
spppasyn_wput, /* qi_putp */
NULL, /* qi_srvp */
NULL, /* qi_qopen */
NULL, /* qi_qclose */
NULL, /* qi_qadmin */
&spppasyn_modinfo, /* qi_minfo */
NULL /* qi_mstat */
};
&spppasyn_rinit, /* st_rdinit */
&spppasyn_winit, /* st_wrinit */
NULL, /* st_muxrinit */
NULL, /* st_muxwinit */
};
/* Matches above structure. */
static const char *kstat_names[] = {
"ioctls", "ioctlsfwd", "ioctlserr", "ctls",
"ctlsfwd", "ctlserr", "inbadchars", "inbadcharmask",
"inaborts", "inrunts", "inallocfails", "intoolongs",
"outrunts", "outallocfails", "incrcerrs", "unknownwrs",
"unknownrds", "hangups", "datain", "dataout",
"extrabufs", "sentmux", "recvmux", "inmuxerrs",
#ifdef REPORT_CRC_TYPE
"incrctype", "outcrctype",
#endif
};
/* So. This is why we have optimizing compilers. */
const char *msg);
/*
*/
/*
* FCS lookup table as calculated by genfcstab.
*/
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
/*
* Per-character flags for accumulating input errors. Flags are
* accumulated for bit 7 set to 0, bit 7 set to 1, even parity
* characters, and odd parity characters. The link should see all
* four in the very first LCP Configure-Request if all is ok. (C0 is
* even parity and has bit 7 set to 1, and 23 is odd parity and has
* bit 7 set to 0.)
*/
};
/*
* Append two lists; preserve message boundaries.
* Warning: uses b_next.
*/
static mblk_t *
{
return (m2);
return (m1);
return (mret);
}
/*
* Concatenate two mblk lists.
*/
static mblk_t *
{
return (m2);
return (m1);
return (mret);
}
/*
* spppasyn_open()
*
* STREAMS module open (entry) point. Called when spppasyn is pushed
* onto an asynchronous serial stream.
*/
/* ARGSUSED */
static int
{
return (0); /* return if already opened */
}
return (EINVAL); /* only open as a module */
}
qprocson(q);
return (0);
}
/*
* spppasyn_close()
*
* STREAMS module close (exit) point
*/
/* ARGSUSED */
static int
{
/* We're leaving now. No more calls, please. */
qprocsoff(q);
}
}
/* remove the time out routine */
if (state->sa_timeout_id != 0)
return (0);
}
/*
* Create the standard kernel statistics structure and attach it to
* the current state structure. This can be called only after
* assigning the unit number.
*/
static void
{
int nstat, i;
#ifdef DEBUG
/* Just in case I do something silly here. */
if (i >= sizeof (kstat_names) / sizeof (kstat_names[0]))
else
#endif
}
/*
* sprintf is known to be safe here because KSTAT_STRLEN is
* 31, the maximum module name length is 8, and the maximum
* string length from %d is 11. This was once snprintf, but
* that's not backward-compatible with Solaris 2.6.
*/
}
#ifdef REPORT_CRC_TYPE
#endif
}
/*
* spppasyn_inner_ioctl
*
* MT-Perimeters:
* exclusive inner
*
* Handle state-affecting ioctls.
*/
static void
{
int error;
int flagval;
int len;
int flagmask;
len = 0;
case PPPIO_XFCS:
/* Check for valid option length */
break;
/* Grab flag value */
break;
#ifdef REPORT_CRC_TYPE
#endif
} else if (flagval == PPPFCS_NONE) {
#ifdef REPORT_CRC_TYPE
KSET(pks_outcrctype, 0);
#endif
}
#ifdef REPORT_CRC_TYPE
else {
}
#endif
/* Return success */
error = 0;
break;
case PPPIO_RFCS:
/* Check for valid option length */
break;
/* Grab flag value */
break;
#ifdef REPORT_CRC_TYPE
#endif
} else if (flagval == PPPFCS_NONE) {
#ifdef REPORT_CRC_TYPE
KSET(pks_incrctype, 0);
#endif
}
#ifdef REPORT_CRC_TYPE
else {
}
#endif
/* Return success */
error = 0;
break;
case PPPIO_XACCM:
/* Check for valid asyncmap length */
break;
/* Copy user's asyncmap into our state structure. */
error = 0;
break;
case PPPIO_RACCM:
/* Check for valid asyncmap length (only ctrl chars) */
break;
error = 0;
break;
case PPPIO_LASTMOD:
/* We already know this. */
error = 0;
break;
case PPPIO_MUX:
/* set the compression flags */
break;
/* set the mux flags */
if (mux_flags != 0)
/* set the multiplexing timer value */
error = 0;
break;
case PPPIO_CFLAGS:
break;
error = 0;
break;
case PPPIO_DEBUG:
break;
return;
}
error = 0;
break;
}
if (error == 0) {
/* Success; tell the user */
len = 0;
else
} else {
/* Failure; send error back upstream. */
}
}
/*
* spppasyn_inner_mctl
*
* MT-Perimeters:
* exclusive inner
*
* Handle state-affecting M_CTL messages.
*/
static void
{
int msglen;
int error;
error = 0;
case PPPCTL_MTU:
/* Just ignore the MTU */
break;
case PPPCTL_MRU:
if (msglen != 4)
else
break;
case PPPCTL_UNIT:
break;
}
if (msglen == 2)
else if (msglen == 8)
else
break;
}
if (error > 0) {
}
} else {
}
}
/*
* spppasyn_wput()
*
* MT-Perimeters:
* exclusive inner.
*
* Write side put routine. This called by the modules above us (likely to
* be the compression module) to transmit data or pass along ioctls.
*/
static int
{
int error;
int msglen;
case M_DATA:
/*
* A data packet - do character-stuffing and FCS, and
* send it onwards. The blocks are freed as we go.
*/
if (IS_XMUX_ENABLED(state))
else
break;
case M_IOCTL:
msglen = 0;
case PPPIO_XFCS:
case PPPIO_RFCS:
case PPPIO_XACCM:
case PPPIO_RACCM:
case PPPIO_LASTMOD:
case PPPIO_DEBUG:
case PPPIO_MUX:
case PPPIO_CFLAGS:
spppasyn_inner_ioctl(q, mp);
return (0);
case PPPIO_GCLEAN:
break;
}
}
error = 0;
break;
case PPPIO_GETSTAT:
break;
case PPPIO_GETSTAT64:
break;
}
}
error = 0;
break;
case PPPIO_GTYPE:
break;
}
}
error = 0;
break;
default:
/* Unknown ioctl -- forward along */
return (0);
}
if (error == 0) {
/* Success; tell the user */
} else {
/* Failure; send error back upstream. */
}
break;
case M_CTL:
spppasyn_inner_mctl(q, mp);
break;
default:
"spppasyn_wpur: unknown buffer type %d",
break;
}
return (0);
}
/*
* spppasyn_rput()
*
* MT-Perimeters:
* exclusive inner.
*
* Read side put routine. This is called by the async serial driver
* below us to handle received data and returned signals (like
* hang-up).
*/
static int
{
case M_DATA:
/* Note -- decoder frees the buffers */
}
break;
case M_HANGUP:
break;
default:
"spppasyn_rput: unexpected ioctl %X",
else
"spppasyn_rput: unknown buffer type %d",
}
break;
}
return (0);
}
/*
* ahdlc_encode
*
* Perform asynchronous HDLC framing on a given buffer and transmit
* the result. The state structure must be valid. The input buffers
* are freed as we go.
*
* This function is called by wput and just encodes the data. Wput
* then calls putnext directly. There's no service routine for this
* module, so flow control is asserted by the module below us up to
* our caller by the STREAMS framework. This is by design -- this
* module does not queue anything so that other modules can make QoS
* decisions.
*/
static mblk_t *
{
#else
/* with WorkShop compiler */
#endif
int code;
/* Don't transmit anything obviously silly. */
if (msglen < 4) {
return (NULL);
}
/*
* Allocate an output buffer just large enough for most cases.
* Based on original work in the ppp-2.2 AIX PPP driver, we
* estimate the output size as 1.25 * input message length
* plus 16. If this turns out to be too small, then we'll
* allocate exactly one additional buffer with two times the
* remaining input length (the maximum that could possibly be
* required).
*/
goto outallocfail;
/*
* Check if our last transmit happened within FLAG_TIME, using
* the system's hrtime.
*/
}
/*
* LCP messages must be sent using the default escaping
* (ACCM). We bend this rule a little to allow LCP
* Echo-Request through with the negotiated escaping so that
* we can detect bad negotiated ACCM values. If the ACCM is
* bad, echos will fail and take down the link.
*/
if (code == PPP_ALLSTATIONS) {
if (LCP_USE_DFLT(mp))
is_lcp = 2;
else
is_ctrl = 1;
}
is_ctrl = 1;
/*
* If it's LCP and not just an LCP Echo-Request, then we need
* to drop back to default escaping rules temporarily.
*/
if (is_lcp > 1) {
/*
* force escape on 0x00 through 0x1f
* and, for RFC 1662 (and ISO 3309:1991), 0x80-0x9f.
*/
loc_xaccm[0] = 0xffffffff;
}
/*
* Process this block and the rest (if any) attached to this
* one. Note that we quite intentionally ignore the type of
* the buffer. The caller has checked that the first buffer
* is M_DATA; all others must be so, and any that are not are
* harmless driver errors.
*/
do {
/*
* Calculate maximum safe run length for inner loop,
* regardless of escaping.
*/
/*
* Select out on CRC type here to make the
* inner byte loop more efficient. (We could
* do both CRCs at all times if we wanted, but
* that ends up taking an extra 8 cycles per
* byte -- 47% overhead!)
*/
if (flags & SAF_XMITCRC32) {
*tp++ = PPP_ESCAPE;
}
}
} else {
*tp++ = PPP_ESCAPE;
}
}
}
/*
* If we limited our run length and we're now low
* on output space, then allocate a new output buffer.
* This should rarely happen, unless the output data
* has a lot of escapes.
*/
/* Get remaining message length */
/* Calculate maximum required space */
goto outallocfail;
}
}
/*
* Make sure we have enough remaining room to add the CRC (if
* any) and a trailing flag byte.
*/
goto outallocfail;
}
/*
* Network layer data is the only thing that can be sent with
* no CRC at all.
*/
goto nocrc;
if (!(flags & SAF_XMITCRC32))
/*
* Append the HDLC FCS, making sure that escaping is done on any
* necessary bytes. Note that the FCS bytes are in little-endian.
*/
*tp++ = PPP_ESCAPE;
}
*tp++ = PPP_ESCAPE;
}
if (flags & SAF_XMITCRC32) {
*tp++ = PPP_ESCAPE;
}
*tp++ = PPP_ESCAPE;
}
}
/*
* And finally append the HDLC flag, and send it away
*/
return (outmp);
return (NULL);
}
/*
* Handle end-of-frame excitement. This is here mostly because the Solaris
* C style rules require tab for indent and prohibit excessive indenting.
*/
static mblk_t *
{
int i;
cp += 2;
if ((proto & 1) == 0)
/*
* To allow for renegotiation, LCP accepts good CRCs of either
* type at any time. Other control (non-network) packets must
* have either CRC-16 or CRC-32, as negotiated. Network layer
* packets may additionally omit the CRC entirely, if that was
* negotiated.
*/
(fcs32 == PPPGOODFCS32 &&
if (is_lcp) {
} else {
crclen = 0;
}
if (crclen != 0) {
ASSERT(i != 0);
/* lint is happier this way in a non-DEBUG build */
i = i;
#endif
}
/* spppasyn_inpkt checks for PPP_MUX packets */
/* Remove headers */
return (spppasyn_inpkt(q, outmp));
}
/*
* Sniff the received data stream. If we see an LCP
* Configure-Ack, then pick out the ACCM setting, if
* any, and configure now. This allows us to stay in
* sync in case the peer is already out of Establish
* phase.
*/
cp += 4;
i = 2;
cp[5];
break;
}
cp += i;
}
}
return (outmp);
} else {
return (NULL);
}
}
/*
* ahdlc_decode()
*
* Process received characters.
*
* This is handled as exclusive inner so that we don't get confused
* about the state. Returns a list of packets linked by b_next.
*/
static mblk_t *
{
#else
/* with WorkShop compiler */
#endif
#ifdef HANDLE_ZERO_LENGTH
#endif
} else {
}
#ifdef HANDLE_ZERO_LENGTH
nprocessed = 0;
#endif
/*
* Main input processing loop. Loop over received buffers and
* each byte in each buffer. Note that we quite intentionally
* ignore the type of the buffer. The caller has checked that
* the first buffer is M_DATA; all others must be so, and any
* that are not are harmless driver errors.
*/
/* Innermost loop -- examine bytes in buffer. */
#ifdef HANDLE_ZERO_LENGTH
#endif
/*
* This should detect the lack of an 8-bit
* communication channel, which is necessary
* for PPP to work.
*/
/*
* So we have a HDLC flag ...
*/
/*
* If there's no received buffer, then
* just ignore this frame marker.
*/
continue;
}
/*
* Per RFC 1662 -- silently discard
* runt frames (fewer than 4 octets
* with 16 bit CRC) and frames that
* end in 7D 7E (abort sequence).
* These are not counted as errors.
*
* (We could just reset the pointers
* and reuse the buffer, but this is a
* rarely used error path and not
* worth the optimization.)
*/
if ((flagtmp & SAF_ESCAPED) ||
if (flagtmp & SAF_ESCAPED)
else
"runt");
}
flagtmp &= ~SAF_ESCAPED;
} else {
/* Handle the received frame */
fcs32);
}
continue;
}
/* If we're waiting for a new frame, then drop data. */
if (flagtmp & SAF_IFLUSH) {
continue;
}
/*
* Start of new frame. Allocate a receive
* buffer large enough to store a frame (after
* un-escaping) of at least 1500 octets plus
* the CRC. 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, in case the peer doesn't do
* arithmetic very well.
*/
int maxlen;
/*
* If allocation fails, try again on
* the next frame. (Go into discard
* mode.)
*/
flagtmp |= SAF_IFLUSH;
continue;
}
/* Neither flag can possibly be set here. */
}
/*
* If the peer sends us a character that's in
* our receive character map, then that's
* junk. Discard it without changing state.
* If he previously sent us an escape
* character, then toggle this one and
* continue. Otherwise, if he's now sending
* escape, set the flag for next time.
*/
continue;
}
if (flagtmp & SAF_ESCAPED) {
flagtmp &= ~SAF_ESCAPED;
} else if (chr == PPP_ESCAPE) {
flagtmp |= SAF_ESCAPED;
continue;
}
/*
* Unless the peer is confused about the
* negotiated MRU, we should never get a frame
* that is too long. If it happens, toss it
* away and begin discarding data until we see
* the end of the frame.
*/
} else {
"%d: frame too long (%d bytes)\n",
flagtmp |= SAF_IFLUSH;
}
}
/*
* Free the buffer we just processed and move on to
* the next one.
*/
}
#ifdef HANDLE_ZERO_LENGTH
if (nprocessed <= 0) {
}
}
#endif
return (retmp);
}
/*
* Nifty packet dumper; copied from AIX 4.1 port. This routine dumps
* the raw received and transmitted data through syslog. This allows
* debug of communications problems without resorting to a line
* analyzer.
*
* The expression "3*BYTES_PER_LINE" used frequently here represents
* the size of each hex value printed -- two hex digits and a space.
*/
static void
{
/*
* Buffer is big enough for hex digits, two spaces, ASCII output,
* and one NUL byte.
*/
int i, chr;
char *bp;
i = 0;
/* Add filler spaces between hex output and ASCII */
/* Add NUL byte at end */
/* convert byte to ascii hex */
*bp++ = ' ';
/* Insert ASCII past hex output and filler */
i++;
if (i >= BYTES_PER_LINE) {
buf);
i = 0;
}
}
}
/* fill over unused hex display positions */
*bp++ = ' ';
/* terminate ASCII string at right position */
}
}
static mblk_t *
{
ushort_t i;
i = 0;
protolen = 1;
if (proto == PPP_ALLSTATIONS) {
len -= 2;
i += 2;
}
++i;
if ((proto & 1) == 0) {
protolen++;
}
hdrlen = i - 1;
send_frame = NULL;
/* send the queued frames */
/* increment counter if it is MUX pkt */
}
/* send the current frame */
/* reset the state values over here */
return (send_frame);
}
/* len + 1 , since we add the mux overhead */
/* subtract the protocol length if protocol matches */
send_frame = NULL;
/* send the existing queued frames */
/* increment counter if it is MUX pkt */
}
/* reset state values */
}
/* add the current frame to the queue */
/*
* this is the first mblk in the queue create
* a new frame to hold the PPP MUX header
*/
return (send_frame);
}
if (!IS_COMP_AC(state)) {
/* add the header */
}
/* do protocol compression */
if (IS_COMP_PROT(state)) {
} else {
}
return (send_frame);
}
}
/* point mqtail to the last mblk_t */
/* change state->sa_mqhead */
}
/* Check if the mblk_t is being referenced */
return (send_frame);
}
}
/*
* match,can remove the protocol field
* and write data there
*/
/*
* protolen - 1 ,because the the byte with
* the PFF bit and the length field have
* to added
*/
} else {
/*
* no match, there are three options
* 1. write in mp
* 2. write in mqtail
* 3. alloc a new blk for just one byte
*/
/* Check if the mblk_t is being referenced */
return (send_frame);
}
}
if (hdrlen != 0) {
} else {
/* allocate a new mblk & add the byte */
/* write the data */
== NULL) {
return (send_frame);
}
}
/* update proto */
}
} else {
}
if (state->sa_timeout_id == 0) {
}
return (send_frame);
}
/*
* Called from receive frame, this routine checks if it is a PPP_MUX
* packet and demuxes it. The returned pointer is a chain of mblks
* using b_next and representing the demultiplexed packets.
*/
static mblk_t *
{
return (NULL);
}
/* initialise the Last protocol and protocol length */
prev_proto = 0;
/*
* Taking into granted that the decoded frame is contiguous
*/
/*
* get the last protocol, protocol length
* and the length of the message
*/
/* protocol field flag and length */
/* check if there and enough bytes left in pkt */
break;
}
/* allocate memory for the header length */
break;
}
/* add the ppp header to the pkt */
/* check if the protocol field flag is set */
/* get the protocol */
if ((proto & 1) == 0)
/* reset values */
prev_proto = proto;
} else {
if (!IS_DECOMP_PROT(state))
}
/* get the payload from the MUXed packet */
/* link the subframe to the new frame */
/* do a putnext */
/* move the read pointer beyond this subframe */
}
return (retmp);
}
/*
* timer routine which sends out the queued pkts *
*/
static void
{
queue_t *q;
/* increment counter */
/* reset the state values over here */
}
/* clear timeout_id */
state->sa_timeout_id = 0;
}