1 /*
2 * spppasyn.c - STREAMS module for doing PPP asynchronous HDLC.
3 *
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.
7 *
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.
11 *
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
18 *
19 * Copyright (c) 1994 The Australian National University.
20 * All rights reserved.
21 *
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.
28 *
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.
34 *
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.
41 *
42 * $Id: ppp_ahdlc.c,v 1.16 2000/03/06 19:38:12 masputra Exp $
43 */
44
45 #pragma ident "%Z%%M% %I% %E% SMI"
46
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>
58
59 #include <net/ppp_defs.h>
60 #include <net/pppio.h>
61
62 #include "s_common.h"
63
64 #ifdef DEBUG
65 #define REPORT_CRC_TYPE
66 #endif
67 #include "spppasyn.h"
68
69 /*
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.
73 */
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$";
79
80 /* LINTED */
81 static const char buildtime[] = "Built " __DATE__ " at " __TIME__
82 #ifdef DEBUG
83 " DEBUG"
84 #endif
85 "\n";
86 #endif /* INTERNAL_BUILD */
87
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 *);
97
98 #define RESET_MUX_VALUES(x) { \
99 x->sa_mqhead = x->sa_mqtail = NULL; \
100 x->sa_proto = 0; \
101 x->sa_mqlen = 0; \
102 }
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)
113
114 /*
115 * Don't send HDLC start flag if last transmit is within 1.5 seconds -
116 * FLAG_TIME is defined in nanoseconds.
117 */
118 #define FLAG_TIME 1500000000ul
119
120 /*
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.
129 */
130 #define LCP_USE_DFLT(mp) ((code = MSG_BYTE((mp), 4)) < 9 || code > 11)
131
132 /*
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.
136 */
137 #define IN_TX_MAP(c, m) \
138 ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
139
140 /*
141 * Checks the 32-bit receive ACCM to see if the byte should have been
142 * escaped by peer.
143 */
144 #define IN_RX_MAP(c, m) (((c) < 0x20) && ((m) & (1 << (c))))
145
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 */
153 };
154
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 */
163 };
164
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 */
173 };
174
175 struct streamtab spppasyn_tab = {
176 &spppasyn_rinit, /* st_rdinit */
177 &spppasyn_winit, /* st_wrinit */
178 NULL, /* st_muxrinit */
179 NULL, /* st_muxwinit */
180 };
181
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
193 };
194
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)
201
202 static void ppp_dump_frame(sppp_ahdlc_t *state, mblk_t *mptr,
203 const char *msg);
204
205 /*
206 * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also.
207 */
208 #define RCV_FLAGS (RCV_B7_1 | RCV_B7_0 | RCV_ODDP | RCV_EVNP)
209
210 /*
211 * FCS lookup table as calculated by genfcstab.
212 */
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
246 };
247
248 /*
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.)
255 */
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
343 };
344
345 /*
346 * Append two lists; preserve message boundaries.
347 * Warning: uses b_next.
348 */
349 static mblk_t *
sppp_mappend(mblk_t * m1,mblk_t * m2)350 sppp_mappend(mblk_t *m1, mblk_t *m2)
351 {
352 mblk_t *mret;
353
354 if (m1 == NULL)
355 return (m2);
356 if (m2 == NULL)
357 return (m1);
358
359 mret = m1;
360 while (m1->b_next != NULL)
361 m1 = m1->b_next;
362 m1->b_next = m2;
363 return (mret);
364 }
365
366 /*
367 * Concatenate two mblk lists.
368 */
369 static mblk_t *
sppp_mcat(mblk_t * m1,mblk_t * m2)370 sppp_mcat(mblk_t *m1, mblk_t *m2)
371 {
372 mblk_t *mret;
373
374 if (m1 == NULL)
375 return (m2);
376 if (m2 == NULL)
377 return (m1);
378
379 mret = m1;
380 while (m1->b_cont != NULL)
381 m1 = m1->b_cont;
382 m1->b_cont = m2;
383 return (mret);
384 }
385
386 /*
387 * spppasyn_open()
388 *
389 * STREAMS module open (entry) point. Called when spppasyn is pushed
390 * onto an asynchronous serial stream.
391 */
392 /* ARGSUSED */
393 static int
spppasyn_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)394 spppasyn_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
395 {
396 sppp_ahdlc_t *state;
397
398 ASSERT(q != NULL);
399
400 if (q->q_ptr != NULL) {
401 return (0); /* return if already opened */
402 }
403
404 if (sflag != MODOPEN) {
405 return (EINVAL); /* only open as a module */
406 }
407
408 state = (sppp_ahdlc_t *)kmem_zalloc(sizeof (sppp_ahdlc_t), KM_SLEEP);
409 ASSERT(state != NULL);
410
411 q->q_ptr = (caddr_t)state;
412 WR(q)->q_ptr = (caddr_t)state;
413
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 */
417
418 qprocson(q);
419
420 return (0);
421 }
422
423 /*
424 * spppasyn_close()
425 *
426 * STREAMS module close (exit) point
427 */
428 /* ARGSUSED */
429 static int
spppasyn_close(queue_t * q,int flag,cred_t * credp)430 spppasyn_close(queue_t *q, int flag, cred_t *credp)
431 {
432 sppp_ahdlc_t *state;
433
434 ASSERT(q != NULL);
435 state = (sppp_ahdlc_t *)q->q_ptr;
436 ASSERT(state != NULL);
437
438 /* We're leaving now. No more calls, please. */
439 qprocsoff(q);
440
441 if (state->sa_rx_buf != NULL) {
442 freemsg(state->sa_rx_buf);
443 state->sa_rx_buf = NULL;
444 }
445
446 if (state->sa_ksp != NULL) {
447 kstat_delete(state->sa_ksp);
448 state->sa_ksp = NULL;
449 }
450
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);
456
457 q->q_ptr = NULL;
458 WR(q)->q_ptr = NULL;
459 kmem_free(state, sizeof (sppp_ahdlc_t));
460
461 return (0);
462 }
463
464 /*
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.
468 */
469 static void
create_kstats(sppp_ahdlc_t * state)470 create_kstats(sppp_ahdlc_t *state)
471 {
472 kstat_t *ksp;
473 char unitname[KSTAT_STRLEN];
474 int nstat, i;
475 kstat_named_t *knt;
476
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;
489 }
490 /*
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.
495 */
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);
502 }
503 state->sa_ksp = ksp;
504 #ifdef REPORT_CRC_TYPE
505 KSET(pks_outcrctype, 16);
506 KSET(pks_incrctype, 16);
507 #endif
508 }
509
510 /*
511 * spppasyn_inner_ioctl
512 *
513 * MT-Perimeters:
514 * exclusive inner
515 *
516 * Handle state-affecting ioctls.
517 */
518 static void
spppasyn_inner_ioctl(queue_t * q,mblk_t * mp)519 spppasyn_inner_ioctl(queue_t *q, mblk_t *mp)
520 {
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;
529
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);
534
535 error = EINVAL;
536 len = 0;
537
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;
543
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;
559 }
560 #ifdef REPORT_CRC_TYPE
561 else {
562 KSET(pks_outcrctype, 16);
563 }
564 #endif
565
566 /* Return success */
567 error = 0;
568 break;
569
570 case PPPIO_RFCS:
571 /* Check for valid option length */
572 if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
573 break;
574
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;
590 }
591 #ifdef REPORT_CRC_TYPE
592 else {
593 KSET(pks_incrctype, 16);
594 }
595 #endif
596
597 /* Return success */
598 error = 0;
599 break;
600
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;
607
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);
611
612 state->sa_xaccm[2] &= ~0x40000000; /* don't escape 0x5e */
613 state->sa_xaccm[3] |= 0x60000000; /* escape 0x7d, 0x7e */
614
615 error = 0;
616 break;
617
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;
623
624 state->sa_raccm = *(uint32_t *)mp->b_cont->b_rptr;
625
626 error = 0;
627 break;
628
629 case PPPIO_LASTMOD:
630 /* We already know this. */
631 state->sa_flags |= SAF_LASTMOD;
632 error = 0;
633 break;
634
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;
640
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);
646
647 /* set the multiplexing timer value */
648 if (mask & R_MUXMASK)
649 state->sa_timeout_usec = mux_flags;
650
651 error = 0;
652 break;
653
654 case PPPIO_CFLAGS:
655 if (iop->ioc_count != 2 * sizeof (uint32_t) ||
656 mp->b_cont == NULL)
657 break;
658
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;
670
671 case PPPIO_DEBUG:
672 if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
673 break;
674
675 flagval = *(uint32_t *)mp->b_cont->b_rptr;
676 if (flagval != PPPDBG_LOG + PPPDBG_AHDLC) {
677 putnext(q, mp);
678 return;
679 }
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;
685 }
686
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);
698 }
699 }
700
701 /*
702 * spppasyn_inner_mctl
703 *
704 * MT-Perimeters:
705 * exclusive inner
706 *
707 * Handle state-affecting M_CTL messages.
708 */
709 static void
spppasyn_inner_mctl(queue_t * q,mblk_t * mp)710 spppasyn_inner_mctl(queue_t *q, mblk_t *mp)
711 {
712 sppp_ahdlc_t *state;
713 int msglen;
714 int error;
715
716 ASSERT(q != NULL && mp != NULL);
717 state = (sppp_ahdlc_t *)q->q_ptr;
718 ASSERT(state != NULL);
719
720 msglen = MBLKL(mp);
721 error = 0;
722 switch (*mp->b_rptr) {
723 case PPPCTL_MTU:
724 /* Just ignore the MTU */
725 break;
726
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;
734
735 case PPPCTL_UNIT:
736 if (state->sa_ksp != NULL) {
737 error = EINVAL;
738 break;
739 }
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;
750 }
751
752 if (error > 0) {
753 KINCR(pks_ctlserr);
754 }
755 if (state->sa_flags & SAF_LASTMOD) {
756 freemsg(mp);
757 } else {
758 KINCR(pks_ctlsfwd);
759 putnext(q, mp);
760 }
761 }
762
763 /*
764 * spppasyn_wput()
765 *
766 * MT-Perimeters:
767 * exclusive inner.
768 *
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.
771 */
772 static int
spppasyn_wput(queue_t * q,mblk_t * mp)773 spppasyn_wput(queue_t *q, mblk_t *mp)
774 {
775 sppp_ahdlc_t *state;
776 struct iocblk *iop;
777 int error;
778 mblk_t *np;
779 struct ppp_stats64 *psp;
780 int msglen;
781
782 ASSERT(q != NULL && mp != NULL);
783 state = (sppp_ahdlc_t *)q->q_ptr;
784 ASSERT(state != NULL);
785
786 switch (MTYPE(mp)) {
787
788 case M_DATA:
789 /*
790 * A data packet - do character-stuffing and FCS, and
791 * send it onwards. The blocks are freed as we go.
792 */
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;
800
801 case M_IOCTL:
802
803 KINCR(pks_ioctls);
804 iop = (struct iocblk *)mp->b_rptr;
805
806 msglen = 0;
807
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);
819
820 case PPPIO_GCLEAN:
821 np = allocb(sizeof (uint32_t), BPRI_HI);
822 if (np == NULL) {
823 error = ENOSR;
824 break;
825 }
826 if (mp->b_cont != NULL) {
827 freemsg(mp->b_cont);
828 }
829 mp->b_cont = np;
830
831 *(uint32_t *)np->b_wptr = state->sa_flags & RCV_FLAGS;
832
833 msglen = sizeof (uint32_t);
834 np->b_wptr += msglen;
835 error = 0;
836 break;
837
838 case PPPIO_GETSTAT:
839 error = EINVAL;
840 break;
841
842 case PPPIO_GETSTAT64:
843 np = allocb(sizeof (*psp), BPRI_HI);
844 if (np == NULL) {
845 error = ENOSR;
846 break;
847 }
848 if (mp->b_cont != NULL) {
849 freemsg(mp->b_cont);
850 }
851 mp->b_cont = np;
852
853 psp = (struct ppp_stats64 *)np->b_wptr;
854 bzero((caddr_t)psp, sizeof (*psp));
855 psp->p = state->sa_stats;
856
857 msglen = sizeof (*psp);
858 np->b_wptr += msglen;
859 error = 0;
860 break;
861
862 case PPPIO_GTYPE:
863 np = allocb(sizeof (uint32_t), BPRI_HI);
864 if (np == NULL) {
865 error = ENOSR;
866 break;
867 }
868 if (mp->b_cont != NULL) {
869 freemsg(mp->b_cont);
870 }
871 mp->b_cont = np;
872
873 *(uint32_t *)np->b_wptr = PPPTYP_AHDLC;
874
875 msglen = sizeof (uint32_t);
876 np->b_wptr += msglen;
877 error = 0;
878 break;
879
880 default:
881 /* Unknown ioctl -- forward along */
882 KINCR(pks_ioctlsfwd);
883 putnext(q, mp);
884 return (0);
885 }
886
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);
894 }
895
896 break;
897
898 case M_CTL:
899 KINCR(pks_ctls);
900 spppasyn_inner_mctl(q, mp);
901 break;
902
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;
911 }
912
913 return (0);
914 }
915
916 /*
917 * spppasyn_rput()
918 *
919 * MT-Perimeters:
920 * exclusive inner.
921 *
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).
925 */
926 static int
spppasyn_rput(queue_t * q,mblk_t * mp)927 spppasyn_rput(queue_t *q, mblk_t *mp)
928 {
929 sppp_ahdlc_t *state;
930 mblk_t *mpnext;
931
932 ASSERT(q != NULL && mp != NULL);
933 state = (sppp_ahdlc_t *)q->q_ptr;
934 ASSERT(state != NULL);
935
936 switch (MTYPE(mp)) {
937
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;
946 }
947 break;
948
949 case M_HANGUP:
950 KINCR(pks_hangups);
951 state->sa_flags |= SAF_IFLUSH;
952 putnext(q, mp);
953 break;
954
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));
965 }
966 KINCR(pks_unknownrds);
967 putnext(q, mp);
968 break;
969 }
970
971 return (0);
972 }
973
974 /*
975 * ahdlc_encode
976 *
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.
980 *
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.
987 */
988 static mblk_t *
ahdlc_encode(queue_t * q,mblk_t * mp)989 ahdlc_encode(queue_t *q, mblk_t *mp)
990 {
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 #if defined(lint) || defined(_lint)
1005 uchar_t chr; /* lint likes this */
1006 #else
1007 int chr; /* not uchar_t; more efficient this way */
1008 /* with WorkShop compiler */
1009 #endif
1010 int is_lcp, is_ctrl;
1011 int code;
1012 hrtime_t hrtime;
1013 uint32_t flags; /* sampled copy of flags */
1014
1015 state = (sppp_ahdlc_t *)q->q_ptr;
1016
1017 /* Don't transmit anything obviously silly. */
1018 msglen = msgsize(mp);
1019 if (msglen < 4) {
1020 KINCR(pks_outrunts);
1021 freemsg(mp);
1022 (void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR);
1023 return (NULL);
1024 }
1025
1026 /*
1027 * Allocate an output buffer just large enough for most cases.
1028 * Based on original work in the ppp-2.2 AIX PPP driver, we
1029 * estimate the output size as 1.25 * input message length
1030 * plus 16. If this turns out to be too small, then we'll
1031 * allocate exactly one additional buffer with two times the
1032 * remaining input length (the maximum that could possibly be
1033 * required).
1034 */
1035 outmp_len = msglen + (msglen >> 2) + 16;
1036 outmp = allocb(outmp_len, BPRI_MED);
1037 if (outmp == NULL)
1038 goto outallocfail;
1039
1040 tp = outmp->b_wptr;
1041
1042 /*
1043 * Check if our last transmit happened within FLAG_TIME, using
1044 * the system's hrtime.
1045 */
1046 hrtime = gethrtime();
1047 if (ABS(hrtime - state->sa_hrtime) > FLAG_TIME) {
1048 *tp++ = PPP_FLAG;
1049 }
1050 state->sa_hrtime = hrtime;
1051 bcopy((caddr_t)state->sa_xaccm, (caddr_t)loc_xaccm, sizeof (loc_xaccm));
1052 flags = state->sa_flags;
1053
1054 /*
1055 * LCP messages must be sent using the default escaping
1056 * (ACCM). We bend this rule a little to allow LCP
1057 * Echo-Request through with the negotiated escaping so that
1058 * we can detect bad negotiated ACCM values. If the ACCM is
1059 * bad, echos will fail and take down the link.
1060 */
1061 is_lcp = is_ctrl = 0;
1062 code = MSG_BYTE(mp, 0);
1063 if (code == PPP_ALLSTATIONS) {
1064 if (MSG_BYTE(mp, 1) == PPP_UI) {
1065 code = MSG_BYTE(mp, 2);
1066 if (code == (PPP_LCP >> 8) &&
1067 MSG_BYTE(mp, 3) == (PPP_LCP & 0xFF)) {
1068 if (LCP_USE_DFLT(mp))
1069 is_lcp = 2;
1070 else
1071 is_lcp = 1; /* Echo-Request */
1072 } else if (!(code & 1) && code > 0x3F)
1073 is_ctrl = 1;
1074 }
1075 } else if (!(code & 1) && code > 0x3F)
1076 is_ctrl = 1;
1077
1078 /*
1079 * If it's LCP and not just an LCP Echo-Request, then we need
1080 * to drop back to default escaping rules temporarily.
1081 */
1082 if (is_lcp > 1) {
1083 /*
1084 * force escape on 0x00 through 0x1f
1085 * and, for RFC 1662 (and ISO 3309:1991), 0x80-0x9f.
1086 */
1087 loc_xaccm[0] = 0xffffffff;
1088 loc_xaccm[4] = 0xffffffff;
1089 }
1090
1091 fcs16 = PPPINITFCS16; /* Initial FCS is 0xffff */
1092 fcs32 = PPPINITFCS32;
1093
1094 /*
1095 * Process this block and the rest (if any) attached to this
1096 * one. Note that we quite intentionally ignore the type of
1097 * the buffer. The caller has checked that the first buffer
1098 * is M_DATA; all others must be so, and any that are not are
1099 * harmless driver errors.
1100 */
1101 curout = outmp;
1102 tpmax = outmp->b_datap->db_lim;
1103 do {
1104 dp = mp->b_rptr;
1105 while (dp < (ep = mp->b_wptr)) {
1106 /*
1107 * Calculate maximum safe run length for inner loop,
1108 * regardless of escaping.
1109 */
1110 outmp_len = (tpmax - tp) / 2;
1111 if (dp + outmp_len < ep)
1112 ep = dp + outmp_len;
1113
1114 /*
1115 * Select out on CRC type here to make the
1116 * inner byte loop more efficient. (We could
1117 * do both CRCs at all times if we wanted, but
1118 * that ends up taking an extra 8 cycles per
1119 * byte -- 47% overhead!)
1120 */
1121 if (flags & SAF_XMITCRC32) {
1122 while (dp < ep) {
1123 chr = *dp++;
1124 fcs32 = PPPFCS32(fcs32, chr);
1125 if (IN_TX_MAP(chr, loc_xaccm)) {
1126 *tp++ = PPP_ESCAPE;
1127 chr ^= PPP_TRANS;
1128 }
1129 *tp++ = chr;
1130 }
1131 } else {
1132 while (dp < ep) {
1133 chr = *dp++;
1134 fcs16 = PPPFCS16(fcs16, chr);
1135 if (IN_TX_MAP(chr, loc_xaccm)) {
1136 *tp++ = PPP_ESCAPE;
1137 chr ^= PPP_TRANS;
1138 }
1139 *tp++ = chr;
1140 }
1141 }
1142
1143 /*
1144 * If we limited our run length and we're now low
1145 * on output space, then allocate a new output buffer.
1146 * This should rarely happen, unless the output data
1147 * has a lot of escapes.
1148 */
1149 if (ep != mp->b_wptr && tpmax - tp < 5) {
1150 KINCR(pks_extrabufs);
1151 /* Get remaining message length */
1152 outmp_len = (mp->b_wptr - dp) +
1153 msgsize(mp->b_cont);
1154 /* Calculate maximum required space */
1155 outmp_len = (outmp_len + PPP_FCS32LEN) * 2 + 1;
1156 curout = allocb(outmp_len, BPRI_MED);
1157 if ((outmp->b_cont = curout) == NULL)
1158 goto outallocfail;
1159 outmp->b_wptr = tp;
1160 tp = curout->b_wptr;
1161 tpmax = curout->b_datap->db_lim;
1162 }
1163 }
1164 tmp = mp->b_cont;
1165 freeb(mp);
1166 mp = tmp;
1167 } while (mp != NULL);
1168
1169 /*
1170 * Make sure we have enough remaining room to add the CRC (if
1171 * any) and a trailing flag byte.
1172 */
1173 outmp_len = PPP_FCS32LEN * 2 + 1;
1174 if (tpmax - tp < outmp_len) {
1175 KINCR(pks_extrabufs);
1176 curout = allocb(outmp_len, BPRI_MED);
1177 if ((outmp->b_cont = curout) == NULL)
1178 goto outallocfail;
1179 outmp->b_wptr = tp;
1180 tp = curout->b_wptr;
1181 tpmax = curout->b_datap->db_lim;
1182 }
1183
1184 /*
1185 * Network layer data is the only thing that can be sent with
1186 * no CRC at all.
1187 */
1188 if ((flags & SAF_XMITCRCNONE) && !is_lcp && !is_ctrl)
1189 goto nocrc;
1190
1191 if (!(flags & SAF_XMITCRC32))
1192 fcs32 = fcs16;
1193
1194 /*
1195 * Append the HDLC FCS, making sure that escaping is done on any
1196 * necessary bytes. Note that the FCS bytes are in little-endian.
1197 */
1198 fcs32 = ~fcs32;
1199 chr = fcs32 & 0xff;
1200 if (IN_TX_MAP(chr, loc_xaccm)) {
1201 *tp++ = PPP_ESCAPE;
1202 chr ^= PPP_TRANS;
1203 }
1204 *tp++ = chr;
1205
1206 chr = (fcs32 >> 8) & 0xff;
1207 if (IN_TX_MAP(chr, loc_xaccm)) {
1208 *tp++ = PPP_ESCAPE;
1209 chr ^= PPP_TRANS;
1210 }
1211 *tp++ = chr;
1212
1213 if (flags & SAF_XMITCRC32) {
1214 chr = (fcs32 >> 16) & 0xff;
1215 if (IN_TX_MAP(chr, loc_xaccm)) {
1216 *tp++ = PPP_ESCAPE;
1217 chr ^= PPP_TRANS;
1218 }
1219 *tp++ = chr;
1220
1221 chr = (fcs32 >> 24) & 0xff;
1222 if (IN_TX_MAP(chr, loc_xaccm)) {
1223 *tp++ = PPP_ESCAPE;
1224 chr ^= PPP_TRANS;
1225 }
1226 *tp++ = chr;
1227 }
1228
1229 nocrc:
1230 /*
1231 * And finally append the HDLC flag, and send it away
1232 */
1233 *tp++ = PPP_FLAG;
1234 ASSERT(tp < tpmax);
1235 curout->b_wptr = tp;
1236
1237 state->sa_stats.ppp_obytes += msgsize(outmp);
1238 state->sa_stats.ppp_opackets++;
1239
1240 if (state->sa_flags & SAF_XMITDUMP)
1241 ppp_dump_frame(state, outmp, "sent");
1242
1243 KINCR(pks_dataout);
1244 return (outmp);
1245
1246 outallocfail:
1247 KINCR(pks_outallocfails);
1248 state->sa_stats.ppp_oerrors++;
1249 freemsg(outmp);
1250 freemsg(mp);
1251 (void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR);
1252 return (NULL);
1253 }
1254
1255 /*
1256 * Handle end-of-frame excitement. This is here mostly because the Solaris
1257 * C style rules require tab for indent and prohibit excessive indenting.
1258 */
1259 static mblk_t *
receive_frame(queue_t * q,mblk_t * outmp,ushort_t fcs16,uint32_t fcs32)1260 receive_frame(queue_t *q, mblk_t *outmp, ushort_t fcs16, uint32_t fcs32)
1261 {
1262 sppp_ahdlc_t *state = (sppp_ahdlc_t *)q->q_ptr;
1263 uchar_t *cp, *ep;
1264 int is_lcp, is_ctrl, crclen;
1265 ushort_t proto;
1266 int i;
1267
1268 cp = outmp->b_rptr;
1269 if (cp[0] == PPP_ALLSTATIONS && cp[1] == PPP_UI)
1270 cp += 2;
1271 proto = *cp++;
1272 if ((proto & 1) == 0)
1273 proto = (proto << 8) + *cp++;
1274 is_lcp = (proto == PPP_LCP);
1275 is_ctrl = (proto >= 0x4000);
1276
1277 /*
1278 * To allow for renegotiation, LCP accepts good CRCs of either
1279 * type at any time. Other control (non-network) packets must
1280 * have either CRC-16 or CRC-32, as negotiated. Network layer
1281 * packets may additionally omit the CRC entirely, if that was
1282 * negotiated.
1283 */
1284 if ((is_lcp && (fcs16 == PPPGOODFCS16 || fcs32 == PPPGOODFCS32)) ||
1285 ((fcs16 == PPPGOODFCS16 && !(state->sa_flags & SAF_RECVCRC32)) ||
1286 (fcs32 == PPPGOODFCS32 &&
1287 (state->sa_flags & SAF_RECVCRC32))) ||
1288 (!is_ctrl && !is_lcp && (state->sa_flags & SAF_RECVCRCNONE))) {
1289
1290 state->sa_stats.ppp_ipackets++;
1291 if (is_lcp) {
1292 crclen = (fcs16 == PPPGOODFCS16) ?
1293 PPP_FCSLEN : PPP_FCS32LEN;
1294 } else {
1295 crclen = (state->sa_flags & SAF_RECVCRC32) ?
1296 PPP_FCS32LEN : PPP_FCSLEN;
1297 if (!is_ctrl && (state->sa_flags & SAF_RECVCRCNONE))
1298 crclen = 0;
1299 }
1300 if (crclen != 0) {
1301 i = adjmsg(outmp, -crclen);
1302 ASSERT(i != 0);
1303 #if defined(lint) || defined(_lint)
1304 /* lint is happier this way in a non-DEBUG build */
1305 i = i;
1306 #endif
1307 }
1308
1309 if (proto == PPP_MUX) {
1310 /* spppasyn_inpkt checks for PPP_MUX packets */
1311 KINCR(pks_recvmux);
1312 /* Remove headers */
1313 outmp->b_rptr = cp;
1314 return (spppasyn_inpkt(q, outmp));
1315 }
1316
1317 /*
1318 * Sniff the received data stream. If we see an LCP
1319 * Configure-Ack, then pick out the ACCM setting, if
1320 * any, and configure now. This allows us to stay in
1321 * sync in case the peer is already out of Establish
1322 * phase.
1323 */
1324 if (is_lcp && *cp == 2) {
1325 ep = outmp->b_wptr;
1326 i = (cp[2] << 8) | cp[3];
1327 if (i > ep - cp)
1328 ep = cp; /* Discard junk */
1329 else if (i < ep - cp)
1330 ep = cp + i;
1331 cp += 4;
1332 while (cp + 2 < ep) {
1333 if ((i = cp[1]) < 2)
1334 i = 2;
1335 if (cp + i > ep)
1336 i = ep - cp;
1337 if (cp[0] == 2 && i >= 6) {
1338 state->sa_raccm = (cp[2] << 24) |
1339 (cp[3] << 16) | (cp[4] << 8) |
1340 cp[5];
1341 break;
1342 }
1343 cp += i;
1344 }
1345 }
1346 return (outmp);
1347 } else {
1348 KINCR(pks_incrcerrs);
1349 cmn_err(CE_CONT, PPP_DRV_NAME "%d: bad fcs (len=%ld)\n",
1350 state->sa_unit, msgsize(outmp));
1351
1352 if (state->sa_flags & SAF_RECVDUMP)
1353 ppp_dump_frame(state, outmp, "bad data");
1354
1355 freemsg(outmp);
1356
1357 state->sa_stats.ppp_ierrors++;
1358
1359 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1360 return (NULL);
1361 }
1362 }
1363
1364 /*
1365 * ahdlc_decode()
1366 *
1367 * Process received characters.
1368 *
1369 * This is handled as exclusive inner so that we don't get confused
1370 * about the state. Returns a list of packets linked by b_next.
1371 */
1372 static mblk_t *
ahdlc_decode(queue_t * q,mblk_t * mp)1373 ahdlc_decode(queue_t *q, mblk_t *mp)
1374 {
1375 sppp_ahdlc_t *state;
1376 mblk_t *retmp; /* list of packets to return */
1377 mblk_t *outmp; /* buffer for decoded data */
1378 mblk_t *mpnext; /* temporary ptr for unlinking */
1379 uchar_t *dp; /* pointer to input data */
1380 uchar_t *dpend; /* end of input data */
1381 uchar_t *tp; /* pointer to decoded output data */
1382 uchar_t *tpmax; /* output buffer limit */
1383 int flagtmp; /* temporary cache of flags */
1384 #if defined(lint) || defined(_lint)
1385 uchar_t chr; /* lint likes this */
1386 #else
1387 int chr; /* not uchar_t; more efficient this way */
1388 /* with WorkShop compiler */
1389 #endif
1390 ushort_t fcs16; /* running CRC-16 */
1391 uint32_t fcs32; /* running CRC-32 */
1392 #ifdef HANDLE_ZERO_LENGTH
1393 size_t nprocessed;
1394 #endif
1395
1396 state = (sppp_ahdlc_t *)q->q_ptr;
1397
1398 KINCR(pks_datain);
1399
1400 state->sa_stats.ppp_ibytes += msgsize(mp);
1401
1402 if (state->sa_flags & SAF_RECVDUMP)
1403 ppp_dump_frame(state, mp, "rcvd");
1404
1405 flagtmp = state->sa_flags;
1406 fcs16 = state->sa_infcs16;
1407 fcs32 = state->sa_infcs32;
1408 outmp = state->sa_rx_buf;
1409 if (outmp == NULL) {
1410 tp = tpmax = NULL;
1411 } else {
1412 tp = outmp->b_wptr;
1413 tpmax = outmp->b_datap->db_lim;
1414 }
1415 #ifdef HANDLE_ZERO_LENGTH
1416 nprocessed = 0;
1417 #endif
1418
1419 /*
1420 * Main input processing loop. Loop over received buffers and
1421 * each byte in each buffer. Note that we quite intentionally
1422 * ignore the type of the buffer. The caller has checked that
1423 * the first buffer is M_DATA; all others must be so, and any
1424 * that are not are harmless driver errors.
1425 */
1426 retmp = NULL;
1427 while (mp != NULL) {
1428
1429 /* Innermost loop -- examine bytes in buffer. */
1430 dpend = mp->b_wptr;
1431 dp = mp->b_rptr;
1432 #ifdef HANDLE_ZERO_LENGTH
1433 nprocessed += dpend - dp;
1434 #endif
1435 for (; dp < dpend; dp++) {
1436 chr = *dp;
1437
1438 /*
1439 * This should detect the lack of an 8-bit
1440 * communication channel, which is necessary
1441 * for PPP to work.
1442 */
1443 flagtmp |= charflags[chr];
1444
1445 /*
1446 * So we have a HDLC flag ...
1447 */
1448 if (chr == PPP_FLAG) {
1449
1450 /*
1451 * If there's no received buffer, then
1452 * just ignore this frame marker.
1453 */
1454 if ((flagtmp & SAF_IFLUSH) || outmp == NULL) {
1455 flagtmp &= ~SAF_IFLUSH & ~SAF_ESCAPED;
1456 continue;
1457 }
1458
1459 /*
1460 * Per RFC 1662 -- silently discard
1461 * runt frames (fewer than 4 octets
1462 * with 16 bit CRC) and frames that
1463 * end in 7D 7E (abort sequence).
1464 * These are not counted as errors.
1465 *
1466 * (We could just reset the pointers
1467 * and reuse the buffer, but this is a
1468 * rarely used error path and not
1469 * worth the optimization.)
1470 */
1471 if ((flagtmp & SAF_ESCAPED) ||
1472 tp - outmp->b_rptr < 2 + PPP_FCSLEN) {
1473 if (flagtmp & SAF_ESCAPED)
1474 KINCR(pks_inaborts);
1475 else
1476 KINCR(pks_inrunts);
1477 if (state->sa_flags & SAF_RECVDUMP) {
1478 outmp->b_wptr = tp;
1479 ppp_dump_frame(state, outmp,
1480 "runt");
1481 }
1482 freemsg(outmp);
1483 flagtmp &= ~SAF_ESCAPED;
1484 } else {
1485 /* Handle the received frame */
1486 outmp->b_wptr = tp;
1487 outmp = receive_frame(q, outmp, fcs16,
1488 fcs32);
1489 retmp = sppp_mappend(retmp, outmp);
1490 }
1491
1492 outmp = NULL;
1493 tp = tpmax = NULL;
1494
1495 continue;
1496 }
1497
1498 /* If we're waiting for a new frame, then drop data. */
1499 if (flagtmp & SAF_IFLUSH) {
1500 continue;
1501 }
1502
1503 /*
1504 * Start of new frame. Allocate a receive
1505 * buffer large enough to store a frame (after
1506 * un-escaping) of at least 1500 octets plus
1507 * the CRC. If MRU is negotiated to be more
1508 * than the default, then allocate that much.
1509 * In addition, we add an extra 32-bytes for a
1510 * fudge factor, in case the peer doesn't do
1511 * arithmetic very well.
1512 */
1513 if (outmp == NULL) {
1514 int maxlen;
1515
1516 if ((maxlen = state->sa_mru) < PPP_MRU)
1517 maxlen = PPP_MRU;
1518 maxlen += PPP_FCS32LEN + 32;
1519 outmp = allocb(maxlen, BPRI_MED);
1520
1521 /*
1522 * If allocation fails, try again on
1523 * the next frame. (Go into discard
1524 * mode.)
1525 */
1526 if (outmp == NULL) {
1527 KINCR(pks_inallocfails);
1528 flagtmp |= SAF_IFLUSH;
1529 continue;
1530 }
1531
1532 tp = outmp->b_wptr;
1533 tpmax = outmp->b_datap->db_lim;
1534
1535 /* Neither flag can possibly be set here. */
1536 flagtmp &= ~(SAF_IFLUSH | SAF_ESCAPED);
1537 fcs16 = PPPINITFCS16;
1538 fcs32 = PPPINITFCS32;
1539 }
1540
1541 /*
1542 * If the peer sends us a character that's in
1543 * our receive character map, then that's
1544 * junk. Discard it without changing state.
1545 * If they previously sent us an escape
1546 * character, then toggle this one and
1547 * continue. Otherwise, if they're now sending
1548 * escape, set the flag for next time.
1549 */
1550 if (IN_RX_MAP(chr, state->sa_raccm)) {
1551 KINCR(pks_inbadchars);
1552 KOR(pks_inbadcharmask, 1 << chr);
1553 continue;
1554 }
1555 if (flagtmp & SAF_ESCAPED) {
1556 chr ^= PPP_TRANS;
1557 flagtmp &= ~SAF_ESCAPED;
1558 } else if (chr == PPP_ESCAPE) {
1559 flagtmp |= SAF_ESCAPED;
1560 continue;
1561 }
1562
1563 /*
1564 * Unless the peer is confused about the
1565 * negotiated MRU, we should never get a frame
1566 * that is too long. If it happens, toss it
1567 * away and begin discarding data until we see
1568 * the end of the frame.
1569 */
1570 if (tp < tpmax) {
1571 fcs16 = PPPFCS16(fcs16, chr);
1572 fcs32 = PPPFCS32(fcs32, chr);
1573 *tp++ = chr;
1574 } else {
1575 KINCR(pks_intoolongs);
1576 cmn_err(CE_CONT, PPP_DRV_NAME
1577 "%d: frame too long (%d bytes)\n",
1578 state->sa_unit,
1579 (int)(tpmax - outmp->b_rptr));
1580
1581 freemsg(outmp);
1582 outmp = NULL;
1583 tp = tpmax = NULL;
1584 flagtmp |= SAF_IFLUSH;
1585 }
1586 }
1587
1588 /*
1589 * Free the buffer we just processed and move on to
1590 * the next one.
1591 */
1592 mpnext = mp->b_cont;
1593 freeb(mp);
1594 mp = mpnext;
1595 }
1596 state->sa_flags = flagtmp;
1597 if ((state->sa_rx_buf = outmp) != NULL)
1598 outmp->b_wptr = tp;
1599 state->sa_infcs16 = fcs16;
1600 state->sa_infcs32 = fcs32;
1601
1602 #ifdef HANDLE_ZERO_LENGTH
1603 if (nprocessed <= 0) {
1604 outmp = allocb(0, BPRI_MED);
1605 if (outmp != NULL) {
1606 outmp->b_datap->db_type = M_HANGUP;
1607 retmp = sppp_mappend(retmp, outmp);
1608 }
1609 }
1610 #endif
1611 return (retmp);
1612 }
1613
1614 /*
1615 * Nifty packet dumper; copied from AIX 4.1 port. This routine dumps
1616 * the raw received and transmitted data through syslog. This allows
1617 * debug of communications problems without resorting to a line
1618 * analyzer.
1619 *
1620 * The expression "3*BYTES_PER_LINE" used frequently here represents
1621 * the size of each hex value printed -- two hex digits and a space.
1622 */
1623 #define BYTES_PER_LINE 8
1624 static void
ppp_dump_frame(sppp_ahdlc_t * state,mblk_t * mptr,const char * msg)1625 ppp_dump_frame(sppp_ahdlc_t *state, mblk_t *mptr, const char *msg)
1626 {
1627 /*
1628 * Buffer is big enough for hex digits, two spaces, ASCII output,
1629 * and one NUL byte.
1630 */
1631 char buf[3 * BYTES_PER_LINE + 2 + BYTES_PER_LINE + 1];
1632 uchar_t *rptr, *eptr;
1633 int i, chr;
1634 char *bp;
1635 static const char digits[] = "0123456789abcdef";
1636
1637 cmn_err(CE_CONT, "!ppp_async%d: %s %ld bytes\n", state->sa_unit,
1638 msg, msgsize(mptr));
1639 i = 0;
1640 bp = buf;
1641 /* Add filler spaces between hex output and ASCII */
1642 buf[3 * BYTES_PER_LINE] = ' ';
1643 buf[3 * BYTES_PER_LINE + 1] = ' ';
1644 /* Add NUL byte at end */
1645 buf[sizeof (buf) - 1] = '\0';
1646 while (mptr != NULL) {
1647 rptr = mptr->b_rptr; /* get pointer to beginning */
1648 eptr = mptr->b_wptr;
1649 while (rptr < eptr) {
1650 chr = *rptr++;
1651 /* convert byte to ascii hex */
1652 *bp++ = digits[chr >> 4];
1653 *bp++ = digits[chr & 0xf];
1654 *bp++ = ' ';
1655 /* Insert ASCII past hex output and filler */
1656 buf[3 * BYTES_PER_LINE + 2 + i] =
1657 (chr >= 0x20 && chr <= 0x7E) ? (char)chr : '.';
1658 i++;
1659 if (i >= BYTES_PER_LINE) {
1660 cmn_err(CE_CONT, "!ppp%d: %s\n", state->sa_unit,
1661 buf);
1662 bp = buf;
1663 i = 0;
1664 }
1665 }
1666 mptr = mptr->b_cont;
1667 }
1668 if (bp > buf) {
1669 /* fill over unused hex display positions */
1670 while (bp < buf + 3 * BYTES_PER_LINE)
1671 *bp++ = ' ';
1672 /* terminate ASCII string at right position */
1673 buf[3 * BYTES_PER_LINE + 2 + i] = '\0';
1674 cmn_err(CE_CONT, "!ppp%d: %s\n", state->sa_unit, buf);
1675 }
1676 }
1677
1678 static mblk_t *
spppasyn_muxencode(queue_t * q,mblk_t * mp)1679 spppasyn_muxencode(queue_t *q, mblk_t *mp)
1680 {
1681 sppp_ahdlc_t *state = (sppp_ahdlc_t *)q->q_ptr;
1682 uint32_t len;
1683 uint32_t nlen;
1684 ushort_t protolen;
1685 uint32_t hdrlen;
1686 ushort_t proto;
1687 mblk_t *new_frame;
1688 mblk_t *tmp;
1689 mblk_t *send_frame;
1690 ushort_t i;
1691
1692 len = msgdsize(mp);
1693 i = 0;
1694 protolen = 1;
1695 proto = MSG_BYTE(mp, i);
1696
1697 if (proto == PPP_ALLSTATIONS) {
1698 len -= 2;
1699 i += 2;
1700 proto = MSG_BYTE(mp, i);
1701 }
1702
1703 ++i;
1704 if ((proto & 1) == 0) {
1705 proto = (proto << 8) + MSG_BYTE(mp, i);
1706 protolen++;
1707 }
1708
1709 hdrlen = i - 1;
1710
1711 send_frame = NULL;
1712 if (len > PPP_MAX_MUX_LEN || (proto & 0x8000)) {
1713
1714 /* send the queued frames */
1715 if (state->sa_mqhead != NULL) {
1716 /* increment counter if it is MUX pkt */
1717 if (state->sa_mqtail != NULL)
1718 KINCR(pks_sentmux);
1719 send_frame = ahdlc_encode(q, state->sa_mqhead);
1720 }
1721
1722 /* send the current frame */
1723 mp = ahdlc_encode(q, mp);
1724 send_frame = sppp_mcat(send_frame, mp);
1725
1726 /* reset the state values over here */
1727 RESET_MUX_VALUES(state);
1728 return (send_frame);
1729 }
1730
1731 /* len + 1 , since we add the mux overhead */
1732 nlen = len + 1;
1733 /* subtract the protocol length if protocol matches */
1734 if (state->sa_proto == proto)
1735 nlen -= protolen;
1736
1737 send_frame = NULL;
1738 if ((state->sa_mqlen + nlen) >= state->sa_mru) {
1739
1740 /* send the existing queued frames */
1741 if (state->sa_mqhead != NULL) {
1742 /* increment counter if it is MUX pkt */
1743 if (state->sa_mqtail != NULL)
1744 KINCR(pks_sentmux);
1745 send_frame = ahdlc_encode(q, state->sa_mqhead);
1746 }
1747
1748 /* reset state values */
1749 RESET_MUX_VALUES(state);
1750 }
1751
1752 /* add the current frame to the queue */
1753 if (state->sa_mqhead != NULL) {
1754
1755 if (state->sa_mqtail == NULL) {
1756
1757 /*
1758 * this is the first mblk in the queue create
1759 * a new frame to hold the PPP MUX header
1760 */
1761 if ((new_frame = allocb(PPP_HDRLEN+1,
1762 BPRI_MED)) == NULL) {
1763 return (send_frame);
1764 }
1765
1766 if (!IS_COMP_AC(state)) {
1767 /* add the header */
1768 *new_frame->b_wptr++ = PPP_ALLSTATIONS;
1769 *new_frame->b_wptr++ = PPP_UI;
1770 }
1771
1772 /* do protocol compression */
1773 if (IS_COMP_PROT(state)) {
1774 *new_frame->b_wptr++ = PPP_MUX;
1775 } else {
1776 *new_frame->b_wptr++ = 0;
1777 *new_frame->b_wptr++ = PPP_MUX;
1778 }
1779
1780 *new_frame->b_wptr++ = PFF |
1781 (state->sa_mqlen - protolen - 1);
1782
1783 if (DB_REF(mp) > 1) {
1784 tmp = copymsg(state->sa_mqhead);
1785 freemsg(state->sa_mqhead);
1786 if ((state->sa_mqhead = tmp) == NULL) {
1787 return (send_frame);
1788 }
1789 }
1790
1791 if (state->sa_mqhead->b_rptr[0] == PPP_ALLSTATIONS)
1792 state->sa_mqhead->b_rptr += 2;
1793
1794 linkb(new_frame, state->sa_mqhead);
1795 state->sa_mqtail = state->sa_mqhead;
1796 /* point mqtail to the last mblk_t */
1797 while (state->sa_mqtail->b_cont != NULL)
1798 state->sa_mqtail = state->sa_mqtail->b_cont;
1799
1800 /* change state->sa_mqhead */
1801 state->sa_mqhead = new_frame;
1802
1803 }
1804
1805 if (state->sa_proto == proto) {
1806
1807 /* Check if the mblk_t is being referenced */
1808 if (DB_REF(mp) > 1) {
1809 tmp = copymsg(mp);
1810 freemsg(mp);
1811 if ((mp = tmp) == NULL) {
1812 return (send_frame);
1813 }
1814 }
1815
1816 /*
1817 * match,can remove the protocol field
1818 * and write data there
1819 */
1820 mp->b_rptr += hdrlen;
1821 /*
1822 * protolen - 1 ,because the the byte with
1823 * the PFF bit and the length field have
1824 * to added
1825 */
1826 mp->b_rptr += (protolen - 1);
1827 *mp->b_rptr = (len - protolen) & 0xff;
1828
1829 } else {
1830 /*
1831 * no match, there are three options
1832 * 1. write in mp
1833 * 2. write in mqtail
1834 * 3. alloc a new blk for just one byte
1835 */
1836 /* Check if the mblk_t is being referenced */
1837 if (DB_REF(mp) > 1) {
1838 tmp = copymsg(mp);
1839 freemsg(mp);
1840 if ((mp = tmp) == NULL) {
1841 return (send_frame);
1842 }
1843 }
1844
1845 if (hdrlen != 0) {
1846
1847 mp->b_rptr += (hdrlen-1);
1848 *mp->b_rptr = PFF | (len);
1849
1850 } else if (state->sa_mqtail->b_wptr <
1851 DB_LIM(state->sa_mqtail)) {
1852 *state->sa_mqtail->b_wptr++ = PFF |len;
1853 } else {
1854 /* allocate a new mblk & add the byte */
1855 /* write the data */
1856 if ((new_frame = allocb(1, BPRI_MED))
1857 == NULL) {
1858 freemsg(mp);
1859 return (send_frame);
1860 }
1861 *new_frame->b_wptr++ = PFF | (len);
1862 linkb(state->sa_mqtail, new_frame);
1863 }
1864
1865 /* update proto */
1866 state->sa_proto = proto;
1867 }
1868
1869 linkb(state->sa_mqtail, mp);
1870 state->sa_mqtail = mp;
1871 while (state->sa_mqtail->b_cont != NULL)
1872 state->sa_mqtail = state->sa_mqtail->b_cont;
1873 state->sa_mqlen += nlen;
1874
1875 } else {
1876 state->sa_mqhead = mp;
1877 state->sa_mqlen = len + protolen + 1;
1878 state->sa_proto = proto;
1879 }
1880
1881 if (state->sa_timeout_id == 0) {
1882 state->sa_timeout_id = qtimeout(q, spppasyn_timer, q,
1883 (drv_usectohz(state->sa_timeout_usec)));
1884 }
1885 return (send_frame);
1886 }
1887
1888 /*
1889 * Called from receive frame, this routine checks if it is a PPP_MUX
1890 * packet and demuxes it. The returned pointer is a chain of mblks
1891 * using b_next and representing the demultiplexed packets.
1892 */
1893 static mblk_t *
spppasyn_inpkt(queue_t * q,mblk_t * mp)1894 spppasyn_inpkt(queue_t *q, mblk_t *mp)
1895 {
1896 sppp_ahdlc_t *state = (sppp_ahdlc_t *)q->q_ptr;
1897 ushort_t proto;
1898 ushort_t prev_proto;
1899 uint32_t len; /* length of subframe */
1900 uchar_t muxhdr;
1901 mblk_t *hdrmp;
1902 mblk_t *subframe;
1903 mblk_t *retmp;
1904
1905 if (!(mp->b_rptr[0] & PFF)) {
1906 KINCR(pks_inmuxerrs);
1907 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1908 freemsg(mp);
1909 return (NULL);
1910 }
1911
1912 /* initialise the Last protocol and protocol length */
1913 prev_proto = 0;
1914
1915 /*
1916 * Taking into granted that the decoded frame is contiguous
1917 */
1918 retmp = NULL;
1919 while (mp->b_rptr < mp->b_wptr) {
1920
1921 /*
1922 * get the last protocol, protocol length
1923 * and the length of the message
1924 */
1925
1926 /* protocol field flag and length */
1927 muxhdr = mp->b_rptr[0];
1928 len = muxhdr & ~PFF;
1929
1930 mp->b_rptr++;
1931
1932 /* check if there and enough bytes left in pkt */
1933 if (MBLKL(mp) < len) {
1934 KINCR(pks_inmuxerrs);
1935 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1936 break;
1937 }
1938
1939 /* allocate memory for the header length */
1940 if ((hdrmp = allocb(PPP_HDRLEN, BPRI_MED)) == NULL) {
1941 KINCR(pks_inallocfails);
1942 break;
1943 }
1944
1945 /* add the ppp header to the pkt */
1946 *hdrmp->b_wptr++ = PPP_ALLSTATIONS;
1947 *hdrmp->b_wptr++ = PPP_UI;
1948
1949 /* check if the protocol field flag is set */
1950 if (muxhdr & PFF) {
1951
1952 /* get the protocol */
1953 proto = MSG_BYTE(mp, 0);
1954 if ((proto & 1) == 0)
1955 proto = (proto << 8) + MSG_BYTE(mp, 1);
1956
1957 /* reset values */
1958 prev_proto = proto;
1959 } else {
1960 if (!IS_DECOMP_PROT(state))
1961 *hdrmp->b_wptr++ = prev_proto >> 8;
1962 *hdrmp->b_wptr++ = (prev_proto & 0xff);
1963 }
1964
1965 /* get the payload from the MUXed packet */
1966 subframe = dupmsg(mp);
1967 subframe->b_wptr = mp->b_rptr + len;
1968
1969 /* link the subframe to the new frame */
1970 linkb(hdrmp, subframe);
1971
1972 /* do a putnext */
1973 retmp = sppp_mappend(retmp, hdrmp);
1974
1975 /* move the read pointer beyond this subframe */
1976 mp->b_rptr += len;
1977 }
1978
1979 freemsg(mp);
1980 return (retmp);
1981 }
1982
1983
1984 /*
1985 * timer routine which sends out the queued pkts *
1986 */
1987 static void
spppasyn_timer(void * arg)1988 spppasyn_timer(void *arg)
1989 {
1990 queue_t *q;
1991 sppp_ahdlc_t *state;
1992 mblk_t *mp;
1993
1994 ASSERT(arg);
1995 q = (queue_t *)arg;
1996 state = (sppp_ahdlc_t *)q->q_ptr;
1997
1998 if (state->sa_mqhead != NULL) {
1999 /* increment counter */
2000 if (state->sa_mqtail != NULL)
2001 KINCR(pks_sentmux);
2002 if ((mp = ahdlc_encode(q, state->sa_mqhead)) != NULL)
2003 putnext(q, mp);
2004 /* reset the state values over here */
2005 RESET_MUX_VALUES(state);
2006 }
2007 /* clear timeout_id */
2008 state->sa_timeout_id = 0;
2009 }
2010