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