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 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/stream.h>
48 #include <sys/strsun.h>
49 #include <sys/sysmacros.h>
50 #include <sys/errno.h>
51 #include <sys/conf.h>
52 #include <sys/kmem.h>
53 #include <sys/crc32.h>
54 #include <sys/cmn_err.h>
55 #include <sys/ddi.h>
56
57 #include <net/ppp_defs.h>
58 #include <net/pppio.h>
59
60 #include "s_common.h"
61
62 #ifdef DEBUG
63 #define REPORT_CRC_TYPE
64 #endif
65 #include "spppasyn.h"
66
67 /*
68 * This is used to tag official Solaris sources. Please do not define
69 * "INTERNAL_BUILD" when building this software outside of Sun
70 * Microsystems.
71 */
72 #ifdef INTERNAL_BUILD
73 /* MODINFO is limited to 32 characters. */
74 const char spppasyn_module_description[] = "PPP 4.0 AHDLC";
75 #else /* INTERNAL_BUILD */
76 const char spppasyn_module_description[] = "ANU PPP AHDLC $Revision: 1.16$";
77
78 /* LINTED */
79 static const char buildtime[] = "Built " __DATE__ " at " __TIME__
80 #ifdef DEBUG
81 " DEBUG"
82 #endif
83 "\n";
84 #endif /* INTERNAL_BUILD */
85
86 static int spppasyn_open(queue_t *, dev_t *, int, int, cred_t *);
87 static int spppasyn_close(queue_t *, int, cred_t *);
88 static int spppasyn_wput(queue_t *, mblk_t *);
89 static int spppasyn_rput(queue_t *, mblk_t *);
90 static mblk_t *ahdlc_encode(queue_t *, mblk_t *);
91 static mblk_t *ahdlc_decode(queue_t *, mblk_t *);
92 static void spppasyn_timer(void *);
93 static mblk_t *spppasyn_inpkt(queue_t *, mblk_t *);
94 static mblk_t *spppasyn_muxencode(queue_t *, mblk_t *);
95
96 #define RESET_MUX_VALUES(x) { \
97 x->sa_mqhead = x->sa_mqtail = NULL; \
98 x->sa_proto = 0; \
99 x->sa_mqlen = 0; \
100 }
101 #define IS_XMUX_ENABLED(x) \
102 ((x)->sa_flags & X_MUXMASK)
103 #define IS_RMUX_ENABLED(x) \
104 ((x)->sa_flags & R_MUXMASK)
105 #define IS_COMP_AC(x) \
106 ((x)->sa_flags & SAF_XCOMP_AC)
107 #define IS_COMP_PROT(x) \
108 ((x)->sa_flags & SAF_XCOMP_PROT)
109 #define IS_DECOMP_PROT(x) \
110 ((x)->sa_flags & SAF_RDECOMP_PROT)
111
112 /*
113 * Don't send HDLC start flag if last transmit is within 1.5 seconds -
114 * FLAG_TIME is defined in nanoseconds.
115 */
116 #define FLAG_TIME 1500000000ul
117
118 /*
119 * The usual AHDLC implementation enables the default escaping for all
120 * LCP frames. LCP_USE_DFLT() is used in this implementation to
121 * modify this rule slightly. If the code number happens to be
122 * Echo-Request, Echo-Reply, or Discard-Request (each of which may be
123 * sent only when LCP is in Opened state), then one may also use the
124 * negotiated ACCM; the RFC is silent on this. The theory is that
125 * pppd can construct Echo-Request messages that are guaranteed to
126 * fail if the negotiated ACCM is bad.
127 */
128 #define LCP_USE_DFLT(mp) ((code = MSG_BYTE((mp), 4)) < 9 || code > 11)
129
130 /*
131 * Extract bit c from map m, to determine if character c needs to be
132 * escaped. Map 'm' is a pointer to a 256 bit map; 8 words of 32 bits
133 * each.
134 */
135 #define IN_TX_MAP(c, m) \
136 ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
137
138 /*
139 * Checks the 32-bit receive ACCM to see if the byte should have been
140 * escaped by peer.
141 */
142 #define IN_RX_MAP(c, m) (((c) < 0x20) && ((m) & (1 << (c))))
143
144 static struct module_info spppasyn_modinfo = {
145 AHDLC_MOD_ID, /* mi_idnum */
146 AHDLC_MOD_NAME, /* mi_idname */
147 0, /* mi_minpsz */
148 INFPSZ, /* mi_maxpsz */
149 0, /* mi_hiwat */
150 0 /* mi_lowat */
151 };
152
153 static struct qinit spppasyn_rinit = {
154 spppasyn_rput, /* qi_putp */
155 NULL, /* qi_srvp */
156 spppasyn_open, /* qi_qopen */
157 spppasyn_close, /* qi_qclose */
158 NULL, /* qi_qadmin */
159 &spppasyn_modinfo, /* qi_minfo */
160 NULL /* qi_mstat */
161 };
162
163 static struct qinit spppasyn_winit = {
164 spppasyn_wput, /* qi_putp */
165 NULL, /* qi_srvp */
166 NULL, /* qi_qopen */
167 NULL, /* qi_qclose */
168 NULL, /* qi_qadmin */
169 &spppasyn_modinfo, /* qi_minfo */
170 NULL /* qi_mstat */
171 };
172
173 struct streamtab spppasyn_tab = {
174 &spppasyn_rinit, /* st_rdinit */
175 &spppasyn_winit, /* st_wrinit */
176 NULL, /* st_muxrinit */
177 NULL, /* st_muxwinit */
178 };
179
180 /* Matches above structure. */
181 static const char *kstat_names[] = {
182 "ioctls", "ioctlsfwd", "ioctlserr", "ctls",
183 "ctlsfwd", "ctlserr", "inbadchars", "inbadcharmask",
184 "inaborts", "inrunts", "inallocfails", "intoolongs",
185 "outrunts", "outallocfails", "incrcerrs", "unknownwrs",
186 "unknownrds", "hangups", "datain", "dataout",
187 "extrabufs", "sentmux", "recvmux", "inmuxerrs",
188 #ifdef REPORT_CRC_TYPE
189 "incrctype", "outcrctype",
190 #endif
191 };
192
193 /* So. This is why we have optimizing compilers. */
194 #define KVAL(vn) state->sa_kstats.vn.value.ui32
195 #define KSET(vn, v) KVAL(vn) = (v)
196 #define KADD(vn, v) KSET(vn, KVAL(vn) + (v))
197 #define KOR(vn, v) KSET(vn, KVAL(vn) | (v))
198 #define KINCR(vn) KADD(vn, 1)
199
200 static void ppp_dump_frame(sppp_ahdlc_t *state, mblk_t *mptr,
201 const char *msg);
202
203 /*
204 * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also.
205 */
206 #define RCV_FLAGS (RCV_B7_1 | RCV_B7_0 | RCV_ODDP | RCV_EVNP)
207
208 /*
209 * FCS lookup table as calculated by genfcstab.
210 */
211 static ushort_t fcstab[256] = {
212 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
213 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
214 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
215 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
216 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
217 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
218 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
219 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
220 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
221 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
222 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
223 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
224 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
225 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
226 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
227 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
228 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
229 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
230 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
231 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
232 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
233 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
234 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
235 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
236 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
237 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
238 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
239 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
240 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
241 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
242 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
243 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
244 };
245
246 /*
247 * Per-character flags for accumulating input errors. Flags are
248 * accumulated for bit 7 set to 0, bit 7 set to 1, even parity
249 * characters, and odd parity characters. The link should see all
250 * four in the very first LCP Configure-Request if all is ok. (C0 is
251 * even parity and has bit 7 set to 1, and 23 is odd parity and has
252 * bit 7 set to 0.)
253 */
254 static uchar_t charflags[256] = {
255 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
256 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
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_EVNP, RCV_B7_0|RCV_ODDP,
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_ODDP, RCV_B7_0|RCV_EVNP,
261 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
262 RCV_B7_0|RCV_ODDP, 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_ODDP,
264 RCV_B7_0|RCV_EVNP, 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_EVNP, RCV_B7_0|RCV_ODDP,
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_ODDP, RCV_B7_0|RCV_EVNP, 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_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP,
272 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
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_EVNP, RCV_B7_0|RCV_ODDP,
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_ODDP, RCV_B7_0|RCV_EVNP,
277 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
278 RCV_B7_0|RCV_ODDP, 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_ODDP,
280 RCV_B7_0|RCV_EVNP, 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_EVNP,
282 RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
283 RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP, 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_EVNP, RCV_B7_0|RCV_ODDP, 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_ODDP,
288 RCV_B7_0|RCV_EVNP, 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_EVNP, RCV_B7_0|RCV_ODDP,
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_ODDP, RCV_B7_0|RCV_EVNP,
293 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
294 RCV_B7_0|RCV_ODDP, 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_ODDP,
296 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_0|RCV_EVNP,
297 RCV_B7_0|RCV_EVNP, RCV_B7_0|RCV_ODDP, RCV_B7_1|RCV_ODDP,
298 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
299 RCV_B7_1|RCV_EVNP, RCV_B7_1|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_ODDP, RCV_B7_1|RCV_EVNP, 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_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
304 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
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_EVNP, RCV_B7_1|RCV_ODDP,
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_ODDP, RCV_B7_1|RCV_EVNP, 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_EVNP,
312 RCV_B7_1|RCV_ODDP, 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_ODDP,
314 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP,
315 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, 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_ODDP, RCV_B7_1|RCV_EVNP, 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_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
320 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
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_EVNP, RCV_B7_1|RCV_ODDP,
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_ODDP, RCV_B7_1|RCV_EVNP,
325 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
326 RCV_B7_1|RCV_ODDP, 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_ODDP,
328 RCV_B7_1|RCV_EVNP, 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_EVNP, RCV_B7_1|RCV_ODDP,
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_ODDP, RCV_B7_1|RCV_EVNP, 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_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
336 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_EVNP,
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_EVNP, RCV_B7_1|RCV_ODDP,
339 RCV_B7_1|RCV_EVNP, RCV_B7_1|RCV_ODDP, RCV_B7_1|RCV_ODDP,
340 RCV_B7_1|RCV_EVNP
341 };
342
343 /*
344 * Append two lists; preserve message boundaries.
345 * Warning: uses b_next.
346 */
347 static mblk_t *
sppp_mappend(mblk_t * m1,mblk_t * m2)348 sppp_mappend(mblk_t *m1, mblk_t *m2)
349 {
350 mblk_t *mret;
351
352 if (m1 == NULL)
353 return (m2);
354 if (m2 == NULL)
355 return (m1);
356
357 mret = m1;
358 while (m1->b_next != NULL)
359 m1 = m1->b_next;
360 m1->b_next = m2;
361 return (mret);
362 }
363
364 /*
365 * Concatenate two mblk lists.
366 */
367 static mblk_t *
sppp_mcat(mblk_t * m1,mblk_t * m2)368 sppp_mcat(mblk_t *m1, mblk_t *m2)
369 {
370 mblk_t *mret;
371
372 if (m1 == NULL)
373 return (m2);
374 if (m2 == NULL)
375 return (m1);
376
377 mret = m1;
378 while (m1->b_cont != NULL)
379 m1 = m1->b_cont;
380 m1->b_cont = m2;
381 return (mret);
382 }
383
384 /*
385 * spppasyn_open()
386 *
387 * STREAMS module open (entry) point. Called when spppasyn is pushed
388 * onto an asynchronous serial stream.
389 */
390 /* ARGSUSED */
391 static int
spppasyn_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)392 spppasyn_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
393 {
394 sppp_ahdlc_t *state;
395
396 ASSERT(q != NULL);
397
398 if (q->q_ptr != NULL) {
399 return (0); /* return if already opened */
400 }
401
402 if (sflag != MODOPEN) {
403 return (EINVAL); /* only open as a module */
404 }
405
406 state = (sppp_ahdlc_t *)kmem_zalloc(sizeof (sppp_ahdlc_t), KM_SLEEP);
407 ASSERT(state != NULL);
408
409 q->q_ptr = (caddr_t)state;
410 WR(q)->q_ptr = (caddr_t)state;
411
412 state->sa_xaccm[0] = 0xffffffff; /* escape 0x00 through 0x1f */
413 state->sa_xaccm[3] = 0x60000000; /* escape 0x7d and 0x7e */
414 state->sa_mru = PPP_MRU; /* default of 1500 bytes */
415
416 qprocson(q);
417
418 return (0);
419 }
420
421 /*
422 * spppasyn_close()
423 *
424 * STREAMS module close (exit) point
425 */
426 /* ARGSUSED */
427 static int
spppasyn_close(queue_t * q,int flag,cred_t * credp)428 spppasyn_close(queue_t *q, int flag, cred_t *credp)
429 {
430 sppp_ahdlc_t *state;
431
432 ASSERT(q != NULL);
433 state = (sppp_ahdlc_t *)q->q_ptr;
434 ASSERT(state != NULL);
435
436 /* We're leaving now. No more calls, please. */
437 qprocsoff(q);
438
439 if (state->sa_rx_buf != NULL) {
440 freemsg(state->sa_rx_buf);
441 state->sa_rx_buf = NULL;
442 }
443
444 if (state->sa_ksp != NULL) {
445 kstat_delete(state->sa_ksp);
446 state->sa_ksp = NULL;
447 }
448
449 if (state->sa_mqhead != NULL)
450 freemsg(state->sa_mqhead);
451 /* remove the time out routine */
452 if (state->sa_timeout_id != 0)
453 (void) quntimeout(q, state->sa_timeout_id);
454
455 q->q_ptr = NULL;
456 WR(q)->q_ptr = NULL;
457 kmem_free(state, sizeof (sppp_ahdlc_t));
458
459 return (0);
460 }
461
462 /*
463 * Create the standard kernel statistics structure and attach it to
464 * the current state structure. This can be called only after
465 * assigning the unit number.
466 */
467 static void
create_kstats(sppp_ahdlc_t * state)468 create_kstats(sppp_ahdlc_t *state)
469 {
470 kstat_t *ksp;
471 char unitname[KSTAT_STRLEN];
472 int nstat, i;
473 kstat_named_t *knt;
474
475 nstat = sizeof (state->sa_kstats) / sizeof (kstat_named_t);
476 knt = (kstat_named_t *)&state->sa_kstats;
477 for (i = 0; i < nstat; i++, knt++) {
478 #ifdef DEBUG
479 /* Just in case I do something silly here. */
480 if (i >= sizeof (kstat_names) / sizeof (kstat_names[0]))
481 (void) sprintf(knt->name, "unknown%d", i);
482 else
483 #endif
484 (void) strncpy(knt->name, kstat_names[i],
485 sizeof (knt->name));
486 knt->data_type = KSTAT_DATA_UINT32;
487 }
488 /*
489 * sprintf is known to be safe here because KSTAT_STRLEN is
490 * 31, the maximum module name length is 8, and the maximum
491 * string length from %d is 11. This was once snprintf, but
492 * that's not backward-compatible with Solaris 2.6.
493 */
494 (void) sprintf(unitname, "%s" "%d", AHDLC_MOD_NAME, state->sa_unit);
495 ksp = kstat_create(AHDLC_MOD_NAME, state->sa_unit, unitname, "net",
496 KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_VIRTUAL);
497 if (ksp != NULL) {
498 ksp->ks_data = (void *)&state->sa_kstats;
499 kstat_install(ksp);
500 }
501 state->sa_ksp = ksp;
502 #ifdef REPORT_CRC_TYPE
503 KSET(pks_outcrctype, 16);
504 KSET(pks_incrctype, 16);
505 #endif
506 }
507
508 /*
509 * spppasyn_inner_ioctl
510 *
511 * MT-Perimeters:
512 * exclusive inner
513 *
514 * Handle state-affecting ioctls.
515 */
516 static void
spppasyn_inner_ioctl(queue_t * q,mblk_t * mp)517 spppasyn_inner_ioctl(queue_t *q, mblk_t *mp)
518 {
519 sppp_ahdlc_t *state;
520 struct iocblk *iop;
521 int error;
522 int flagval;
523 int len;
524 uint32_t mux_flags;
525 uint32_t mask;
526 int flagmask;
527
528 ASSERT(q != NULL && mp != NULL);
529 state = (sppp_ahdlc_t *)q->q_ptr;
530 iop = (struct iocblk *)mp->b_rptr;
531 ASSERT(state != NULL && iop != NULL);
532
533 error = EINVAL;
534 len = 0;
535
536 switch (iop->ioc_cmd) {
537 case PPPIO_XFCS:
538 /* Check for valid option length */
539 if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
540 break;
541
542 /* Grab flag value */
543 flagval = *(uint32_t *)mp->b_cont->b_rptr;
544 if (flagval < PPPFCS_16 || flagval > PPPFCS_NONE)
545 break;
546 state->sa_flags &= ~SAF_XMITCRC32 & ~SAF_XMITCRCNONE;
547 if (flagval == PPPFCS_32) {
548 #ifdef REPORT_CRC_TYPE
549 KSET(pks_outcrctype, 32);
550 #endif
551 state->sa_flags |= SAF_XMITCRC32;
552 } else if (flagval == PPPFCS_NONE) {
553 #ifdef REPORT_CRC_TYPE
554 KSET(pks_outcrctype, 0);
555 #endif
556 state->sa_flags |= SAF_XMITCRCNONE;
557 }
558 #ifdef REPORT_CRC_TYPE
559 else {
560 KSET(pks_outcrctype, 16);
561 }
562 #endif
563
564 /* Return success */
565 error = 0;
566 break;
567
568 case PPPIO_RFCS:
569 /* Check for valid option length */
570 if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
571 break;
572
573 /* Grab flag value */
574 flagval = *(uint32_t *)mp->b_cont->b_rptr;
575 if (flagval < PPPFCS_16 || flagval > PPPFCS_NONE)
576 break;
577 state->sa_flags &= ~SAF_RECVCRC32 & ~SAF_RECVCRCNONE;
578 if (flagval == PPPFCS_32) {
579 #ifdef REPORT_CRC_TYPE
580 KSET(pks_incrctype, 32);
581 #endif
582 state->sa_flags |= SAF_RECVCRC32;
583 } else if (flagval == PPPFCS_NONE) {
584 #ifdef REPORT_CRC_TYPE
585 KSET(pks_incrctype, 0);
586 #endif
587 state->sa_flags |= SAF_RECVCRCNONE;
588 }
589 #ifdef REPORT_CRC_TYPE
590 else {
591 KSET(pks_incrctype, 16);
592 }
593 #endif
594
595 /* Return success */
596 error = 0;
597 break;
598
599 case PPPIO_XACCM:
600 /* Check for valid asyncmap length */
601 if (iop->ioc_count < sizeof (uint32_t) ||
602 iop->ioc_count > sizeof (ext_accm) ||
603 mp->b_cont == NULL)
604 break;
605
606 /* Copy user's asyncmap into our state structure. */
607 bcopy((caddr_t)mp->b_cont->b_rptr,
608 (caddr_t)state->sa_xaccm, iop->ioc_count);
609
610 state->sa_xaccm[2] &= ~0x40000000; /* don't escape 0x5e */
611 state->sa_xaccm[3] |= 0x60000000; /* escape 0x7d, 0x7e */
612
613 error = 0;
614 break;
615
616 case PPPIO_RACCM:
617 /* Check for valid asyncmap length (only ctrl chars) */
618 if (iop->ioc_count != sizeof (uint32_t) ||
619 mp->b_cont == NULL)
620 break;
621
622 state->sa_raccm = *(uint32_t *)mp->b_cont->b_rptr;
623
624 error = 0;
625 break;
626
627 case PPPIO_LASTMOD:
628 /* We already know this. */
629 state->sa_flags |= SAF_LASTMOD;
630 error = 0;
631 break;
632
633 case PPPIO_MUX:
634 /* set the compression flags */
635 if (iop->ioc_count != 2 * sizeof (uint32_t) ||
636 mp->b_cont == NULL)
637 break;
638
639 /* set the mux flags */
640 mux_flags = ((uint32_t *)mp->b_cont->b_rptr)[0];
641 mask = ((uint32_t *)mp->b_cont->b_rptr)[1];
642 if (mux_flags != 0)
643 state->sa_flags = (state->sa_flags & ~mask) | (mask);
644
645 /* set the multiplexing timer value */
646 if (mask & R_MUXMASK)
647 state->sa_timeout_usec = mux_flags;
648
649 error = 0;
650 break;
651
652 case PPPIO_CFLAGS:
653 if (iop->ioc_count != 2 * sizeof (uint32_t) ||
654 mp->b_cont == NULL)
655 break;
656
657 flagval = (((uint32_t *)mp->b_cont->b_rptr)[0] << 20) &
658 (SAF_RDECOMP_PROT | SAF_RDECOMP_AC | SAF_XCOMP_PROT |
659 SAF_XCOMP_AC);
660 flagmask = (((uint32_t *)mp->b_cont->b_rptr)[1] << 20) &
661 (SAF_RDECOMP_PROT | SAF_RDECOMP_AC | SAF_XCOMP_PROT |
662 SAF_XCOMP_AC);
663 state->sa_flags = flagval | (state->sa_flags & ~flagmask);
664 *(uint32_t *)mp->b_cont->b_rptr = state->sa_flags >> 20;
665 len = sizeof (uint32_t);
666 error = 0;
667 break;
668
669 case PPPIO_DEBUG:
670 if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL)
671 break;
672
673 flagval = *(uint32_t *)mp->b_cont->b_rptr;
674 if (flagval != PPPDBG_LOG + PPPDBG_AHDLC) {
675 putnext(q, mp);
676 return;
677 }
678 cmn_err(CE_CONT, AHDLC_MOD_NAME "%d: debug log enabled\n",
679 state->sa_unit);
680 state->sa_flags |= SAF_XMITDUMP | SAF_RECVDUMP;
681 error = 0;
682 break;
683 }
684
685 if (error == 0) {
686 /* Success; tell the user */
687 if (mp->b_cont == NULL)
688 len = 0;
689 else
690 mp->b_cont->b_wptr = mp->b_cont->b_rptr + len;
691 miocack(q, mp, len, 0);
692 } else {
693 /* Failure; send error back upstream. */
694 KINCR(pks_ioctlserr);
695 miocnak(q, mp, 0, error);
696 }
697 }
698
699 /*
700 * spppasyn_inner_mctl
701 *
702 * MT-Perimeters:
703 * exclusive inner
704 *
705 * Handle state-affecting M_CTL messages.
706 */
707 static void
spppasyn_inner_mctl(queue_t * q,mblk_t * mp)708 spppasyn_inner_mctl(queue_t *q, mblk_t *mp)
709 {
710 sppp_ahdlc_t *state;
711 int msglen;
712 int error;
713
714 ASSERT(q != NULL && mp != NULL);
715 state = (sppp_ahdlc_t *)q->q_ptr;
716 ASSERT(state != NULL);
717
718 msglen = MBLKL(mp);
719 error = 0;
720 switch (*mp->b_rptr) {
721 case PPPCTL_MTU:
722 /* Just ignore the MTU */
723 break;
724
725 case PPPCTL_MRU:
726 if (msglen != 4)
727 error = EINVAL;
728 else
729 state->sa_mru =
730 ((ushort_t *)mp->b_rptr)[1];
731 break;
732
733 case PPPCTL_UNIT:
734 if (state->sa_ksp != NULL) {
735 error = EINVAL;
736 break;
737 }
738 if (msglen == 2)
739 state->sa_unit = mp->b_rptr[1];
740 else if (msglen == 8)
741 state->sa_unit =
742 ((uint32_t *)mp->b_rptr)[1];
743 else
744 error = EINVAL;
745 if (error == 0 && state->sa_ksp == NULL)
746 create_kstats(state);
747 break;
748 }
749
750 if (error > 0) {
751 KINCR(pks_ctlserr);
752 }
753 if (state->sa_flags & SAF_LASTMOD) {
754 freemsg(mp);
755 } else {
756 KINCR(pks_ctlsfwd);
757 putnext(q, mp);
758 }
759 }
760
761 /*
762 * spppasyn_wput()
763 *
764 * MT-Perimeters:
765 * exclusive inner.
766 *
767 * Write side put routine. This called by the modules above us (likely to
768 * be the compression module) to transmit data or pass along ioctls.
769 */
770 static int
spppasyn_wput(queue_t * q,mblk_t * mp)771 spppasyn_wput(queue_t *q, mblk_t *mp)
772 {
773 sppp_ahdlc_t *state;
774 struct iocblk *iop;
775 int error;
776 mblk_t *np;
777 struct ppp_stats64 *psp;
778 int msglen;
779
780 ASSERT(q != NULL && mp != NULL);
781 state = (sppp_ahdlc_t *)q->q_ptr;
782 ASSERT(state != NULL);
783
784 switch (MTYPE(mp)) {
785
786 case M_DATA:
787 /*
788 * A data packet - do character-stuffing and FCS, and
789 * send it onwards. The blocks are freed as we go.
790 */
791 if (IS_XMUX_ENABLED(state))
792 mp = spppasyn_muxencode(q, mp);
793 else
794 mp = ahdlc_encode(q, mp);
795 if (mp != NULL)
796 putnext(q, mp);
797 break;
798
799 case M_IOCTL:
800
801 KINCR(pks_ioctls);
802 iop = (struct iocblk *)mp->b_rptr;
803
804 msglen = 0;
805
806 switch (iop->ioc_cmd) {
807 case PPPIO_XFCS:
808 case PPPIO_RFCS:
809 case PPPIO_XACCM:
810 case PPPIO_RACCM:
811 case PPPIO_LASTMOD:
812 case PPPIO_DEBUG:
813 case PPPIO_MUX:
814 case PPPIO_CFLAGS:
815 spppasyn_inner_ioctl(q, mp);
816 return (0);
817
818 case PPPIO_GCLEAN:
819 np = allocb(sizeof (uint32_t), BPRI_HI);
820 if (np == NULL) {
821 error = ENOSR;
822 break;
823 }
824 if (mp->b_cont != NULL) {
825 freemsg(mp->b_cont);
826 }
827 mp->b_cont = np;
828
829 *(uint32_t *)np->b_wptr = state->sa_flags & RCV_FLAGS;
830
831 msglen = sizeof (uint32_t);
832 np->b_wptr += msglen;
833 error = 0;
834 break;
835
836 case PPPIO_GETSTAT:
837 error = EINVAL;
838 break;
839
840 case PPPIO_GETSTAT64:
841 np = allocb(sizeof (*psp), BPRI_HI);
842 if (np == NULL) {
843 error = ENOSR;
844 break;
845 }
846 if (mp->b_cont != NULL) {
847 freemsg(mp->b_cont);
848 }
849 mp->b_cont = np;
850
851 psp = (struct ppp_stats64 *)np->b_wptr;
852 bzero((caddr_t)psp, sizeof (*psp));
853 psp->p = state->sa_stats;
854
855 msglen = sizeof (*psp);
856 np->b_wptr += msglen;
857 error = 0;
858 break;
859
860 case PPPIO_GTYPE:
861 np = allocb(sizeof (uint32_t), BPRI_HI);
862 if (np == NULL) {
863 error = ENOSR;
864 break;
865 }
866 if (mp->b_cont != NULL) {
867 freemsg(mp->b_cont);
868 }
869 mp->b_cont = np;
870
871 *(uint32_t *)np->b_wptr = PPPTYP_AHDLC;
872
873 msglen = sizeof (uint32_t);
874 np->b_wptr += msglen;
875 error = 0;
876 break;
877
878 default:
879 /* Unknown ioctl -- forward along */
880 KINCR(pks_ioctlsfwd);
881 putnext(q, mp);
882 return (0);
883 }
884
885 if (error == 0) {
886 /* Success; tell the user */
887 miocack(q, mp, msglen, 0);
888 } else {
889 /* Failure; send error back upstream. */
890 KINCR(pks_ioctlserr);
891 miocnak(q, mp, 0, error);
892 }
893
894 break;
895
896 case M_CTL:
897 KINCR(pks_ctls);
898 spppasyn_inner_mctl(q, mp);
899 break;
900
901 default:
902 if (state->sa_flags & (SAF_XMITDUMP|SAF_RECVDUMP))
903 cmn_err(CE_CONT,
904 "spppasyn_wpur: unknown buffer type %d",
905 MTYPE(mp));
906 KINCR(pks_unknownwrs);
907 putnext(q, mp);
908 break;
909 }
910
911 return (0);
912 }
913
914 /*
915 * spppasyn_rput()
916 *
917 * MT-Perimeters:
918 * exclusive inner.
919 *
920 * Read side put routine. This is called by the async serial driver
921 * below us to handle received data and returned signals (like
922 * hang-up).
923 */
924 static int
spppasyn_rput(queue_t * q,mblk_t * mp)925 spppasyn_rput(queue_t *q, mblk_t *mp)
926 {
927 sppp_ahdlc_t *state;
928 mblk_t *mpnext;
929
930 ASSERT(q != NULL && mp != NULL);
931 state = (sppp_ahdlc_t *)q->q_ptr;
932 ASSERT(state != NULL);
933
934 switch (MTYPE(mp)) {
935
936 case M_DATA:
937 /* Note -- decoder frees the buffers */
938 mp = ahdlc_decode(q, mp);
939 while (mp != NULL) {
940 mpnext = mp->b_next;
941 mp->b_next = NULL;
942 putnext(q, mp);
943 mp = mpnext;
944 }
945 break;
946
947 case M_HANGUP:
948 KINCR(pks_hangups);
949 state->sa_flags |= SAF_IFLUSH;
950 putnext(q, mp);
951 break;
952
953 default:
954 if (state->sa_flags & (SAF_XMITDUMP|SAF_RECVDUMP)) {
955 if (MTYPE(mp) == M_IOCTL)
956 cmn_err(CE_CONT,
957 "spppasyn_rput: unexpected ioctl %X",
958 ((struct iocblk *)mp->b_rptr)->ioc_cmd);
959 else
960 cmn_err(CE_CONT,
961 "spppasyn_rput: unknown buffer type %d",
962 MTYPE(mp));
963 }
964 KINCR(pks_unknownrds);
965 putnext(q, mp);
966 break;
967 }
968
969 return (0);
970 }
971
972 /*
973 * ahdlc_encode
974 *
975 * Perform asynchronous HDLC framing on a given buffer and transmit
976 * the result. The state structure must be valid. The input buffers
977 * are freed as we go.
978 *
979 * This function is called by wput and just encodes the data. Wput
980 * then calls putnext directly. There's no service routine for this
981 * module, so flow control is asserted by the module below us up to
982 * our caller by the STREAMS framework. This is by design -- this
983 * module does not queue anything so that other modules can make QoS
984 * decisions.
985 */
986 static mblk_t *
ahdlc_encode(queue_t * q,mblk_t * mp)987 ahdlc_encode(queue_t *q, mblk_t *mp)
988 {
989 sppp_ahdlc_t *state;
990 uint32_t loc_xaccm[8];
991 ushort_t fcs16;
992 uint32_t fcs32;
993 size_t msglen;
994 size_t outmp_len;
995 mblk_t *outmp;
996 mblk_t *curout;
997 mblk_t *tmp;
998 uchar_t *ep;
999 uchar_t *dp;
1000 uchar_t *tp;
1001 uchar_t *tpmax;
1002 #if defined(lint) || defined(_lint)
1003 uchar_t chr; /* lint likes this */
1004 #else
1005 int chr; /* not uchar_t; more efficient this way */
1006 /* with WorkShop compiler */
1007 #endif
1008 int is_lcp, is_ctrl;
1009 int code;
1010 hrtime_t hrtime;
1011 uint32_t flags; /* sampled copy of flags */
1012
1013 state = (sppp_ahdlc_t *)q->q_ptr;
1014
1015 /* Don't transmit anything obviously silly. */
1016 msglen = msgsize(mp);
1017 if (msglen < 4) {
1018 KINCR(pks_outrunts);
1019 freemsg(mp);
1020 (void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR);
1021 return (NULL);
1022 }
1023
1024 /*
1025 * Allocate an output buffer just large enough for most cases.
1026 * Based on original work in the ppp-2.2 AIX PPP driver, we
1027 * estimate the output size as 1.25 * input message length
1028 * plus 16. If this turns out to be too small, then we'll
1029 * allocate exactly one additional buffer with two times the
1030 * remaining input length (the maximum that could possibly be
1031 * required).
1032 */
1033 outmp_len = msglen + (msglen >> 2) + 16;
1034 outmp = allocb(outmp_len, BPRI_MED);
1035 if (outmp == NULL)
1036 goto outallocfail;
1037
1038 tp = outmp->b_wptr;
1039
1040 /*
1041 * Check if our last transmit happened within FLAG_TIME, using
1042 * the system's hrtime.
1043 */
1044 hrtime = gethrtime();
1045 if (ABS(hrtime - state->sa_hrtime) > FLAG_TIME) {
1046 *tp++ = PPP_FLAG;
1047 }
1048 state->sa_hrtime = hrtime;
1049 bcopy((caddr_t)state->sa_xaccm, (caddr_t)loc_xaccm, sizeof (loc_xaccm));
1050 flags = state->sa_flags;
1051
1052 /*
1053 * LCP messages must be sent using the default escaping
1054 * (ACCM). We bend this rule a little to allow LCP
1055 * Echo-Request through with the negotiated escaping so that
1056 * we can detect bad negotiated ACCM values. If the ACCM is
1057 * bad, echos will fail and take down the link.
1058 */
1059 is_lcp = is_ctrl = 0;
1060 code = MSG_BYTE(mp, 0);
1061 if (code == PPP_ALLSTATIONS) {
1062 if (MSG_BYTE(mp, 1) == PPP_UI) {
1063 code = MSG_BYTE(mp, 2);
1064 if (code == (PPP_LCP >> 8) &&
1065 MSG_BYTE(mp, 3) == (PPP_LCP & 0xFF)) {
1066 if (LCP_USE_DFLT(mp))
1067 is_lcp = 2;
1068 else
1069 is_lcp = 1; /* Echo-Request */
1070 } else if (!(code & 1) && code > 0x3F)
1071 is_ctrl = 1;
1072 }
1073 } else if (!(code & 1) && code > 0x3F)
1074 is_ctrl = 1;
1075
1076 /*
1077 * If it's LCP and not just an LCP Echo-Request, then we need
1078 * to drop back to default escaping rules temporarily.
1079 */
1080 if (is_lcp > 1) {
1081 /*
1082 * force escape on 0x00 through 0x1f
1083 * and, for RFC 1662 (and ISO 3309:1991), 0x80-0x9f.
1084 */
1085 loc_xaccm[0] = 0xffffffff;
1086 loc_xaccm[4] = 0xffffffff;
1087 }
1088
1089 fcs16 = PPPINITFCS16; /* Initial FCS is 0xffff */
1090 fcs32 = PPPINITFCS32;
1091
1092 /*
1093 * Process this block and the rest (if any) attached to this
1094 * one. Note that we quite intentionally ignore the type of
1095 * the buffer. The caller has checked that the first buffer
1096 * is M_DATA; all others must be so, and any that are not are
1097 * harmless driver errors.
1098 */
1099 curout = outmp;
1100 tpmax = outmp->b_datap->db_lim;
1101 do {
1102 dp = mp->b_rptr;
1103 while (dp < (ep = mp->b_wptr)) {
1104 /*
1105 * Calculate maximum safe run length for inner loop,
1106 * regardless of escaping.
1107 */
1108 outmp_len = (tpmax - tp) / 2;
1109 if (dp + outmp_len < ep)
1110 ep = dp + outmp_len;
1111
1112 /*
1113 * Select out on CRC type here to make the
1114 * inner byte loop more efficient. (We could
1115 * do both CRCs at all times if we wanted, but
1116 * that ends up taking an extra 8 cycles per
1117 * byte -- 47% overhead!)
1118 */
1119 if (flags & SAF_XMITCRC32) {
1120 while (dp < ep) {
1121 chr = *dp++;
1122 fcs32 = PPPFCS32(fcs32, chr);
1123 if (IN_TX_MAP(chr, loc_xaccm)) {
1124 *tp++ = PPP_ESCAPE;
1125 chr ^= PPP_TRANS;
1126 }
1127 *tp++ = chr;
1128 }
1129 } else {
1130 while (dp < ep) {
1131 chr = *dp++;
1132 fcs16 = PPPFCS16(fcs16, chr);
1133 if (IN_TX_MAP(chr, loc_xaccm)) {
1134 *tp++ = PPP_ESCAPE;
1135 chr ^= PPP_TRANS;
1136 }
1137 *tp++ = chr;
1138 }
1139 }
1140
1141 /*
1142 * If we limited our run length and we're now low
1143 * on output space, then allocate a new output buffer.
1144 * This should rarely happen, unless the output data
1145 * has a lot of escapes.
1146 */
1147 if (ep != mp->b_wptr && tpmax - tp < 5) {
1148 KINCR(pks_extrabufs);
1149 /* Get remaining message length */
1150 outmp_len = (mp->b_wptr - dp) +
1151 msgsize(mp->b_cont);
1152 /* Calculate maximum required space */
1153 outmp_len = (outmp_len + PPP_FCS32LEN) * 2 + 1;
1154 curout = allocb(outmp_len, BPRI_MED);
1155 if ((outmp->b_cont = curout) == NULL)
1156 goto outallocfail;
1157 outmp->b_wptr = tp;
1158 tp = curout->b_wptr;
1159 tpmax = curout->b_datap->db_lim;
1160 }
1161 }
1162 tmp = mp->b_cont;
1163 freeb(mp);
1164 mp = tmp;
1165 } while (mp != NULL);
1166
1167 /*
1168 * Make sure we have enough remaining room to add the CRC (if
1169 * any) and a trailing flag byte.
1170 */
1171 outmp_len = PPP_FCS32LEN * 2 + 1;
1172 if (tpmax - tp < outmp_len) {
1173 KINCR(pks_extrabufs);
1174 curout = allocb(outmp_len, BPRI_MED);
1175 if ((outmp->b_cont = curout) == NULL)
1176 goto outallocfail;
1177 outmp->b_wptr = tp;
1178 tp = curout->b_wptr;
1179 tpmax = curout->b_datap->db_lim;
1180 }
1181
1182 /*
1183 * Network layer data is the only thing that can be sent with
1184 * no CRC at all.
1185 */
1186 if ((flags & SAF_XMITCRCNONE) && !is_lcp && !is_ctrl)
1187 goto nocrc;
1188
1189 if (!(flags & SAF_XMITCRC32))
1190 fcs32 = fcs16;
1191
1192 /*
1193 * Append the HDLC FCS, making sure that escaping is done on any
1194 * necessary bytes. Note that the FCS bytes are in little-endian.
1195 */
1196 fcs32 = ~fcs32;
1197 chr = fcs32 & 0xff;
1198 if (IN_TX_MAP(chr, loc_xaccm)) {
1199 *tp++ = PPP_ESCAPE;
1200 chr ^= PPP_TRANS;
1201 }
1202 *tp++ = chr;
1203
1204 chr = (fcs32 >> 8) & 0xff;
1205 if (IN_TX_MAP(chr, loc_xaccm)) {
1206 *tp++ = PPP_ESCAPE;
1207 chr ^= PPP_TRANS;
1208 }
1209 *tp++ = chr;
1210
1211 if (flags & SAF_XMITCRC32) {
1212 chr = (fcs32 >> 16) & 0xff;
1213 if (IN_TX_MAP(chr, loc_xaccm)) {
1214 *tp++ = PPP_ESCAPE;
1215 chr ^= PPP_TRANS;
1216 }
1217 *tp++ = chr;
1218
1219 chr = (fcs32 >> 24) & 0xff;
1220 if (IN_TX_MAP(chr, loc_xaccm)) {
1221 *tp++ = PPP_ESCAPE;
1222 chr ^= PPP_TRANS;
1223 }
1224 *tp++ = chr;
1225 }
1226
1227 nocrc:
1228 /*
1229 * And finally append the HDLC flag, and send it away
1230 */
1231 *tp++ = PPP_FLAG;
1232 ASSERT(tp < tpmax);
1233 curout->b_wptr = tp;
1234
1235 state->sa_stats.ppp_obytes += msgsize(outmp);
1236 state->sa_stats.ppp_opackets++;
1237
1238 if (state->sa_flags & SAF_XMITDUMP)
1239 ppp_dump_frame(state, outmp, "sent");
1240
1241 KINCR(pks_dataout);
1242 return (outmp);
1243
1244 outallocfail:
1245 KINCR(pks_outallocfails);
1246 state->sa_stats.ppp_oerrors++;
1247 freemsg(outmp);
1248 freemsg(mp);
1249 (void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR);
1250 return (NULL);
1251 }
1252
1253 /*
1254 * Handle end-of-frame excitement. This is here mostly because the Solaris
1255 * C style rules require tab for indent and prohibit excessive indenting.
1256 */
1257 static mblk_t *
receive_frame(queue_t * q,mblk_t * outmp,ushort_t fcs16,uint32_t fcs32)1258 receive_frame(queue_t *q, mblk_t *outmp, ushort_t fcs16, uint32_t fcs32)
1259 {
1260 sppp_ahdlc_t *state = (sppp_ahdlc_t *)q->q_ptr;
1261 uchar_t *cp, *ep;
1262 int is_lcp, is_ctrl, crclen;
1263 ushort_t proto;
1264 int i;
1265
1266 cp = outmp->b_rptr;
1267 if (cp[0] == PPP_ALLSTATIONS && cp[1] == PPP_UI)
1268 cp += 2;
1269 proto = *cp++;
1270 if ((proto & 1) == 0)
1271 proto = (proto << 8) + *cp++;
1272 is_lcp = (proto == PPP_LCP);
1273 is_ctrl = (proto >= 0x4000);
1274
1275 /*
1276 * To allow for renegotiation, LCP accepts good CRCs of either
1277 * type at any time. Other control (non-network) packets must
1278 * have either CRC-16 or CRC-32, as negotiated. Network layer
1279 * packets may additionally omit the CRC entirely, if that was
1280 * negotiated.
1281 */
1282 if ((is_lcp && (fcs16 == PPPGOODFCS16 || fcs32 == PPPGOODFCS32)) ||
1283 ((fcs16 == PPPGOODFCS16 && !(state->sa_flags & SAF_RECVCRC32)) ||
1284 (fcs32 == PPPGOODFCS32 &&
1285 (state->sa_flags & SAF_RECVCRC32))) ||
1286 (!is_ctrl && !is_lcp && (state->sa_flags & SAF_RECVCRCNONE))) {
1287
1288 state->sa_stats.ppp_ipackets++;
1289 if (is_lcp) {
1290 crclen = (fcs16 == PPPGOODFCS16) ?
1291 PPP_FCSLEN : PPP_FCS32LEN;
1292 } else {
1293 crclen = (state->sa_flags & SAF_RECVCRC32) ?
1294 PPP_FCS32LEN : PPP_FCSLEN;
1295 if (!is_ctrl && (state->sa_flags & SAF_RECVCRCNONE))
1296 crclen = 0;
1297 }
1298 if (crclen != 0) {
1299 i = adjmsg(outmp, -crclen);
1300 ASSERT(i != 0);
1301 #if defined(lint) || defined(_lint)
1302 /* lint is happier this way in a non-DEBUG build */
1303 i = i;
1304 #endif
1305 }
1306
1307 if (proto == PPP_MUX) {
1308 /* spppasyn_inpkt checks for PPP_MUX packets */
1309 KINCR(pks_recvmux);
1310 /* Remove headers */
1311 outmp->b_rptr = cp;
1312 return (spppasyn_inpkt(q, outmp));
1313 }
1314
1315 /*
1316 * Sniff the received data stream. If we see an LCP
1317 * Configure-Ack, then pick out the ACCM setting, if
1318 * any, and configure now. This allows us to stay in
1319 * sync in case the peer is already out of Establish
1320 * phase.
1321 */
1322 if (is_lcp && *cp == 2) {
1323 ep = outmp->b_wptr;
1324 i = (cp[2] << 8) | cp[3];
1325 if (i > ep - cp)
1326 ep = cp; /* Discard junk */
1327 else if (i < ep - cp)
1328 ep = cp + i;
1329 cp += 4;
1330 while (cp + 2 < ep) {
1331 if ((i = cp[1]) < 2)
1332 i = 2;
1333 if (cp + i > ep)
1334 i = ep - cp;
1335 if (cp[0] == 2 && i >= 6) {
1336 state->sa_raccm = (cp[2] << 24) |
1337 (cp[3] << 16) | (cp[4] << 8) |
1338 cp[5];
1339 break;
1340 }
1341 cp += i;
1342 }
1343 }
1344 return (outmp);
1345 } else {
1346 KINCR(pks_incrcerrs);
1347 cmn_err(CE_CONT, PPP_DRV_NAME "%d: bad fcs (len=%ld)\n",
1348 state->sa_unit, msgsize(outmp));
1349
1350 if (state->sa_flags & SAF_RECVDUMP)
1351 ppp_dump_frame(state, outmp, "bad data");
1352
1353 freemsg(outmp);
1354
1355 state->sa_stats.ppp_ierrors++;
1356
1357 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1358 return (NULL);
1359 }
1360 }
1361
1362 /*
1363 * ahdlc_decode()
1364 *
1365 * Process received characters.
1366 *
1367 * This is handled as exclusive inner so that we don't get confused
1368 * about the state. Returns a list of packets linked by b_next.
1369 */
1370 static mblk_t *
ahdlc_decode(queue_t * q,mblk_t * mp)1371 ahdlc_decode(queue_t *q, mblk_t *mp)
1372 {
1373 sppp_ahdlc_t *state;
1374 mblk_t *retmp; /* list of packets to return */
1375 mblk_t *outmp; /* buffer for decoded data */
1376 mblk_t *mpnext; /* temporary ptr for unlinking */
1377 uchar_t *dp; /* pointer to input data */
1378 uchar_t *dpend; /* end of input data */
1379 uchar_t *tp; /* pointer to decoded output data */
1380 uchar_t *tpmax; /* output buffer limit */
1381 int flagtmp; /* temporary cache of flags */
1382 #if defined(lint) || defined(_lint)
1383 uchar_t chr; /* lint likes this */
1384 #else
1385 int chr; /* not uchar_t; more efficient this way */
1386 /* with WorkShop compiler */
1387 #endif
1388 ushort_t fcs16; /* running CRC-16 */
1389 uint32_t fcs32; /* running CRC-32 */
1390 #ifdef HANDLE_ZERO_LENGTH
1391 size_t nprocessed;
1392 #endif
1393
1394 state = (sppp_ahdlc_t *)q->q_ptr;
1395
1396 KINCR(pks_datain);
1397
1398 state->sa_stats.ppp_ibytes += msgsize(mp);
1399
1400 if (state->sa_flags & SAF_RECVDUMP)
1401 ppp_dump_frame(state, mp, "rcvd");
1402
1403 flagtmp = state->sa_flags;
1404 fcs16 = state->sa_infcs16;
1405 fcs32 = state->sa_infcs32;
1406 outmp = state->sa_rx_buf;
1407 if (outmp == NULL) {
1408 tp = tpmax = NULL;
1409 } else {
1410 tp = outmp->b_wptr;
1411 tpmax = outmp->b_datap->db_lim;
1412 }
1413 #ifdef HANDLE_ZERO_LENGTH
1414 nprocessed = 0;
1415 #endif
1416
1417 /*
1418 * Main input processing loop. Loop over received buffers and
1419 * each byte in each buffer. Note that we quite intentionally
1420 * ignore the type of the buffer. The caller has checked that
1421 * the first buffer is M_DATA; all others must be so, and any
1422 * that are not are harmless driver errors.
1423 */
1424 retmp = NULL;
1425 while (mp != NULL) {
1426
1427 /* Innermost loop -- examine bytes in buffer. */
1428 dpend = mp->b_wptr;
1429 dp = mp->b_rptr;
1430 #ifdef HANDLE_ZERO_LENGTH
1431 nprocessed += dpend - dp;
1432 #endif
1433 for (; dp < dpend; dp++) {
1434 chr = *dp;
1435
1436 /*
1437 * This should detect the lack of an 8-bit
1438 * communication channel, which is necessary
1439 * for PPP to work.
1440 */
1441 flagtmp |= charflags[chr];
1442
1443 /*
1444 * So we have a HDLC flag ...
1445 */
1446 if (chr == PPP_FLAG) {
1447
1448 /*
1449 * If there's no received buffer, then
1450 * just ignore this frame marker.
1451 */
1452 if ((flagtmp & SAF_IFLUSH) || outmp == NULL) {
1453 flagtmp &= ~SAF_IFLUSH & ~SAF_ESCAPED;
1454 continue;
1455 }
1456
1457 /*
1458 * Per RFC 1662 -- silently discard
1459 * runt frames (fewer than 4 octets
1460 * with 16 bit CRC) and frames that
1461 * end in 7D 7E (abort sequence).
1462 * These are not counted as errors.
1463 *
1464 * (We could just reset the pointers
1465 * and reuse the buffer, but this is a
1466 * rarely used error path and not
1467 * worth the optimization.)
1468 */
1469 if ((flagtmp & SAF_ESCAPED) ||
1470 tp - outmp->b_rptr < 2 + PPP_FCSLEN) {
1471 if (flagtmp & SAF_ESCAPED)
1472 KINCR(pks_inaborts);
1473 else
1474 KINCR(pks_inrunts);
1475 if (state->sa_flags & SAF_RECVDUMP) {
1476 outmp->b_wptr = tp;
1477 ppp_dump_frame(state, outmp,
1478 "runt");
1479 }
1480 freemsg(outmp);
1481 flagtmp &= ~SAF_ESCAPED;
1482 } else {
1483 /* Handle the received frame */
1484 outmp->b_wptr = tp;
1485 outmp = receive_frame(q, outmp, fcs16,
1486 fcs32);
1487 retmp = sppp_mappend(retmp, outmp);
1488 }
1489
1490 outmp = NULL;
1491 tp = tpmax = NULL;
1492
1493 continue;
1494 }
1495
1496 /* If we're waiting for a new frame, then drop data. */
1497 if (flagtmp & SAF_IFLUSH) {
1498 continue;
1499 }
1500
1501 /*
1502 * Start of new frame. Allocate a receive
1503 * buffer large enough to store a frame (after
1504 * un-escaping) of at least 1500 octets plus
1505 * the CRC. If MRU is negotiated to be more
1506 * than the default, then allocate that much.
1507 * In addition, we add an extra 32-bytes for a
1508 * fudge factor, in case the peer doesn't do
1509 * arithmetic very well.
1510 */
1511 if (outmp == NULL) {
1512 int maxlen;
1513
1514 if ((maxlen = state->sa_mru) < PPP_MRU)
1515 maxlen = PPP_MRU;
1516 maxlen += PPP_FCS32LEN + 32;
1517 outmp = allocb(maxlen, BPRI_MED);
1518
1519 /*
1520 * If allocation fails, try again on
1521 * the next frame. (Go into discard
1522 * mode.)
1523 */
1524 if (outmp == NULL) {
1525 KINCR(pks_inallocfails);
1526 flagtmp |= SAF_IFLUSH;
1527 continue;
1528 }
1529
1530 tp = outmp->b_wptr;
1531 tpmax = outmp->b_datap->db_lim;
1532
1533 /* Neither flag can possibly be set here. */
1534 flagtmp &= ~(SAF_IFLUSH | SAF_ESCAPED);
1535 fcs16 = PPPINITFCS16;
1536 fcs32 = PPPINITFCS32;
1537 }
1538
1539 /*
1540 * If the peer sends us a character that's in
1541 * our receive character map, then that's
1542 * junk. Discard it without changing state.
1543 * If they previously sent us an escape
1544 * character, then toggle this one and
1545 * continue. Otherwise, if they're now sending
1546 * escape, set the flag for next time.
1547 */
1548 if (IN_RX_MAP(chr, state->sa_raccm)) {
1549 KINCR(pks_inbadchars);
1550 KOR(pks_inbadcharmask, 1 << chr);
1551 continue;
1552 }
1553 if (flagtmp & SAF_ESCAPED) {
1554 chr ^= PPP_TRANS;
1555 flagtmp &= ~SAF_ESCAPED;
1556 } else if (chr == PPP_ESCAPE) {
1557 flagtmp |= SAF_ESCAPED;
1558 continue;
1559 }
1560
1561 /*
1562 * Unless the peer is confused about the
1563 * negotiated MRU, we should never get a frame
1564 * that is too long. If it happens, toss it
1565 * away and begin discarding data until we see
1566 * the end of the frame.
1567 */
1568 if (tp < tpmax) {
1569 fcs16 = PPPFCS16(fcs16, chr);
1570 fcs32 = PPPFCS32(fcs32, chr);
1571 *tp++ = chr;
1572 } else {
1573 KINCR(pks_intoolongs);
1574 cmn_err(CE_CONT, PPP_DRV_NAME
1575 "%d: frame too long (%d bytes)\n",
1576 state->sa_unit,
1577 (int)(tpmax - outmp->b_rptr));
1578
1579 freemsg(outmp);
1580 outmp = NULL;
1581 tp = tpmax = NULL;
1582 flagtmp |= SAF_IFLUSH;
1583 }
1584 }
1585
1586 /*
1587 * Free the buffer we just processed and move on to
1588 * the next one.
1589 */
1590 mpnext = mp->b_cont;
1591 freeb(mp);
1592 mp = mpnext;
1593 }
1594 state->sa_flags = flagtmp;
1595 if ((state->sa_rx_buf = outmp) != NULL)
1596 outmp->b_wptr = tp;
1597 state->sa_infcs16 = fcs16;
1598 state->sa_infcs32 = fcs32;
1599
1600 #ifdef HANDLE_ZERO_LENGTH
1601 if (nprocessed <= 0) {
1602 outmp = allocb(0, BPRI_MED);
1603 if (outmp != NULL) {
1604 outmp->b_datap->db_type = M_HANGUP;
1605 retmp = sppp_mappend(retmp, outmp);
1606 }
1607 }
1608 #endif
1609 return (retmp);
1610 }
1611
1612 /*
1613 * Nifty packet dumper; copied from AIX 4.1 port. This routine dumps
1614 * the raw received and transmitted data through syslog. This allows
1615 * debug of communications problems without resorting to a line
1616 * analyzer.
1617 *
1618 * The expression "3*BYTES_PER_LINE" used frequently here represents
1619 * the size of each hex value printed -- two hex digits and a space.
1620 */
1621 #define BYTES_PER_LINE 8
1622 static void
ppp_dump_frame(sppp_ahdlc_t * state,mblk_t * mptr,const char * msg)1623 ppp_dump_frame(sppp_ahdlc_t *state, mblk_t *mptr, const char *msg)
1624 {
1625 /*
1626 * Buffer is big enough for hex digits, two spaces, ASCII output,
1627 * and one NUL byte.
1628 */
1629 char buf[3 * BYTES_PER_LINE + 2 + BYTES_PER_LINE + 1];
1630 uchar_t *rptr, *eptr;
1631 int i, chr;
1632 char *bp;
1633 static const char digits[] = "0123456789abcdef";
1634
1635 cmn_err(CE_CONT, "!ppp_async%d: %s %ld bytes\n", state->sa_unit,
1636 msg, msgsize(mptr));
1637 i = 0;
1638 bp = buf;
1639 /* Add filler spaces between hex output and ASCII */
1640 buf[3 * BYTES_PER_LINE] = ' ';
1641 buf[3 * BYTES_PER_LINE + 1] = ' ';
1642 /* Add NUL byte at end */
1643 buf[sizeof (buf) - 1] = '\0';
1644 while (mptr != NULL) {
1645 rptr = mptr->b_rptr; /* get pointer to beginning */
1646 eptr = mptr->b_wptr;
1647 while (rptr < eptr) {
1648 chr = *rptr++;
1649 /* convert byte to ascii hex */
1650 *bp++ = digits[chr >> 4];
1651 *bp++ = digits[chr & 0xf];
1652 *bp++ = ' ';
1653 /* Insert ASCII past hex output and filler */
1654 buf[3 * BYTES_PER_LINE + 2 + i] =
1655 (chr >= 0x20 && chr <= 0x7E) ? (char)chr : '.';
1656 i++;
1657 if (i >= BYTES_PER_LINE) {
1658 cmn_err(CE_CONT, "!ppp%d: %s\n", state->sa_unit,
1659 buf);
1660 bp = buf;
1661 i = 0;
1662 }
1663 }
1664 mptr = mptr->b_cont;
1665 }
1666 if (bp > buf) {
1667 /* fill over unused hex display positions */
1668 while (bp < buf + 3 * BYTES_PER_LINE)
1669 *bp++ = ' ';
1670 /* terminate ASCII string at right position */
1671 buf[3 * BYTES_PER_LINE + 2 + i] = '\0';
1672 cmn_err(CE_CONT, "!ppp%d: %s\n", state->sa_unit, buf);
1673 }
1674 }
1675
1676 static mblk_t *
spppasyn_muxencode(queue_t * q,mblk_t * mp)1677 spppasyn_muxencode(queue_t *q, mblk_t *mp)
1678 {
1679 sppp_ahdlc_t *state = (sppp_ahdlc_t *)q->q_ptr;
1680 uint32_t len;
1681 uint32_t nlen;
1682 ushort_t protolen;
1683 uint32_t hdrlen;
1684 ushort_t proto;
1685 mblk_t *new_frame;
1686 mblk_t *tmp;
1687 mblk_t *send_frame;
1688 ushort_t i;
1689
1690 len = msgdsize(mp);
1691 i = 0;
1692 protolen = 1;
1693 proto = MSG_BYTE(mp, i);
1694
1695 if (proto == PPP_ALLSTATIONS) {
1696 len -= 2;
1697 i += 2;
1698 proto = MSG_BYTE(mp, i);
1699 }
1700
1701 ++i;
1702 if ((proto & 1) == 0) {
1703 proto = (proto << 8) + MSG_BYTE(mp, i);
1704 protolen++;
1705 }
1706
1707 hdrlen = i - 1;
1708
1709 send_frame = NULL;
1710 if (len > PPP_MAX_MUX_LEN || (proto & 0x8000)) {
1711
1712 /* send the queued frames */
1713 if (state->sa_mqhead != NULL) {
1714 /* increment counter if it is MUX pkt */
1715 if (state->sa_mqtail != NULL)
1716 KINCR(pks_sentmux);
1717 send_frame = ahdlc_encode(q, state->sa_mqhead);
1718 }
1719
1720 /* send the current frame */
1721 mp = ahdlc_encode(q, mp);
1722 send_frame = sppp_mcat(send_frame, mp);
1723
1724 /* reset the state values over here */
1725 RESET_MUX_VALUES(state);
1726 return (send_frame);
1727 }
1728
1729 /* len + 1 , since we add the mux overhead */
1730 nlen = len + 1;
1731 /* subtract the protocol length if protocol matches */
1732 if (state->sa_proto == proto)
1733 nlen -= protolen;
1734
1735 send_frame = NULL;
1736 if ((state->sa_mqlen + nlen) >= state->sa_mru) {
1737
1738 /* send the existing queued frames */
1739 if (state->sa_mqhead != NULL) {
1740 /* increment counter if it is MUX pkt */
1741 if (state->sa_mqtail != NULL)
1742 KINCR(pks_sentmux);
1743 send_frame = ahdlc_encode(q, state->sa_mqhead);
1744 }
1745
1746 /* reset state values */
1747 RESET_MUX_VALUES(state);
1748 }
1749
1750 /* add the current frame to the queue */
1751 if (state->sa_mqhead != NULL) {
1752
1753 if (state->sa_mqtail == NULL) {
1754
1755 /*
1756 * this is the first mblk in the queue create
1757 * a new frame to hold the PPP MUX header
1758 */
1759 if ((new_frame = allocb(PPP_HDRLEN+1,
1760 BPRI_MED)) == NULL) {
1761 return (send_frame);
1762 }
1763
1764 if (!IS_COMP_AC(state)) {
1765 /* add the header */
1766 *new_frame->b_wptr++ = PPP_ALLSTATIONS;
1767 *new_frame->b_wptr++ = PPP_UI;
1768 }
1769
1770 /* do protocol compression */
1771 if (IS_COMP_PROT(state)) {
1772 *new_frame->b_wptr++ = PPP_MUX;
1773 } else {
1774 *new_frame->b_wptr++ = 0;
1775 *new_frame->b_wptr++ = PPP_MUX;
1776 }
1777
1778 *new_frame->b_wptr++ = PFF |
1779 (state->sa_mqlen - protolen - 1);
1780
1781 if (DB_REF(mp) > 1) {
1782 tmp = copymsg(state->sa_mqhead);
1783 freemsg(state->sa_mqhead);
1784 if ((state->sa_mqhead = tmp) == NULL) {
1785 return (send_frame);
1786 }
1787 }
1788
1789 if (state->sa_mqhead->b_rptr[0] == PPP_ALLSTATIONS)
1790 state->sa_mqhead->b_rptr += 2;
1791
1792 linkb(new_frame, state->sa_mqhead);
1793 state->sa_mqtail = state->sa_mqhead;
1794 /* point mqtail to the last mblk_t */
1795 while (state->sa_mqtail->b_cont != NULL)
1796 state->sa_mqtail = state->sa_mqtail->b_cont;
1797
1798 /* change state->sa_mqhead */
1799 state->sa_mqhead = new_frame;
1800
1801 }
1802
1803 if (state->sa_proto == proto) {
1804
1805 /* Check if the mblk_t is being referenced */
1806 if (DB_REF(mp) > 1) {
1807 tmp = copymsg(mp);
1808 freemsg(mp);
1809 if ((mp = tmp) == NULL) {
1810 return (send_frame);
1811 }
1812 }
1813
1814 /*
1815 * match,can remove the protocol field
1816 * and write data there
1817 */
1818 mp->b_rptr += hdrlen;
1819 /*
1820 * protolen - 1 ,because the the byte with
1821 * the PFF bit and the length field have
1822 * to added
1823 */
1824 mp->b_rptr += (protolen - 1);
1825 *mp->b_rptr = (len - protolen) & 0xff;
1826
1827 } else {
1828 /*
1829 * no match, there are three options
1830 * 1. write in mp
1831 * 2. write in mqtail
1832 * 3. alloc a new blk for just one byte
1833 */
1834 /* Check if the mblk_t is being referenced */
1835 if (DB_REF(mp) > 1) {
1836 tmp = copymsg(mp);
1837 freemsg(mp);
1838 if ((mp = tmp) == NULL) {
1839 return (send_frame);
1840 }
1841 }
1842
1843 if (hdrlen != 0) {
1844
1845 mp->b_rptr += (hdrlen-1);
1846 *mp->b_rptr = PFF | (len);
1847
1848 } else if (state->sa_mqtail->b_wptr <
1849 DB_LIM(state->sa_mqtail)) {
1850 *state->sa_mqtail->b_wptr++ = PFF |len;
1851 } else {
1852 /* allocate a new mblk & add the byte */
1853 /* write the data */
1854 if ((new_frame = allocb(1, BPRI_MED))
1855 == NULL) {
1856 freemsg(mp);
1857 return (send_frame);
1858 }
1859 *new_frame->b_wptr++ = PFF | (len);
1860 linkb(state->sa_mqtail, new_frame);
1861 }
1862
1863 /* update proto */
1864 state->sa_proto = proto;
1865 }
1866
1867 linkb(state->sa_mqtail, mp);
1868 state->sa_mqtail = mp;
1869 while (state->sa_mqtail->b_cont != NULL)
1870 state->sa_mqtail = state->sa_mqtail->b_cont;
1871 state->sa_mqlen += nlen;
1872
1873 } else {
1874 state->sa_mqhead = mp;
1875 state->sa_mqlen = len + protolen + 1;
1876 state->sa_proto = proto;
1877 }
1878
1879 if (state->sa_timeout_id == 0) {
1880 state->sa_timeout_id = qtimeout(q, spppasyn_timer, q,
1881 (drv_usectohz(state->sa_timeout_usec)));
1882 }
1883 return (send_frame);
1884 }
1885
1886 /*
1887 * Called from receive frame, this routine checks if it is a PPP_MUX
1888 * packet and demuxes it. The returned pointer is a chain of mblks
1889 * using b_next and representing the demultiplexed packets.
1890 */
1891 static mblk_t *
spppasyn_inpkt(queue_t * q,mblk_t * mp)1892 spppasyn_inpkt(queue_t *q, mblk_t *mp)
1893 {
1894 sppp_ahdlc_t *state = (sppp_ahdlc_t *)q->q_ptr;
1895 ushort_t proto;
1896 ushort_t prev_proto;
1897 uint32_t len; /* length of subframe */
1898 uchar_t muxhdr;
1899 mblk_t *hdrmp;
1900 mblk_t *subframe;
1901 mblk_t *retmp;
1902
1903 if (!(mp->b_rptr[0] & PFF)) {
1904 KINCR(pks_inmuxerrs);
1905 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1906 freemsg(mp);
1907 return (NULL);
1908 }
1909
1910 /* initialise the Last protocol and protocol length */
1911 prev_proto = 0;
1912
1913 /*
1914 * Taking into granted that the decoded frame is contiguous
1915 */
1916 retmp = NULL;
1917 while (mp->b_rptr < mp->b_wptr) {
1918
1919 /*
1920 * get the last protocol, protocol length
1921 * and the length of the message
1922 */
1923
1924 /* protocol field flag and length */
1925 muxhdr = mp->b_rptr[0];
1926 len = muxhdr & ~PFF;
1927
1928 mp->b_rptr++;
1929
1930 /* check if there and enough bytes left in pkt */
1931 if (MBLKL(mp) < len) {
1932 KINCR(pks_inmuxerrs);
1933 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR);
1934 break;
1935 }
1936
1937 /* allocate memory for the header length */
1938 if ((hdrmp = allocb(PPP_HDRLEN, BPRI_MED)) == NULL) {
1939 KINCR(pks_inallocfails);
1940 break;
1941 }
1942
1943 /* add the ppp header to the pkt */
1944 *hdrmp->b_wptr++ = PPP_ALLSTATIONS;
1945 *hdrmp->b_wptr++ = PPP_UI;
1946
1947 /* check if the protocol field flag is set */
1948 if (muxhdr & PFF) {
1949
1950 /* get the protocol */
1951 proto = MSG_BYTE(mp, 0);
1952 if ((proto & 1) == 0)
1953 proto = (proto << 8) + MSG_BYTE(mp, 1);
1954
1955 /* reset values */
1956 prev_proto = proto;
1957 } else {
1958 if (!IS_DECOMP_PROT(state))
1959 *hdrmp->b_wptr++ = prev_proto >> 8;
1960 *hdrmp->b_wptr++ = (prev_proto & 0xff);
1961 }
1962
1963 /* get the payload from the MUXed packet */
1964 subframe = dupmsg(mp);
1965 subframe->b_wptr = mp->b_rptr + len;
1966
1967 /* link the subframe to the new frame */
1968 linkb(hdrmp, subframe);
1969
1970 /* do a putnext */
1971 retmp = sppp_mappend(retmp, hdrmp);
1972
1973 /* move the read pointer beyond this subframe */
1974 mp->b_rptr += len;
1975 }
1976
1977 freemsg(mp);
1978 return (retmp);
1979 }
1980
1981
1982 /*
1983 * timer routine which sends out the queued pkts *
1984 */
1985 static void
spppasyn_timer(void * arg)1986 spppasyn_timer(void *arg)
1987 {
1988 queue_t *q;
1989 sppp_ahdlc_t *state;
1990 mblk_t *mp;
1991
1992 ASSERT(arg);
1993 q = (queue_t *)arg;
1994 state = (sppp_ahdlc_t *)q->q_ptr;
1995
1996 if (state->sa_mqhead != NULL) {
1997 /* increment counter */
1998 if (state->sa_mqtail != NULL)
1999 KINCR(pks_sentmux);
2000 if ((mp = ahdlc_encode(q, state->sa_mqhead)) != NULL)
2001 putnext(q, mp);
2002 /* reset the state values over here */
2003 RESET_MUX_VALUES(state);
2004 }
2005 /* clear timeout_id */
2006 state->sa_timeout_id = 0;
2007 }
2008