Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / ppp / spppasyn / spppasyn.c
blobdb7db4a0f98c098df88b1b1ca680d72dd33befda
1 /*
2 * spppasyn.c - STREAMS module for doing PPP asynchronous HDLC.
4 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
5 * Use is subject to license terms.
6 * Copyright (c) 2016 by Delphix. All rights reserved.
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation is hereby granted, provided that the above copyright
10 * notice appears in all copies.
12 * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
13 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
14 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
15 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
16 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
17 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
19 * Copyright (c) 1994 The Australian National University.
20 * All rights reserved.
22 * Permission to use, copy, modify, and distribute this software and its
23 * documentation is hereby granted, provided that the above copyright
24 * notice appears in all copies. This software is provided without any
25 * warranty, express or implied. The Australian National University
26 * makes no representations about the suitability of this software for
27 * any purpose.
29 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
30 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
31 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
32 * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
33 * OF SUCH DAMAGE.
35 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
36 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
37 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
38 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
39 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
40 * OR MODIFICATIONS.
42 * $Id: ppp_ahdlc.c,v 1.16 2000/03/06 19:38:12 masputra Exp $
45 #pragma ident "%Z%%M% %I% %E% SMI"
47 #include <sys/types.h>
48 #include <sys/param.h>
49 #include <sys/stream.h>
50 #include <sys/strsun.h>
51 #include <sys/sysmacros.h>
52 #include <sys/errno.h>
53 #include <sys/conf.h>
54 #include <sys/kmem.h>
55 #include <sys/crc32.h>
56 #include <sys/cmn_err.h>
57 #include <sys/ddi.h>
59 #include <net/ppp_defs.h>
60 #include <net/pppio.h>
62 #include "s_common.h"
64 #ifdef DEBUG
65 #define REPORT_CRC_TYPE
66 #endif
67 #include "spppasyn.h"
70 * This is used to tag official Solaris sources. Please do not define
71 * "INTERNAL_BUILD" when building this software outside of Sun
72 * Microsystems.
74 #ifdef INTERNAL_BUILD
75 /* MODINFO is limited to 32 characters. */
76 const char spppasyn_module_description[] = "PPP 4.0 AHDLC";
77 #else /* INTERNAL_BUILD */
78 const char spppasyn_module_description[] = "ANU PPP AHDLC $Revision: 1.16$";
80 /* LINTED */
81 static const char buildtime[] = "Built " __DATE__ " at " __TIME__
82 #ifdef DEBUG
83 " DEBUG"
84 #endif
85 "\n";
86 #endif /* INTERNAL_BUILD */
88 static int spppasyn_open(queue_t *, dev_t *, int, int, cred_t *);
89 static int spppasyn_close(queue_t *, int, cred_t *);
90 static int spppasyn_wput(queue_t *, mblk_t *);
91 static int spppasyn_rput(queue_t *, mblk_t *);
92 static mblk_t *ahdlc_encode(queue_t *, mblk_t *);
93 static mblk_t *ahdlc_decode(queue_t *, mblk_t *);
94 static void spppasyn_timer(void *);
95 static mblk_t *spppasyn_inpkt(queue_t *, mblk_t *);
96 static mblk_t *spppasyn_muxencode(queue_t *, mblk_t *);
98 #define RESET_MUX_VALUES(x) { \
99 x->sa_mqhead = x->sa_mqtail = NULL; \
100 x->sa_proto = 0; \
101 x->sa_mqlen = 0; \
103 #define IS_XMUX_ENABLED(x) \
104 ((x)->sa_flags & X_MUXMASK)
105 #define IS_RMUX_ENABLED(x) \
106 ((x)->sa_flags & R_MUXMASK)
107 #define IS_COMP_AC(x) \
108 ((x)->sa_flags & SAF_XCOMP_AC)
109 #define IS_COMP_PROT(x) \
110 ((x)->sa_flags & SAF_XCOMP_PROT)
111 #define IS_DECOMP_PROT(x) \
112 ((x)->sa_flags & SAF_RDECOMP_PROT)
115 * Don't send HDLC start flag if last transmit is within 1.5 seconds -
116 * FLAG_TIME is defined in nanoseconds.
118 #define FLAG_TIME 1500000000ul
121 * The usual AHDLC implementation enables the default escaping for all
122 * LCP frames. LCP_USE_DFLT() is used in this implementation to
123 * modify this rule slightly. If the code number happens to be
124 * Echo-Request, Echo-Reply, or Discard-Request (each of which may be
125 * sent only when LCP is in Opened state), then one may also use the
126 * negotiated ACCM; the RFC is silent on this. The theory is that
127 * pppd can construct Echo-Request messages that are guaranteed to
128 * fail if the negotiated ACCM is bad.
130 #define LCP_USE_DFLT(mp) ((code = MSG_BYTE((mp), 4)) < 9 || code > 11)
133 * Extract bit c from map m, to determine if character c needs to be
134 * escaped. Map 'm' is a pointer to a 256 bit map; 8 words of 32 bits
135 * each.
137 #define IN_TX_MAP(c, m) \
138 ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
141 * Checks the 32-bit receive ACCM to see if the byte should have been
142 * escaped by peer.
144 #define IN_RX_MAP(c, m) (((c) < 0x20) && ((m) & (1 << (c))))
146 static struct module_info spppasyn_modinfo = {
147 AHDLC_MOD_ID, /* mi_idnum */
148 AHDLC_MOD_NAME, /* mi_idname */
149 0, /* mi_minpsz */
150 INFPSZ, /* mi_maxpsz */
151 0, /* mi_hiwat */
152 0 /* mi_lowat */
155 static struct qinit spppasyn_rinit = {
156 spppasyn_rput, /* qi_putp */
157 NULL, /* qi_srvp */
158 spppasyn_open, /* qi_qopen */
159 spppasyn_close, /* qi_qclose */
160 NULL, /* qi_qadmin */
161 &spppasyn_modinfo, /* qi_minfo */
162 NULL /* qi_mstat */
165 static struct qinit spppasyn_winit = {
166 spppasyn_wput, /* qi_putp */
167 NULL, /* qi_srvp */
168 NULL, /* qi_qopen */
169 NULL, /* qi_qclose */
170 NULL, /* qi_qadmin */
171 &spppasyn_modinfo, /* qi_minfo */
172 NULL /* qi_mstat */
175 struct streamtab spppasyn_tab = {
176 &spppasyn_rinit, /* st_rdinit */
177 &spppasyn_winit, /* st_wrinit */
178 NULL, /* st_muxrinit */
179 NULL, /* st_muxwinit */
182 /* Matches above structure. */
183 static const char *kstat_names[] = {
184 "ioctls", "ioctlsfwd", "ioctlserr", "ctls",
185 "ctlsfwd", "ctlserr", "inbadchars", "inbadcharmask",
186 "inaborts", "inrunts", "inallocfails", "intoolongs",
187 "outrunts", "outallocfails", "incrcerrs", "unknownwrs",
188 "unknownrds", "hangups", "datain", "dataout",
189 "extrabufs", "sentmux", "recvmux", "inmuxerrs",
190 #ifdef REPORT_CRC_TYPE
191 "incrctype", "outcrctype",
192 #endif
195 /* So. This is why we have optimizing compilers. */
196 #define KVAL(vn) state->sa_kstats.vn.value.ui32
197 #define KSET(vn, v) KVAL(vn) = (v)
198 #define KADD(vn, v) KSET(vn, KVAL(vn) + (v))
199 #define KOR(vn, v) KSET(vn, KVAL(vn) | (v))
200 #define KINCR(vn) KADD(vn, 1)
202 static void ppp_dump_frame(sppp_ahdlc_t *state, mblk_t *mptr,
203 const char *msg);
206 * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also.
208 #define RCV_FLAGS (RCV_B7_1 | RCV_B7_0 | RCV_ODDP | RCV_EVNP)
211 * FCS lookup table as calculated by genfcstab.
213 static ushort_t fcstab[256] = {
214 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
215 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
216 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
217 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
218 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
219 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
220 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
221 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
222 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
223 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
224 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
225 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
226 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
227 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
228 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
229 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
230 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
231 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
232 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
233 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
234 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
235 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
236 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
237 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
238 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
239 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
240 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
241 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
242 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
243 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
244 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
245 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
249 * Per-character flags for accumulating input errors. Flags are
250 * accumulated for bit 7 set to 0, bit 7 set to 1, even parity
251 * characters, and odd parity characters. The link should see all
252 * four in the very first LCP Configure-Request if all is ok. (C0 is
253 * even parity and has bit 7 set to 1, and 23 is odd parity and has
254 * bit 7 set to 0.)
256 static uchar_t charflags[256] = {
257 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
258 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
259 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
260 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
261 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
262 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
263 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
264 RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
265 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
266 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
267 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
268 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
269 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
270 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
271 RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
272 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
273 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
274 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
275 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
276 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
277 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
278 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
279 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
280 RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
281 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
282 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
283 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
284 RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
285 RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP,
286 RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
287 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
288 RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
289 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
290 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
291 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
292 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP,
293 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
294 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
295 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
296 RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
297 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
298 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
299 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_1|RCV_ODDP,
300 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
301 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
302 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
303 RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
304 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
305 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
306 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
307 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
308 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
309 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
310 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
311 RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
312 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
313 RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP,
314 RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
315 RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
316 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
317 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
318 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
319 RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
320 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
321 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
322 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
323 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
324 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
325 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
326 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
327 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
328 RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
329 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
330 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
331 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
332 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
333 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
334 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
335 RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
336 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
337 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
338 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
339 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
340 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
341 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
342 RCV_B7_1|RCV_EVNP
346 * Append two lists; preserve message boundaries.
347 * Warning: uses b_next.
349 static mblk_t *
350 sppp_mappend(mblk_t *m1, mblk_t *m2)
352 mblk_t *mret;
354 if (m1 == NULL)
355 return (m2);
356 if (m2 == NULL)
357 return (m1);
359 mret = m1;
360 while (m1->b_next != NULL)
361 m1 = m1->b_next;
362 m1->b_next = m2;
363 return (mret);
367 * Concatenate two mblk lists.
369 static mblk_t *
370 sppp_mcat(mblk_t *m1, mblk_t *m2)
372 mblk_t *mret;
374 if (m1 == NULL)
375 return (m2);
376 if (m2 == NULL)
377 return (m1);
379 mret = m1;
380 while (m1->b_cont != NULL)
381 m1 = m1->b_cont;
382 m1->b_cont = m2;
383 return (mret);
387 * spppasyn_open()
389 * STREAMS module open (entry) point. Called when spppasyn is pushed
390 * onto an asynchronous serial stream.
392 /* ARGSUSED */
393 static int
394 spppasyn_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
396 sppp_ahdlc_t *state;
398 ASSERT(q != NULL);
400 if (q->q_ptr != NULL) {
401 return (0); /* return if already opened */
404 if (sflag != MODOPEN) {
405 return (EINVAL); /* only open as a module */
408 state = (sppp_ahdlc_t *)kmem_zalloc(sizeof (sppp_ahdlc_t), KM_SLEEP);
409 ASSERT(state != NULL);
411 q->q_ptr = (caddr_t)state;
412 WR(q)->q_ptr = (caddr_t)state;
414 state->sa_xaccm[0] = 0xffffffff; /* escape 0x00 through 0x1f */
415 state->sa_xaccm[3] = 0x60000000; /* escape 0x7d and 0x7e */
416 state->sa_mru = PPP_MRU; /* default of 1500 bytes */
418 qprocson(q);
420 return (0);
424 * spppasyn_close()
426 * STREAMS module close (exit) point
428 /* ARGSUSED */
429 static int
430 spppasyn_close(queue_t *q, int flag, cred_t *credp)
432 sppp_ahdlc_t *state;
434 ASSERT(q != NULL);
435 state = (sppp_ahdlc_t *)q->q_ptr;
436 ASSERT(state != NULL);
438 /* We're leaving now. No more calls, please. */
439 qprocsoff(q);
441 if (state->sa_rx_buf != NULL) {
442 freemsg(state->sa_rx_buf);
443 state->sa_rx_buf = NULL;
446 if (state->sa_ksp != NULL) {
447 kstat_delete(state->sa_ksp);
448 state->sa_ksp = NULL;
451 if (state->sa_mqhead != NULL)
452 freemsg(state->sa_mqhead);
453 /* remove the time out routine */
454 if (state->sa_timeout_id != 0)
455 (void) quntimeout(q, state->sa_timeout_id);
457 q->q_ptr = NULL;
458 WR(q)->q_ptr = NULL;
459 kmem_free(state, sizeof (sppp_ahdlc_t));
461 return (0);
465 * Create the standard kernel statistics structure and attach it to
466 * the current state structure. This can be called only after
467 * assigning the unit number.
469 static void
470 create_kstats(sppp_ahdlc_t *state)
472 kstat_t *ksp;
473 char unitname[KSTAT_STRLEN];
474 int nstat, i;
475 kstat_named_t *knt;
477 nstat = sizeof (state->sa_kstats) / sizeof (kstat_named_t);
478 knt = (kstat_named_t *)&state->sa_kstats;
479 for (i = 0; i < nstat; i++, knt++) {
480 #ifdef DEBUG
481 /* Just in case I do something silly here. */
482 if (i >= sizeof (kstat_names) / sizeof (kstat_names[0]))
483 (void) sprintf(knt->name, "unknown%d", i);
484 else
485 #endif
486 (void) strncpy(knt->name, kstat_names[i],
487 sizeof (knt->name));
488 knt->data_type = KSTAT_DATA_UINT32;
491 * sprintf is known to be safe here because KSTAT_STRLEN is
492 * 31, the maximum module name length is 8, and the maximum
493 * string length from %d is 11. This was once snprintf, but
494 * that's not backward-compatible with Solaris 2.6.
496 (void) sprintf(unitname, "%s" "%d", AHDLC_MOD_NAME, state->sa_unit);
497 ksp = kstat_create(AHDLC_MOD_NAME, state->sa_unit, unitname, "net",
498 KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_VIRTUAL);
499 if (ksp != NULL) {
500 ksp->ks_data = (void *)&state->sa_kstats;
501 kstat_install(ksp);
503 state->sa_ksp = ksp;
504 #ifdef REPORT_CRC_TYPE
505 KSET(pks_outcrctype, 16);
506 KSET(pks_incrctype, 16);
507 #endif
511 * spppasyn_inner_ioctl
513 * MT-Perimeters:
514 * exclusive inner
516 * Handle state-affecting ioctls.
518 static void
519 spppasyn_inner_ioctl(queue_t *q, mblk_t *mp)
521 sppp_ahdlc_t *state;
522 struct iocblk *iop;
523 int error;
524 int flagval;
525 int len;
526 uint32_t mux_flags;
527 uint32_t mask;
528 int flagmask;
530 ASSERT(q != NULL && mp != NULL);
531 state = (sppp_ahdlc_t *)q->q_ptr;
532 iop = (struct iocblk *)mp->b_rptr;
533 ASSERT(state != NULL && iop != NULL);
535 error = EINVAL;
536 len = 0;
538 switch (iop->ioc_cmd) {
539 case PPPIO_XFCS:
540 /* Check for valid option length */
541 if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
542 break;
544 /* Grab flag value */
545 flagval = *(uint32_t *)mp->b_cont->b_rptr;
546 if (flagval < PPPFCS_16 || flagval > PPPFCS_NONE)
547 break;
548 state->sa_flags &= ~SAF_XMITCRC32 & ~SAF_XMITCRCNONE;
549 if (flagval == PPPFCS_32) {
550 #ifdef REPORT_CRC_TYPE
551 KSET(pks_outcrctype, 32);
552 #endif
553 state->sa_flags |= SAF_XMITCRC32;
554 } else if (flagval == PPPFCS_NONE) {
555 #ifdef REPORT_CRC_TYPE
556 KSET(pks_outcrctype, 0);
557 #endif
558 state->sa_flags |= SAF_XMITCRCNONE;
560 #ifdef REPORT_CRC_TYPE
561 else {
562 KSET(pks_outcrctype, 16);
564 #endif
566 /* Return success */
567 error = 0;
568 break;
570 case PPPIO_RFCS:
571 /* Check for valid option length */
572 if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
573 break;
575 /* Grab flag value */
576 flagval = *(uint32_t *)mp->b_cont->b_rptr;
577 if (flagval < PPPFCS_16 || flagval > PPPFCS_NONE)
578 break;
579 state->sa_flags &= ~SAF_RECVCRC32 & ~SAF_RECVCRCNONE;
580 if (flagval == PPPFCS_32) {
581 #ifdef REPORT_CRC_TYPE
582 KSET(pks_incrctype, 32);
583 #endif
584 state->sa_flags |= SAF_RECVCRC32;
585 } else if (flagval == PPPFCS_NONE) {
586 #ifdef REPORT_CRC_TYPE
587 KSET(pks_incrctype, 0);
588 #endif
589 state->sa_flags |= SAF_RECVCRCNONE;
591 #ifdef REPORT_CRC_TYPE
592 else {
593 KSET(pks_incrctype, 16);
595 #endif
597 /* Return success */
598 error = 0;
599 break;
601 case PPPIO_XACCM:
602 /* Check for valid asyncmap length */
603 if (iop->ioc_count < sizeof (uint32_t) ||
604 iop->ioc_count > sizeof (ext_accm) ||
605 mp->b_cont == NULL)
606 break;
608 /* Copy user's asyncmap into our state structure. */
609 bcopy((caddr_t)mp->b_cont->b_rptr,
610 (caddr_t)state->sa_xaccm, iop->ioc_count);
612 state->sa_xaccm[2] &= ~0x40000000; /* don't escape 0x5e */
613 state->sa_xaccm[3] |= 0x60000000; /* escape 0x7d, 0x7e */
615 error = 0;
616 break;
618 case PPPIO_RACCM:
619 /* Check for valid asyncmap length (only ctrl chars) */
620 if (iop->ioc_count != sizeof (uint32_t) ||
621 mp->b_cont == NULL)
622 break;
624 state->sa_raccm = *(uint32_t *)mp->b_cont->b_rptr;
626 error = 0;
627 break;
629 case PPPIO_LASTMOD:
630 /* We already know this. */
631 state->sa_flags |= SAF_LASTMOD;
632 error = 0;
633 break;
635 case PPPIO_MUX:
636 /* set the compression flags */
637 if (iop->ioc_count != 2 * sizeof (uint32_t) ||
638 mp->b_cont == NULL)
639 break;
641 /* set the mux flags */
642 mux_flags = ((uint32_t *)mp->b_cont->b_rptr)[0];
643 mask = ((uint32_t *)mp->b_cont->b_rptr)[1];
644 if (mux_flags != 0)
645 state->sa_flags = (state->sa_flags & ~mask) | (mask);
647 /* set the multiplexing timer value */
648 if (mask & R_MUXMASK)
649 state->sa_timeout_usec = mux_flags;
651 error = 0;
652 break;
654 case PPPIO_CFLAGS:
655 if (iop->ioc_count != 2 * sizeof (uint32_t) ||
656 mp->b_cont == NULL)
657 break;
659 flagval = (((uint32_t *)mp->b_cont->b_rptr)[0] << 20) &
660 (SAF_RDECOMP_PROT | SAF_RDECOMP_AC | SAF_XCOMP_PROT |
661 SAF_XCOMP_AC);
662 flagmask = (((uint32_t *)mp->b_cont->b_rptr)[1] << 20) &
663 (SAF_RDECOMP_PROT | SAF_RDECOMP_AC | SAF_XCOMP_PROT |
664 SAF_XCOMP_AC);
665 state->sa_flags = flagval | (state->sa_flags & ~flagmask);
666 *(uint32_t *)mp->b_cont->b_rptr = state->sa_flags >> 20;
667 len = sizeof (uint32_t);
668 error = 0;
669 break;
671 case PPPIO_DEBUG:
672 if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
673 break;
675 flagval = *(uint32_t *)mp->b_cont->b_rptr;
676 if (flagval != PPPDBG_LOG + PPPDBG_AHDLC) {
677 putnext(q, mp);
678 return;
680 cmn_err(CE_CONT, AHDLC_MOD_NAME "%d: debug log enabled\n",
681 state->sa_unit);
682 state->sa_flags |= SAF_XMITDUMP | SAF_RECVDUMP;
683 error = 0;
684 break;
687 if (error == 0) {
688 /* Success; tell the user */
689 if (mp->b_cont == NULL)
690 len = 0;
691 else
692 mp->b_cont->b_wptr = mp->b_cont->b_rptr + len;
693 miocack(q, mp, len, 0);
694 } else {
695 /* Failure; send error back upstream. */
696 KINCR(pks_ioctlserr);
697 miocnak(q, mp, 0, error);
702 * spppasyn_inner_mctl
704 * MT-Perimeters:
705 * exclusive inner
707 * Handle state-affecting M_CTL messages.
709 static void
710 spppasyn_inner_mctl(queue_t *q, mblk_t *mp)
712 sppp_ahdlc_t *state;
713 int msglen;
714 int error;
716 ASSERT(q != NULL && mp != NULL);
717 state = (sppp_ahdlc_t *)q->q_ptr;
718 ASSERT(state != NULL);
720 msglen = MBLKL(mp);
721 error = 0;
722 switch (*mp->b_rptr) {
723 case PPPCTL_MTU:
724 /* Just ignore the MTU */
725 break;
727 case PPPCTL_MRU:
728 if (msglen != 4)
729 error = EINVAL;
730 else
731 state->sa_mru =
732 ((ushort_t *)mp->b_rptr)[1];
733 break;
735 case PPPCTL_UNIT:
736 if (state->sa_ksp != NULL) {
737 error = EINVAL;
738 break;
740 if (msglen == 2)
741 state->sa_unit = mp->b_rptr[1];
742 else if (msglen == 8)
743 state->sa_unit =
744 ((uint32_t *)mp->b_rptr)[1];
745 else
746 error = EINVAL;
747 if (error == 0 && state->sa_ksp == NULL)
748 create_kstats(state);
749 break;
752 if (error > 0) {
753 KINCR(pks_ctlserr);
755 if (state->sa_flags & SAF_LASTMOD) {
756 freemsg(mp);
757 } else {
758 KINCR(pks_ctlsfwd);
759 putnext(q, mp);
764 * spppasyn_wput()
766 * MT-Perimeters:
767 * exclusive inner.
769 * Write side put routine. This called by the modules above us (likely to
770 * be the compression module) to transmit data or pass along ioctls.
772 static int
773 spppasyn_wput(queue_t *q, mblk_t *mp)
775 sppp_ahdlc_t *state;
776 struct iocblk *iop;
777 int error;
778 mblk_t *np;
779 struct ppp_stats64 *psp;
780 int msglen;
782 ASSERT(q != NULL && mp != NULL);
783 state = (sppp_ahdlc_t *)q->q_ptr;
784 ASSERT(state != NULL);
786 switch (MTYPE(mp)) {
788 case M_DATA:
790 * A data packet - do character-stuffing and FCS, and
791 * send it onwards. The blocks are freed as we go.
793 if (IS_XMUX_ENABLED(state))
794 mp = spppasyn_muxencode(q, mp);
795 else
796 mp = ahdlc_encode(q, mp);
797 if (mp != NULL)
798 putnext(q, mp);
799 break;
801 case M_IOCTL:
803 KINCR(pks_ioctls);
804 iop = (struct iocblk *)mp->b_rptr;
806 msglen = 0;
808 switch (iop->ioc_cmd) {
809 case PPPIO_XFCS:
810 case PPPIO_RFCS:
811 case PPPIO_XACCM:
812 case PPPIO_RACCM:
813 case PPPIO_LASTMOD:
814 case PPPIO_DEBUG:
815 case PPPIO_MUX:
816 case PPPIO_CFLAGS:
817 spppasyn_inner_ioctl(q, mp);
818 return (0);
820 case PPPIO_GCLEAN:
821 np = allocb(sizeof (uint32_t), BPRI_HI);
822 if (np == NULL) {
823 error = ENOSR;
824 break;
826 if (mp->b_cont != NULL) {
827 freemsg(mp->b_cont);
829 mp->b_cont = np;
831 *(uint32_t *)np->b_wptr = state->sa_flags & RCV_FLAGS;
833 msglen = sizeof (uint32_t);
834 np->b_wptr += msglen;
835 error = 0;
836 break;
838 case PPPIO_GETSTAT:
839 error = EINVAL;
840 break;
842 case PPPIO_GETSTAT64:
843 np = allocb(sizeof (*psp), BPRI_HI);
844 if (np == NULL) {
845 error = ENOSR;
846 break;
848 if (mp->b_cont != NULL) {
849 freemsg(mp->b_cont);
851 mp->b_cont = np;
853 psp = (struct ppp_stats64 *)np->b_wptr;
854 bzero((caddr_t)psp, sizeof (*psp));
855 psp->p = state->sa_stats;
857 msglen = sizeof (*psp);
858 np->b_wptr += msglen;
859 error = 0;
860 break;
862 case PPPIO_GTYPE:
863 np = allocb(sizeof (uint32_t), BPRI_HI);
864 if (np == NULL) {
865 error = ENOSR;
866 break;
868 if (mp->b_cont != NULL) {
869 freemsg(mp->b_cont);
871 mp->b_cont = np;
873 *(uint32_t *)np->b_wptr = PPPTYP_AHDLC;
875 msglen = sizeof (uint32_t);
876 np->b_wptr += msglen;
877 error = 0;
878 break;
880 default:
881 /* Unknown ioctl -- forward along */
882 KINCR(pks_ioctlsfwd);
883 putnext(q, mp);
884 return (0);
887 if (error == 0) {
888 /* Success; tell the user */
889 miocack(q, mp, msglen, 0);
890 } else {
891 /* Failure; send error back upstream. */
892 KINCR(pks_ioctlserr);
893 miocnak(q, mp, 0, error);
896 break;
898 case M_CTL:
899 KINCR(pks_ctls);
900 spppasyn_inner_mctl(q, mp);
901 break;
903 default:
904 if (state->sa_flags & (SAF_XMITDUMP|SAF_RECVDUMP))
905 cmn_err(CE_CONT,
906 "spppasyn_wpur: unknown buffer type %d",
907 MTYPE(mp));
908 KINCR(pks_unknownwrs);
909 putnext(q, mp);
910 break;
913 return (0);
917 * spppasyn_rput()
919 * MT-Perimeters:
920 * exclusive inner.
922 * Read side put routine. This is called by the async serial driver
923 * below us to handle received data and returned signals (like
924 * hang-up).
926 static int
927 spppasyn_rput(queue_t *q, mblk_t *mp)
929 sppp_ahdlc_t *state;
930 mblk_t *mpnext;
932 ASSERT(q != NULL && mp != NULL);
933 state = (sppp_ahdlc_t *)q->q_ptr;
934 ASSERT(state != NULL);
936 switch (MTYPE(mp)) {
938 case M_DATA:
939 /* Note -- decoder frees the buffers */
940 mp = ahdlc_decode(q, mp);
941 while (mp != NULL) {
942 mpnext = mp->b_next;
943 mp->b_next = NULL;
944 putnext(q, mp);
945 mp = mpnext;
947 break;
949 case M_HANGUP:
950 KINCR(pks_hangups);
951 state->sa_flags |= SAF_IFLUSH;
952 putnext(q, mp);
953 break;
955 default:
956 if (state->sa_flags & (SAF_XMITDUMP|SAF_RECVDUMP)) {
957 if (MTYPE(mp) == M_IOCTL)
958 cmn_err(CE_CONT,
959 "spppasyn_rput: unexpected ioctl %X",
960 ((struct iocblk *)mp->b_rptr)->ioc_cmd);
961 else
962 cmn_err(CE_CONT,
963 "spppasyn_rput: unknown buffer type %d",
964 MTYPE(mp));
966 KINCR(pks_unknownrds);
967 putnext(q, mp);
968 break;
971 return (0);
975 * ahdlc_encode
977 * Perform asynchronous HDLC framing on a given buffer and transmit
978 * the result. The state structure must be valid. The input buffers
979 * are freed as we go.
981 * This function is called by wput and just encodes the data. Wput
982 * then calls putnext directly. There's no service routine for this
983 * module, so flow control is asserted by the module below us up to
984 * our caller by the STREAMS framework. This is by design -- this
985 * module does not queue anything so that other modules can make QoS
986 * decisions.
988 static mblk_t *
989 ahdlc_encode(queue_t *q, mblk_t *mp)
991 sppp_ahdlc_t *state;
992 uint32_t loc_xaccm[8];
993 ushort_t fcs16;
994 uint32_t fcs32;
995 size_t msglen;
996 size_t outmp_len;
997 mblk_t *outmp;
998 mblk_t *curout;
999 mblk_t *tmp;
1000 uchar_t *ep;
1001 uchar_t *dp;
1002 uchar_t *tp;
1003 uchar_t *tpmax;
1004 int chr; /* not uchar_t; more efficient this way */
1005 /* with WorkShop compiler */
1006 int is_lcp, is_ctrl;
1007 int code;
1008 hrtime_t hrtime;
1009 uint32_t flags; /* sampled copy of flags */
1011 state = (sppp_ahdlc_t *)q->q_ptr;
1013 /* Don't transmit anything obviously silly. */
1014 msglen = msgsize(mp);
1015 if (msglen < 4) {
1016 KINCR(pks_outrunts);
1017 freemsg(mp);
1018 (void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR);
1019 return (NULL);
1023 * Allocate an output buffer just large enough for most cases.
1024 * Based on original work in the ppp-2.2 AIX PPP driver, we
1025 * estimate the output size as 1.25 * input message length
1026 * plus 16. If this turns out to be too small, then we'll
1027 * allocate exactly one additional buffer with two times the
1028 * remaining input length (the maximum that could possibly be
1029 * required).
1031 outmp_len = msglen + (msglen >> 2) + 16;
1032 outmp = allocb(outmp_len, BPRI_MED);
1033 if (outmp == NULL)
1034 goto outallocfail;
1036 tp = outmp->b_wptr;
1039 * Check if our last transmit happened within FLAG_TIME, using
1040 * the system's hrtime.
1042 hrtime = gethrtime();
1043 if (ABS(hrtime - state->sa_hrtime) > FLAG_TIME) {
1044 *tp++ = PPP_FLAG;
1046 state->sa_hrtime = hrtime;
1047 bcopy((caddr_t)state->sa_xaccm, (caddr_t)loc_xaccm, sizeof (loc_xaccm));
1048 flags = state->sa_flags;
1051 * LCP messages must be sent using the default escaping
1052 * (ACCM). We bend this rule a little to allow LCP
1053 * Echo-Request through with the negotiated escaping so that
1054 * we can detect bad negotiated ACCM values. If the ACCM is
1055 * bad, echos will fail and take down the link.
1057 is_lcp = is_ctrl = 0;
1058 code = MSG_BYTE(mp, 0);
1059 if (code == PPP_ALLSTATIONS) {
1060 if (MSG_BYTE(mp, 1) == PPP_UI) {
1061 code = MSG_BYTE(mp, 2);
1062 if (code == (PPP_LCP >> 8) &&
1063 MSG_BYTE(mp, 3) == (PPP_LCP & 0xFF)) {
1064 if (LCP_USE_DFLT(mp))
1065 is_lcp = 2;
1066 else
1067 is_lcp = 1; /* Echo-Request */
1068 } else if (!(code & 1) && code > 0x3F)
1069 is_ctrl = 1;
1071 } else if (!(code & 1) && code > 0x3F)
1072 is_ctrl = 1;
1075 * If it's LCP and not just an LCP Echo-Request, then we need
1076 * to drop back to default escaping rules temporarily.
1078 if (is_lcp > 1) {
1080 * force escape on 0x00 through 0x1f
1081 * and, for RFC 1662 (and ISO 3309:1991), 0x80-0x9f.
1083 loc_xaccm[0] = 0xffffffff;
1084 loc_xaccm[4] = 0xffffffff;
1087 fcs16 = PPPINITFCS16; /* Initial FCS is 0xffff */
1088 fcs32 = PPPINITFCS32;
1091 * Process this block and the rest (if any) attached to this
1092 * one. Note that we quite intentionally ignore the type of
1093 * the buffer. The caller has checked that the first buffer
1094 * is M_DATA; all others must be so, and any that are not are
1095 * harmless driver errors.
1097 curout = outmp;
1098 tpmax = outmp->b_datap->db_lim;
1099 do {
1100 dp = mp->b_rptr;
1101 while (dp < (ep = mp->b_wptr)) {
1103 * Calculate maximum safe run length for inner loop,
1104 * regardless of escaping.
1106 outmp_len = (tpmax - tp) / 2;
1107 if (dp + outmp_len < ep)
1108 ep = dp + outmp_len;
1111 * Select out on CRC type here to make the
1112 * inner byte loop more efficient. (We could
1113 * do both CRCs at all times if we wanted, but
1114 * that ends up taking an extra 8 cycles per
1115 * byte -- 47% overhead!)
1117 if (flags & SAF_XMITCRC32) {
1118 while (dp < ep) {
1119 chr = *dp++;
1120 fcs32 = PPPFCS32(fcs32, chr);
1121 if (IN_TX_MAP(chr, loc_xaccm)) {
1122 *tp++ = PPP_ESCAPE;
1123 chr ^= PPP_TRANS;
1125 *tp++ = chr;
1127 } else {
1128 while (dp < ep) {
1129 chr = *dp++;
1130 fcs16 = PPPFCS16(fcs16, chr);
1131 if (IN_TX_MAP(chr, loc_xaccm)) {
1132 *tp++ = PPP_ESCAPE;
1133 chr ^= PPP_TRANS;
1135 *tp++ = chr;
1140 * If we limited our run length and we're now low
1141 * on output space, then allocate a new output buffer.
1142 * This should rarely happen, unless the output data
1143 * has a lot of escapes.
1145 if (ep != mp->b_wptr && tpmax - tp < 5) {
1146 KINCR(pks_extrabufs);
1147 /* Get remaining message length */
1148 outmp_len = (mp->b_wptr - dp) +
1149 msgsize(mp->b_cont);
1150 /* Calculate maximum required space */
1151 outmp_len = (outmp_len + PPP_FCS32LEN) * 2 + 1;
1152 curout = allocb(outmp_len, BPRI_MED);
1153 if ((outmp->b_cont = curout) == NULL)
1154 goto outallocfail;
1155 outmp->b_wptr = tp;
1156 tp = curout->b_wptr;
1157 tpmax = curout->b_datap->db_lim;
1160 tmp = mp->b_cont;
1161 freeb(mp);
1162 mp = tmp;
1163 } while (mp != NULL);
1166 * Make sure we have enough remaining room to add the CRC (if
1167 * any) and a trailing flag byte.
1169 outmp_len = PPP_FCS32LEN * 2 + 1;
1170 if (tpmax - tp < outmp_len) {
1171 KINCR(pks_extrabufs);
1172 curout = allocb(outmp_len, BPRI_MED);
1173 if ((outmp->b_cont = curout) == NULL)
1174 goto outallocfail;
1175 outmp->b_wptr = tp;
1176 tp = curout->b_wptr;
1177 tpmax = curout->b_datap->db_lim;
1181 * Network layer data is the only thing that can be sent with
1182 * no CRC at all.
1184 if ((flags & SAF_XMITCRCNONE) && !is_lcp && !is_ctrl)
1185 goto nocrc;
1187 if (!(flags & SAF_XMITCRC32))
1188 fcs32 = fcs16;
1191 * Append the HDLC FCS, making sure that escaping is done on any
1192 * necessary bytes. Note that the FCS bytes are in little-endian.
1194 fcs32 = ~fcs32;
1195 chr = fcs32 & 0xff;
1196 if (IN_TX_MAP(chr, loc_xaccm)) {
1197 *tp++ = PPP_ESCAPE;
1198 chr ^= PPP_TRANS;
1200 *tp++ = chr;
1202 chr = (fcs32 >> 8) & 0xff;
1203 if (IN_TX_MAP(chr, loc_xaccm)) {
1204 *tp++ = PPP_ESCAPE;
1205 chr ^= PPP_TRANS;
1207 *tp++ = chr;
1209 if (flags & SAF_XMITCRC32) {
1210 chr = (fcs32 >> 16) & 0xff;
1211 if (IN_TX_MAP(chr, loc_xaccm)) {
1212 *tp++ = PPP_ESCAPE;
1213 chr ^= PPP_TRANS;
1215 *tp++ = chr;
1217 chr = (fcs32 >> 24) & 0xff;
1218 if (IN_TX_MAP(chr, loc_xaccm)) {
1219 *tp++ = PPP_ESCAPE;
1220 chr ^= PPP_TRANS;
1222 *tp++ = chr;
1225 nocrc:
1227 * And finally append the HDLC flag, and send it away
1229 *tp++ = PPP_FLAG;
1230 ASSERT(tp < tpmax);
1231 curout->b_wptr = tp;
1233 state->sa_stats.ppp_obytes += msgsize(outmp);
1234 state->sa_stats.ppp_opackets++;
1236 if (state->sa_flags & SAF_XMITDUMP)
1237 ppp_dump_frame(state, outmp, "sent");
1239 KINCR(pks_dataout);
1240 return (outmp);
1242 outallocfail:
1243 KINCR(pks_outallocfails);
1244 state->sa_stats.ppp_oerrors++;
1245 freemsg(outmp);
1246 freemsg(mp);
1247 (void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR);
1248 return (NULL);
1252 * Handle end-of-frame excitement. This is here mostly because the Solaris
1253 * C style rules require tab for indent and prohibit excessive indenting.
1255 static mblk_t *
1256 receive_frame(queue_t *q, mblk_t *outmp, ushort_t fcs16, uint32_t fcs32)
1258 sppp_ahdlc_t *state = (sppp_ahdlc_t *)q->q_ptr;
1259 uchar_t *cp, *ep;
1260 int is_lcp, is_ctrl, crclen;
1261 ushort_t proto;
1262 int i;
1264 cp = outmp->b_rptr;
1265 if (cp[0] == PPP_ALLSTATIONS && cp[1] == PPP_UI)
1266 cp += 2;
1267 proto = *cp++;
1268 if ((proto & 1) == 0)
1269 proto = (proto << 8) + *cp++;
1270 is_lcp = (proto == PPP_LCP);
1271 is_ctrl = (proto >= 0x4000);
1274 * To allow for renegotiation, LCP accepts good CRCs of either
1275 * type at any time. Other control (non-network) packets must
1276 * have either CRC-16 or CRC-32, as negotiated. Network layer
1277 * packets may additionally omit the CRC entirely, if that was
1278 * negotiated.
1280 if ((is_lcp && (fcs16 == PPPGOODFCS16 || fcs32 == PPPGOODFCS32)) ||
1281 ((fcs16 == PPPGOODFCS16 && !(state->sa_flags & SAF_RECVCRC32)) ||
1282 (fcs32 == PPPGOODFCS32 &&
1283 (state->sa_flags & SAF_RECVCRC32))) ||
1284 (!is_ctrl && !is_lcp && (state->sa_flags & SAF_RECVCRCNONE))) {
1286 state->sa_stats.ppp_ipackets++;
1287 if (is_lcp) {
1288 crclen = (fcs16 == PPPGOODFCS16) ?
1289 PPP_FCSLEN : PPP_FCS32LEN;
1290 } else {
1291 crclen = (state->sa_flags & SAF_RECVCRC32) ?
1292 PPP_FCS32LEN : PPP_FCSLEN;
1293 if (!is_ctrl && (state->sa_flags & SAF_RECVCRCNONE))
1294 crclen = 0;
1296 if (crclen != 0) {
1297 i = adjmsg(outmp, -crclen);
1298 ASSERT(i != 0);
1301 if (proto == PPP_MUX) {
1302 /* spppasyn_inpkt checks for PPP_MUX packets */
1303 KINCR(pks_recvmux);
1304 /* Remove headers */
1305 outmp->b_rptr = cp;
1306 return (spppasyn_inpkt(q, outmp));
1310 * Sniff the received data stream. If we see an LCP
1311 * Configure-Ack, then pick out the ACCM setting, if
1312 * any, and configure now. This allows us to stay in
1313 * sync in case the peer is already out of Establish
1314 * phase.
1316 if (is_lcp && *cp == 2) {
1317 ep = outmp->b_wptr;
1318 i = (cp[2] << 8) | cp[3];
1319 if (i > ep - cp)
1320 ep = cp; /* Discard junk */
1321 else if (i < ep - cp)
1322 ep = cp + i;
1323 cp += 4;
1324 while (cp + 2 < ep) {
1325 if ((i = cp[1]) < 2)
1326 i = 2;
1327 if (cp + i > ep)
1328 i = ep - cp;
1329 if (cp[0] == 2 && i >= 6) {
1330 state->sa_raccm = (cp[2] << 24) |
1331 (cp[3] << 16) | (cp[4] << 8) |
1332 cp[5];
1333 break;
1335 cp += i;
1338 return (outmp);
1339 } else {
1340 KINCR(pks_incrcerrs);
1341 cmn_err(CE_CONT, PPP_DRV_NAME "%d: bad fcs (len=%ld)\n",
1342 state->sa_unit, msgsize(outmp));
1344 if (state->sa_flags & SAF_RECVDUMP)
1345 ppp_dump_frame(state, outmp, "bad data");
1347 freemsg(outmp);
1349 state->sa_stats.ppp_ierrors++;
1351 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1352 return (NULL);
1357 * ahdlc_decode()
1359 * Process received characters.
1361 * This is handled as exclusive inner so that we don't get confused
1362 * about the state. Returns a list of packets linked by b_next.
1364 static mblk_t *
1365 ahdlc_decode(queue_t *q, mblk_t *mp)
1367 sppp_ahdlc_t *state;
1368 mblk_t *retmp; /* list of packets to return */
1369 mblk_t *outmp; /* buffer for decoded data */
1370 mblk_t *mpnext; /* temporary ptr for unlinking */
1371 uchar_t *dp; /* pointer to input data */
1372 uchar_t *dpend; /* end of input data */
1373 uchar_t *tp; /* pointer to decoded output data */
1374 uchar_t *tpmax; /* output buffer limit */
1375 int flagtmp; /* temporary cache of flags */
1376 int chr; /* not uchar_t; more efficient this way */
1377 /* with WorkShop compiler */
1378 ushort_t fcs16; /* running CRC-16 */
1379 uint32_t fcs32; /* running CRC-32 */
1380 #ifdef HANDLE_ZERO_LENGTH
1381 size_t nprocessed;
1382 #endif
1384 state = (sppp_ahdlc_t *)q->q_ptr;
1386 KINCR(pks_datain);
1388 state->sa_stats.ppp_ibytes += msgsize(mp);
1390 if (state->sa_flags & SAF_RECVDUMP)
1391 ppp_dump_frame(state, mp, "rcvd");
1393 flagtmp = state->sa_flags;
1394 fcs16 = state->sa_infcs16;
1395 fcs32 = state->sa_infcs32;
1396 outmp = state->sa_rx_buf;
1397 if (outmp == NULL) {
1398 tp = tpmax = NULL;
1399 } else {
1400 tp = outmp->b_wptr;
1401 tpmax = outmp->b_datap->db_lim;
1403 #ifdef HANDLE_ZERO_LENGTH
1404 nprocessed = 0;
1405 #endif
1408 * Main input processing loop. Loop over received buffers and
1409 * each byte in each buffer. Note that we quite intentionally
1410 * ignore the type of the buffer. The caller has checked that
1411 * the first buffer is M_DATA; all others must be so, and any
1412 * that are not are harmless driver errors.
1414 retmp = NULL;
1415 while (mp != NULL) {
1417 /* Innermost loop -- examine bytes in buffer. */
1418 dpend = mp->b_wptr;
1419 dp = mp->b_rptr;
1420 #ifdef HANDLE_ZERO_LENGTH
1421 nprocessed += dpend - dp;
1422 #endif
1423 for (; dp < dpend; dp++) {
1424 chr = *dp;
1427 * This should detect the lack of an 8-bit
1428 * communication channel, which is necessary
1429 * for PPP to work.
1431 flagtmp |= charflags[chr];
1434 * So we have a HDLC flag ...
1436 if (chr == PPP_FLAG) {
1439 * If there's no received buffer, then
1440 * just ignore this frame marker.
1442 if ((flagtmp & SAF_IFLUSH) || outmp == NULL) {
1443 flagtmp &= ~SAF_IFLUSH & ~SAF_ESCAPED;
1444 continue;
1448 * Per RFC 1662 -- silently discard
1449 * runt frames (fewer than 4 octets
1450 * with 16 bit CRC) and frames that
1451 * end in 7D 7E (abort sequence).
1452 * These are not counted as errors.
1454 * (We could just reset the pointers
1455 * and reuse the buffer, but this is a
1456 * rarely used error path and not
1457 * worth the optimization.)
1459 if ((flagtmp & SAF_ESCAPED) ||
1460 tp - outmp->b_rptr < 2 + PPP_FCSLEN) {
1461 if (flagtmp & SAF_ESCAPED)
1462 KINCR(pks_inaborts);
1463 else
1464 KINCR(pks_inrunts);
1465 if (state->sa_flags & SAF_RECVDUMP) {
1466 outmp->b_wptr = tp;
1467 ppp_dump_frame(state, outmp,
1468 "runt");
1470 freemsg(outmp);
1471 flagtmp &= ~SAF_ESCAPED;
1472 } else {
1473 /* Handle the received frame */
1474 outmp->b_wptr = tp;
1475 outmp = receive_frame(q, outmp, fcs16,
1476 fcs32);
1477 retmp = sppp_mappend(retmp, outmp);
1480 outmp = NULL;
1481 tp = tpmax = NULL;
1483 continue;
1486 /* If we're waiting for a new frame, then drop data. */
1487 if (flagtmp & SAF_IFLUSH) {
1488 continue;
1492 * Start of new frame. Allocate a receive
1493 * buffer large enough to store a frame (after
1494 * un-escaping) of at least 1500 octets plus
1495 * the CRC. If MRU is negotiated to be more
1496 * than the default, then allocate that much.
1497 * In addition, we add an extra 32-bytes for a
1498 * fudge factor, in case the peer doesn't do
1499 * arithmetic very well.
1501 if (outmp == NULL) {
1502 int maxlen;
1504 if ((maxlen = state->sa_mru) < PPP_MRU)
1505 maxlen = PPP_MRU;
1506 maxlen += PPP_FCS32LEN + 32;
1507 outmp = allocb(maxlen, BPRI_MED);
1510 * If allocation fails, try again on
1511 * the next frame. (Go into discard
1512 * mode.)
1514 if (outmp == NULL) {
1515 KINCR(pks_inallocfails);
1516 flagtmp |= SAF_IFLUSH;
1517 continue;
1520 tp = outmp->b_wptr;
1521 tpmax = outmp->b_datap->db_lim;
1523 /* Neither flag can possibly be set here. */
1524 flagtmp &= ~(SAF_IFLUSH | SAF_ESCAPED);
1525 fcs16 = PPPINITFCS16;
1526 fcs32 = PPPINITFCS32;
1530 * If the peer sends us a character that's in
1531 * our receive character map, then that's
1532 * junk. Discard it without changing state.
1533 * If they previously sent us an escape
1534 * character, then toggle this one and
1535 * continue. Otherwise, if they're now sending
1536 * escape, set the flag for next time.
1538 if (IN_RX_MAP(chr, state->sa_raccm)) {
1539 KINCR(pks_inbadchars);
1540 KOR(pks_inbadcharmask, 1 << chr);
1541 continue;
1543 if (flagtmp & SAF_ESCAPED) {
1544 chr ^= PPP_TRANS;
1545 flagtmp &= ~SAF_ESCAPED;
1546 } else if (chr == PPP_ESCAPE) {
1547 flagtmp |= SAF_ESCAPED;
1548 continue;
1552 * Unless the peer is confused about the
1553 * negotiated MRU, we should never get a frame
1554 * that is too long. If it happens, toss it
1555 * away and begin discarding data until we see
1556 * the end of the frame.
1558 if (tp < tpmax) {
1559 fcs16 = PPPFCS16(fcs16, chr);
1560 fcs32 = PPPFCS32(fcs32, chr);
1561 *tp++ = chr;
1562 } else {
1563 KINCR(pks_intoolongs);
1564 cmn_err(CE_CONT, PPP_DRV_NAME
1565 "%d: frame too long (%d bytes)\n",
1566 state->sa_unit,
1567 (int)(tpmax - outmp->b_rptr));
1569 freemsg(outmp);
1570 outmp = NULL;
1571 tp = tpmax = NULL;
1572 flagtmp |= SAF_IFLUSH;
1577 * Free the buffer we just processed and move on to
1578 * the next one.
1580 mpnext = mp->b_cont;
1581 freeb(mp);
1582 mp = mpnext;
1584 state->sa_flags = flagtmp;
1585 if ((state->sa_rx_buf = outmp) != NULL)
1586 outmp->b_wptr = tp;
1587 state->sa_infcs16 = fcs16;
1588 state->sa_infcs32 = fcs32;
1590 #ifdef HANDLE_ZERO_LENGTH
1591 if (nprocessed <= 0) {
1592 outmp = allocb(0, BPRI_MED);
1593 if (outmp != NULL) {
1594 outmp->b_datap->db_type = M_HANGUP;
1595 retmp = sppp_mappend(retmp, outmp);
1598 #endif
1599 return (retmp);
1603 * Nifty packet dumper; copied from AIX 4.1 port. This routine dumps
1604 * the raw received and transmitted data through syslog. This allows
1605 * debug of communications problems without resorting to a line
1606 * analyzer.
1608 * The expression "3*BYTES_PER_LINE" used frequently here represents
1609 * the size of each hex value printed -- two hex digits and a space.
1611 #define BYTES_PER_LINE 8
1612 static void
1613 ppp_dump_frame(sppp_ahdlc_t *state, mblk_t *mptr, const char *msg)
1616 * Buffer is big enough for hex digits, two spaces, ASCII output,
1617 * and one NUL byte.
1619 char buf[3 * BYTES_PER_LINE + 2 + BYTES_PER_LINE + 1];
1620 uchar_t *rptr, *eptr;
1621 int i, chr;
1622 char *bp;
1623 static const char digits[] = "0123456789abcdef";
1625 cmn_err(CE_CONT, "!ppp_async%d: %s %ld bytes\n", state->sa_unit,
1626 msg, msgsize(mptr));
1627 i = 0;
1628 bp = buf;
1629 /* Add filler spaces between hex output and ASCII */
1630 buf[3 * BYTES_PER_LINE] = ' ';
1631 buf[3 * BYTES_PER_LINE + 1] = ' ';
1632 /* Add NUL byte at end */
1633 buf[sizeof (buf) - 1] = '\0';
1634 while (mptr != NULL) {
1635 rptr = mptr->b_rptr; /* get pointer to beginning */
1636 eptr = mptr->b_wptr;
1637 while (rptr < eptr) {
1638 chr = *rptr++;
1639 /* convert byte to ascii hex */
1640 *bp++ = digits[chr >> 4];
1641 *bp++ = digits[chr & 0xf];
1642 *bp++ = ' ';
1643 /* Insert ASCII past hex output and filler */
1644 buf[3 * BYTES_PER_LINE + 2 + i] =
1645 (chr >= 0x20 && chr <= 0x7E) ? (char)chr : '.';
1646 i++;
1647 if (i >= BYTES_PER_LINE) {
1648 cmn_err(CE_CONT, "!ppp%d: %s\n", state->sa_unit,
1649 buf);
1650 bp = buf;
1651 i = 0;
1654 mptr = mptr->b_cont;
1656 if (bp > buf) {
1657 /* fill over unused hex display positions */
1658 while (bp < buf + 3 * BYTES_PER_LINE)
1659 *bp++ = ' ';
1660 /* terminate ASCII string at right position */
1661 buf[3 * BYTES_PER_LINE + 2 + i] = '\0';
1662 cmn_err(CE_CONT, "!ppp%d: %s\n", state->sa_unit, buf);
1666 static mblk_t *
1667 spppasyn_muxencode(queue_t *q, mblk_t *mp)
1669 sppp_ahdlc_t *state = (sppp_ahdlc_t *)q->q_ptr;
1670 uint32_t len;
1671 uint32_t nlen;
1672 ushort_t protolen;
1673 uint32_t hdrlen;
1674 ushort_t proto;
1675 mblk_t *new_frame;
1676 mblk_t *tmp;
1677 mblk_t *send_frame;
1678 ushort_t i;
1680 len = msgdsize(mp);
1681 i = 0;
1682 protolen = 1;
1683 proto = MSG_BYTE(mp, i);
1685 if (proto == PPP_ALLSTATIONS) {
1686 len -= 2;
1687 i += 2;
1688 proto = MSG_BYTE(mp, i);
1691 ++i;
1692 if ((proto & 1) == 0) {
1693 proto = (proto << 8) + MSG_BYTE(mp, i);
1694 protolen++;
1697 hdrlen = i - 1;
1699 send_frame = NULL;
1700 if (len > PPP_MAX_MUX_LEN || (proto & 0x8000)) {
1702 /* send the queued frames */
1703 if (state->sa_mqhead != NULL) {
1704 /* increment counter if it is MUX pkt */
1705 if (state->sa_mqtail != NULL)
1706 KINCR(pks_sentmux);
1707 send_frame = ahdlc_encode(q, state->sa_mqhead);
1710 /* send the current frame */
1711 mp = ahdlc_encode(q, mp);
1712 send_frame = sppp_mcat(send_frame, mp);
1714 /* reset the state values over here */
1715 RESET_MUX_VALUES(state);
1716 return (send_frame);
1719 /* len + 1 , since we add the mux overhead */
1720 nlen = len + 1;
1721 /* subtract the protocol length if protocol matches */
1722 if (state->sa_proto == proto)
1723 nlen -= protolen;
1725 send_frame = NULL;
1726 if ((state->sa_mqlen + nlen) >= state->sa_mru) {
1728 /* send the existing queued frames */
1729 if (state->sa_mqhead != NULL) {
1730 /* increment counter if it is MUX pkt */
1731 if (state->sa_mqtail != NULL)
1732 KINCR(pks_sentmux);
1733 send_frame = ahdlc_encode(q, state->sa_mqhead);
1736 /* reset state values */
1737 RESET_MUX_VALUES(state);
1740 /* add the current frame to the queue */
1741 if (state->sa_mqhead != NULL) {
1743 if (state->sa_mqtail == NULL) {
1746 * this is the first mblk in the queue create
1747 * a new frame to hold the PPP MUX header
1749 if ((new_frame = allocb(PPP_HDRLEN+1,
1750 BPRI_MED)) == NULL) {
1751 return (send_frame);
1754 if (!IS_COMP_AC(state)) {
1755 /* add the header */
1756 *new_frame->b_wptr++ = PPP_ALLSTATIONS;
1757 *new_frame->b_wptr++ = PPP_UI;
1760 /* do protocol compression */
1761 if (IS_COMP_PROT(state)) {
1762 *new_frame->b_wptr++ = PPP_MUX;
1763 } else {
1764 *new_frame->b_wptr++ = 0;
1765 *new_frame->b_wptr++ = PPP_MUX;
1768 *new_frame->b_wptr++ = PFF |
1769 (state->sa_mqlen - protolen - 1);
1771 if (DB_REF(mp) > 1) {
1772 tmp = copymsg(state->sa_mqhead);
1773 freemsg(state->sa_mqhead);
1774 if ((state->sa_mqhead = tmp) == NULL) {
1775 return (send_frame);
1779 if (state->sa_mqhead->b_rptr[0] == PPP_ALLSTATIONS)
1780 state->sa_mqhead->b_rptr += 2;
1782 linkb(new_frame, state->sa_mqhead);
1783 state->sa_mqtail = state->sa_mqhead;
1784 /* point mqtail to the last mblk_t */
1785 while (state->sa_mqtail->b_cont != NULL)
1786 state->sa_mqtail = state->sa_mqtail->b_cont;
1788 /* change state->sa_mqhead */
1789 state->sa_mqhead = new_frame;
1793 if (state->sa_proto == proto) {
1795 /* Check if the mblk_t is being referenced */
1796 if (DB_REF(mp) > 1) {
1797 tmp = copymsg(mp);
1798 freemsg(mp);
1799 if ((mp = tmp) == NULL) {
1800 return (send_frame);
1805 * match,can remove the protocol field
1806 * and write data there
1808 mp->b_rptr += hdrlen;
1810 * protolen - 1 ,because the the byte with
1811 * the PFF bit and the length field have
1812 * to added
1814 mp->b_rptr += (protolen - 1);
1815 *mp->b_rptr = (len - protolen) & 0xff;
1817 } else {
1819 * no match, there are three options
1820 * 1. write in mp
1821 * 2. write in mqtail
1822 * 3. alloc a new blk for just one byte
1824 /* Check if the mblk_t is being referenced */
1825 if (DB_REF(mp) > 1) {
1826 tmp = copymsg(mp);
1827 freemsg(mp);
1828 if ((mp = tmp) == NULL) {
1829 return (send_frame);
1833 if (hdrlen != 0) {
1835 mp->b_rptr += (hdrlen-1);
1836 *mp->b_rptr = PFF | (len);
1838 } else if (state->sa_mqtail->b_wptr <
1839 DB_LIM(state->sa_mqtail)) {
1840 *state->sa_mqtail->b_wptr++ = PFF |len;
1841 } else {
1842 /* allocate a new mblk & add the byte */
1843 /* write the data */
1844 if ((new_frame = allocb(1, BPRI_MED))
1845 == NULL) {
1846 freemsg(mp);
1847 return (send_frame);
1849 *new_frame->b_wptr++ = PFF | (len);
1850 linkb(state->sa_mqtail, new_frame);
1853 /* update proto */
1854 state->sa_proto = proto;
1857 linkb(state->sa_mqtail, mp);
1858 state->sa_mqtail = mp;
1859 while (state->sa_mqtail->b_cont != NULL)
1860 state->sa_mqtail = state->sa_mqtail->b_cont;
1861 state->sa_mqlen += nlen;
1863 } else {
1864 state->sa_mqhead = mp;
1865 state->sa_mqlen = len + protolen + 1;
1866 state->sa_proto = proto;
1869 if (state->sa_timeout_id == 0) {
1870 state->sa_timeout_id = qtimeout(q, spppasyn_timer, q,
1871 (drv_usectohz(state->sa_timeout_usec)));
1873 return (send_frame);
1877 * Called from receive frame, this routine checks if it is a PPP_MUX
1878 * packet and demuxes it. The returned pointer is a chain of mblks
1879 * using b_next and representing the demultiplexed packets.
1881 static mblk_t *
1882 spppasyn_inpkt(queue_t *q, mblk_t *mp)
1884 sppp_ahdlc_t *state = (sppp_ahdlc_t *)q->q_ptr;
1885 ushort_t proto;
1886 ushort_t prev_proto;
1887 uint32_t len; /* length of subframe */
1888 uchar_t muxhdr;
1889 mblk_t *hdrmp;
1890 mblk_t *subframe;
1891 mblk_t *retmp;
1893 if (!(mp->b_rptr[0] & PFF)) {
1894 KINCR(pks_inmuxerrs);
1895 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1896 freemsg(mp);
1897 return (NULL);
1900 /* initialise the Last protocol and protocol length */
1901 prev_proto = 0;
1904 * Taking into granted that the decoded frame is contiguous
1906 retmp = NULL;
1907 while (mp->b_rptr < mp->b_wptr) {
1910 * get the last protocol, protocol length
1911 * and the length of the message
1914 /* protocol field flag and length */
1915 muxhdr = mp->b_rptr[0];
1916 len = muxhdr & ~PFF;
1918 mp->b_rptr++;
1920 /* check if there and enough bytes left in pkt */
1921 if (MBLKL(mp) < len) {
1922 KINCR(pks_inmuxerrs);
1923 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1924 break;
1927 /* allocate memory for the header length */
1928 if ((hdrmp = allocb(PPP_HDRLEN, BPRI_MED)) == NULL) {
1929 KINCR(pks_inallocfails);
1930 break;
1933 /* add the ppp header to the pkt */
1934 *hdrmp->b_wptr++ = PPP_ALLSTATIONS;
1935 *hdrmp->b_wptr++ = PPP_UI;
1937 /* check if the protocol field flag is set */
1938 if (muxhdr & PFF) {
1940 /* get the protocol */
1941 proto = MSG_BYTE(mp, 0);
1942 if ((proto & 1) == 0)
1943 proto = (proto << 8) + MSG_BYTE(mp, 1);
1945 /* reset values */
1946 prev_proto = proto;
1947 } else {
1948 if (!IS_DECOMP_PROT(state))
1949 *hdrmp->b_wptr++ = prev_proto >> 8;
1950 *hdrmp->b_wptr++ = (prev_proto & 0xff);
1953 /* get the payload from the MUXed packet */
1954 subframe = dupmsg(mp);
1955 subframe->b_wptr = mp->b_rptr + len;
1957 /* link the subframe to the new frame */
1958 linkb(hdrmp, subframe);
1960 /* do a putnext */
1961 retmp = sppp_mappend(retmp, hdrmp);
1963 /* move the read pointer beyond this subframe */
1964 mp->b_rptr += len;
1967 freemsg(mp);
1968 return (retmp);
1973 * timer routine which sends out the queued pkts *
1975 static void
1976 spppasyn_timer(void *arg)
1978 queue_t *q;
1979 sppp_ahdlc_t *state;
1980 mblk_t *mp;
1982 ASSERT(arg);
1983 q = (queue_t *)arg;
1984 state = (sppp_ahdlc_t *)q->q_ptr;
1986 if (state->sa_mqhead != NULL) {
1987 /* increment counter */
1988 if (state->sa_mqtail != NULL)
1989 KINCR(pks_sentmux);
1990 if ((mp = ahdlc_encode(q, state->sa_mqhead)) != NULL)
1991 putnext(q, mp);
1992 /* reset the state values over here */
1993 RESET_MUX_VALUES(state);
1995 /* clear timeout_id */
1996 state->sa_timeout_id = 0;