xref: /illumos-gate/usr/src/uts/common/io/ppp/sppp/sppp_dlpi.c (revision e7cbe64f7a72dae5cb44f100db60ca88f3313c65)
1 /*
2  * sppp_dlpi.c - Solaris STREAMS PPP multiplexing pseudo-driver DLPI handlers
3  *
4  * Copyright 2004 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  * This driver is derived from the original SVR4 STREAMS PPP driver
42  * originally written by Paul Mackerras <paul.mackerras@cs.anu.edu.au>.
43  *
44  * Adi Masputra <adi.masputra@sun.com> rewrote and restructured the code
45  * for improved performance and scalability.
46  */
47 
48 #pragma ident	"%Z%%M%	%I%	%E% SMI"
49 #define	RCSID	"$Id: sppp_dlpi.c,v 1.0 2000/05/08 01:10:12 masputra Exp $"
50 
51 #include <sys/types.h>
52 #include <sys/param.h>
53 #include <sys/stat.h>
54 #include <sys/stream.h>
55 #include <sys/stropts.h>
56 #include <sys/errno.h>
57 #include <sys/time.h>
58 #include <sys/cmn_err.h>
59 #include <sys/conf.h>
60 #include <sys/dlpi.h>
61 #include <sys/ddi.h>
62 #include <sys/kstat.h>
63 #include <sys/strsun.h>
64 #include <sys/ethernet.h>
65 #include <net/ppp_defs.h>
66 #include <netinet/in.h>
67 #include <net/pppio.h>
68 #include "s_common.h"
69 #include "sppp.h"
70 
71 static int	sppp_dlattachreq(queue_t *, mblk_t *, spppstr_t *);
72 static int	sppp_dldetachreq(queue_t *, mblk_t *, spppstr_t *);
73 static int	sppp_dlbindreq(queue_t *, mblk_t *, spppstr_t *);
74 static int	sppp_dlunbindreq(queue_t *, mblk_t *, spppstr_t *);
75 static int	sppp_dlinforeq(queue_t *, mblk_t *, spppstr_t *);
76 static int	sppp_dlunitdatareq(queue_t *, mblk_t *, spppstr_t *);
77 static int	sppp_dlpromisconreq(queue_t *, mblk_t *, spppstr_t *);
78 static int	sppp_dlpromiscoffreq(queue_t *, mblk_t *, spppstr_t *);
79 static int	sppp_dlphyreq(queue_t *, mblk_t *, spppstr_t *);
80 static void	sppp_dl_attach_upper(queue_t *, mblk_t *);
81 static void	sppp_dl_detach_upper(queue_t *, mblk_t *);
82 static void	sppp_dl_bind(queue_t *, mblk_t *);
83 static void	sppp_dl_unbind(queue_t *, mblk_t *);
84 static void	sppp_dl_promiscon(queue_t *, mblk_t *);
85 static void	sppp_dl_promiscoff(queue_t *, mblk_t *);
86 static mblk_t	*sppp_dladdether(spppstr_t *, mblk_t *, t_scalar_t);
87 
88 static struct sppp_dlpi_pinfo_t dl_pinfo[DL_MAXPRIM + 1];
89 
90 #if 0
91 #define	DBGERROR(x)	cmn_err x
92 #else
93 #define	DBGERROR(x)	((void)0)
94 #endif
95 
96 /* #define	DBG_DLPI	1 */
97 
98 #ifdef DBG_DLPI
99 struct sppp_dlpi_entry {
100 	uint32_t sde_val;
101 	const char *sde_name;
102 };
103 
104 static const struct sppp_dlpi_entry sppp_dlpi_list[] = {
105 	{ DL_INFO_REQ, "DL_INFO_REQ" },
106 	{ DL_INFO_ACK, "DL_INFO_ACK" },
107 	{ DL_ATTACH_REQ, "DL_ATTACH_REQ" },
108 	{ DL_DETACH_REQ, "DL_DETACH_REQ" },
109 	{ DL_BIND_REQ, "DL_BIND_REQ" },
110 	{ DL_BIND_ACK, "DL_BIND_ACK" },
111 	{ DL_UNBIND_REQ, "DL_UNBIND_REQ" },
112 	{ DL_OK_ACK, "DL_OK_ACK" },
113 	{ DL_ERROR_ACK, "DL_ERROR_ACK" },
114 	{ DL_SUBS_BIND_REQ, "DL_SUBS_BIND_REQ" },
115 	{ DL_SUBS_BIND_ACK, "DL_SUBS_BIND_ACK" },
116 	{ DL_SUBS_UNBIND_REQ, "DL_SUBS_UNBIND_REQ" },
117 	{ DL_ENABMULTI_REQ, "DL_ENABMULTI_REQ" },
118 	{ DL_DISABMULTI_REQ, "DL_DISABMULTI_REQ" },
119 	{ DL_PROMISCON_REQ, "DL_PROMISCON_REQ" },
120 	{ DL_PROMISCOFF_REQ, "DL_PROMISCOFF_REQ" },
121 	{ DL_UNITDATA_REQ, "DL_UNITDATA_REQ" },
122 	{ DL_UNITDATA_IND, "DL_UNITDATA_IND" },
123 	{ DL_UDERROR_IND, "DL_UDERROR_IND" },
124 	{ DL_UDQOS_REQ, "DL_UDQOS_REQ" },
125 	{ DL_CONNECT_REQ, "DL_CONNECT_REQ" },
126 	{ DL_CONNECT_IND, "DL_CONNECT_IND" },
127 	{ DL_CONNECT_RES, "DL_CONNECT_RES" },
128 	{ DL_CONNECT_CON, "DL_CONNECT_CON" },
129 	{ DL_TOKEN_REQ, "DL_TOKEN_REQ" },
130 	{ DL_TOKEN_ACK, "DL_TOKEN_ACK" },
131 	{ DL_DISCONNECT_REQ, "DL_DISCONNECT_REQ" },
132 	{ DL_DISCONNECT_IND, "DL_DISCONNECT_IND" },
133 	{ DL_RESET_REQ, "DL_RESET_REQ" },
134 	{ DL_RESET_IND, "DL_RESET_IND" },
135 	{ DL_RESET_RES, "DL_RESET_RES" },
136 	{ DL_RESET_CON, "DL_RESET_CON" },
137 	{ DL_DATA_ACK_REQ, "DL_DATA_ACK_REQ" },
138 	{ DL_DATA_ACK_IND, "DL_DATA_ACK_IND" },
139 	{ DL_DATA_ACK_STATUS_IND, "DL_DATA_ACK_STATUS_IND" },
140 	{ DL_REPLY_REQ, "DL_REPLY_REQ" },
141 	{ DL_REPLY_IND, "DL_REPLY_IND" },
142 	{ DL_REPLY_STATUS_IND, "DL_REPLY_STATUS_IND" },
143 	{ DL_REPLY_UPDATE_REQ, "DL_REPLY_UPDATE_REQ" },
144 	{ DL_REPLY_UPDATE_STATUS_IND, "DL_REPLY_UPDATE_STATUS_IND" },
145 	{ DL_XID_REQ, "DL_XID_REQ" },
146 	{ DL_XID_IND, "DL_XID_IND" },
147 	{ DL_XID_RES, "DL_XID_RES" },
148 	{ DL_XID_CON, "DL_XID_CON" },
149 	{ DL_TEST_REQ, "DL_TEST_REQ" },
150 	{ DL_TEST_IND, "DL_TEST_IND" },
151 	{ DL_TEST_RES, "DL_TEST_RES" },
152 	{ DL_TEST_CON, "DL_TEST_CON" },
153 	{ DL_PHYS_ADDR_REQ, "DL_PHYS_ADDR_REQ" },
154 	{ DL_PHYS_ADDR_ACK, "DL_PHYS_ADDR_ACK" },
155 	{ DL_SET_PHYS_ADDR_REQ, "DL_SET_PHYS_ADDR_REQ" },
156 	{ DL_GET_STATISTICS_REQ, "DL_GET_STATISTICS_REQ" },
157 	{ DL_GET_STATISTICS_ACK, "DL_GET_STATISTICS_ACK" },
158 	{ 0, NULL }
159 };
160 
161 static const struct sppp_dlpi_entry sppp_state_list[] = {
162 	{ DL_UNBOUND, "DL_UNBOUND" },
163 	{ DL_BIND_PENDING, "DL_BIND_PENDING" },
164 	{ DL_UNBIND_PENDING, "DL_UNBIND_PENDING" },
165 	{ DL_IDLE, "DL_IDLE" },
166 	{ DL_UNATTACHED, "DL_UNATTACHED" },
167 	{ DL_ATTACH_PENDING, "DL_ATTACH_PENDING" },
168 	{ DL_DETACH_PENDING, "DL_DETACH_PENDING" },
169 	{ DL_UDQOS_PENDING, "DL_UDQOS_PENDING" },
170 	{ DL_OUTCON_PENDING, "DL_OUTCON_PENDING" },
171 	{ DL_INCON_PENDING, "DL_INCON_PENDING" },
172 	{ DL_CONN_RES_PENDING, "DL_CONN_RES_PENDING" },
173 	{ DL_DATAXFER, "DL_DATAXFER" },
174 	{ DL_USER_RESET_PENDING, "DL_USER_RESET_PENDING" },
175 	{ DL_PROV_RESET_PENDING, "DL_PROV_RESET_PENDING" },
176 	{ DL_RESET_RES_PENDING, "DL_RESET_RES_PENDING" },
177 	{ DL_DISCON8_PENDING, "DL_DISCON8_PENDING" },
178 	{ DL_DISCON9_PENDING, "DL_DISCON9_PENDING" },
179 	{ DL_DISCON11_PENDING, "DL_DISCON11_PENDING" },
180 	{ DL_DISCON12_PENDING, "DL_DISCON12_PENDING" },
181 	{ DL_DISCON13_PENDING, "DL_DISCON13_PENDING" },
182 	{ DL_SUBS_BIND_PND, "DL_SUBS_BIND_PND" },
183 	{ DL_SUBS_UNBIND_PND, "DL_SUBS_UNBIND_PND" },
184 	{ 0, NULL }
185 };
186 
187 static const char *
188 prim2name(uint32_t prim)
189 {
190 	const struct sppp_dlpi_entry *sde;
191 
192 	for (sde = sppp_dlpi_list; sde->sde_name != NULL; sde++)
193 		if (sde->sde_val == prim)
194 			break;
195 	return (sde->sde_name);
196 }
197 
198 static const char *
199 state2name(uint32_t state)
200 {
201 	const struct sppp_dlpi_entry *sde;
202 
203 	for (sde = sppp_state_list; sde->sde_name != NULL; sde++)
204 		if (sde->sde_val == state)
205 			break;
206 	return (sde->sde_name);
207 }
208 
209 #define	DBGDLPI(x)	cmn_err x
210 #else
211 #define	DBGDLPI(x)	((void)0)
212 #endif /* DBG_DLPI */
213 
214 /*
215  * DL_INFO_ACK template for point-to-point interface.
216  */
217 static dl_info_ack_t	sppp_infoack = {
218 	DL_INFO_ACK,			/* dl_primitive */
219 	PPP_MAXMTU,			/* dl_max_sdu */
220 	0,				/* dl_min_sdu */
221 	SPPP_ADDRL,			/* dl_addr_length */
222 	/*
223 	 * snoop et. al. don't know about DL_OTHER so this entry
224 	 * was changed to DL_ETHER so ethernet tracing/snooping
225 	 * facilities will work with PPP interfaces.
226 	 */
227 	DL_ETHER,			/* dl_mac_type */
228 	0,				/* dl_reserved */
229 	0,				/* dl_current_state */
230 	SPPP_SAPL,			/* dl_sap_length */
231 	DL_CLDLS,			/* dl_service_mode */
232 	0,				/* dl_qos_length */
233 	0,				/* dl_qos_offset */
234 	0,				/* dl_range_length */
235 	0,				/* dl_range_offset */
236 	DL_STYLE2,			/* dl_provider_style */
237 	sizeof (dl_info_ack_t),		/* dl_addr_offset */
238 	DL_VERSION_2,			/* dl_version */
239 	0,				/* dl_brdcst_addr_length */
240 	0,				/* dl_brdcst_addr_offset */
241 	0				/* dl_growth */
242 };
243 
244 /*
245  * sppp_dlpi_pinfoinit()
246  *
247  * Description:
248  *    Initialize dl_pinfo[], called from sppp_attach.
249  */
250 void
251 sppp_dlpi_pinfoinit(void)
252 {
253 	bzero(dl_pinfo, sizeof (dl_pinfo));	/* Just to be safe */
254 
255 	dl_pinfo[DL_ATTACH_REQ].pi_minlen = sizeof (dl_attach_req_t);
256 	dl_pinfo[DL_ATTACH_REQ].pi_state = DL_UNATTACHED;
257 	dl_pinfo[DL_ATTACH_REQ].pi_funcp = sppp_dlattachreq;
258 
259 	dl_pinfo[DL_DETACH_REQ].pi_minlen = sizeof (dl_detach_req_t);
260 	dl_pinfo[DL_DETACH_REQ].pi_state = DL_UNBOUND;
261 	dl_pinfo[DL_DETACH_REQ].pi_funcp = sppp_dldetachreq;
262 
263 	dl_pinfo[DL_BIND_REQ].pi_minlen = sizeof (dl_bind_req_t);
264 	dl_pinfo[DL_BIND_REQ].pi_state = DL_UNBOUND;
265 	dl_pinfo[DL_BIND_REQ].pi_funcp = sppp_dlbindreq;
266 
267 	dl_pinfo[DL_UNBIND_REQ].pi_minlen = sizeof (dl_unbind_req_t);
268 	dl_pinfo[DL_UNBIND_REQ].pi_state = DL_IDLE;
269 	dl_pinfo[DL_UNBIND_REQ].pi_funcp = sppp_dlunbindreq;
270 
271 	dl_pinfo[DL_INFO_REQ].pi_minlen = sizeof (dl_info_req_t);
272 	dl_pinfo[DL_INFO_REQ].pi_state = 0;	/* special handling */
273 	dl_pinfo[DL_INFO_REQ].pi_funcp = sppp_dlinforeq;
274 
275 	dl_pinfo[DL_UNITDATA_REQ].pi_minlen = sizeof (dl_unitdata_req_t);
276 	dl_pinfo[DL_UNITDATA_REQ].pi_state = DL_IDLE;
277 	dl_pinfo[DL_UNITDATA_REQ].pi_funcp = sppp_dlunitdatareq;
278 
279 	dl_pinfo[DL_PROMISCON_REQ].pi_minlen = sizeof (dl_promiscon_req_t);
280 	dl_pinfo[DL_PROMISCON_REQ].pi_state = 0; /* special handling */
281 	dl_pinfo[DL_PROMISCON_REQ].pi_funcp = sppp_dlpromisconreq;
282 
283 	dl_pinfo[DL_PROMISCOFF_REQ].pi_minlen = sizeof (dl_promiscoff_req_t);
284 	dl_pinfo[DL_PROMISCOFF_REQ].pi_state = 0; /* special handling */
285 	dl_pinfo[DL_PROMISCOFF_REQ].pi_funcp = sppp_dlpromiscoffreq;
286 
287 	dl_pinfo[DL_PHYS_ADDR_REQ].pi_minlen = sizeof (dl_phys_addr_req_t);
288 	dl_pinfo[DL_PHYS_ADDR_REQ].pi_state = 0; /* special handling */
289 	dl_pinfo[DL_PHYS_ADDR_REQ].pi_funcp = sppp_dlphyreq;
290 }
291 
292 /*
293  * sppp_mproto()
294  *
295  * MT-Perimeters:
296  *    shared inner, shared outer.
297  *
298  * Description:
299  *    Handle M_PCPROTO/M_PROTO messages, called by sppp_uwput.
300  */
301 int
302 sppp_mproto(queue_t *q, mblk_t *mp, spppstr_t *sps)
303 {
304 	union DL_primitives *dlp;
305 	struct sppp_dlpi_pinfo_t *dpi;
306 	t_uscalar_t	prim;
307 	int		len;
308 	int		error = 0;
309 
310 	ASSERT(!IS_SPS_CONTROL(sps));
311 	if ((len = MBLKL(mp)) < sizeof (t_uscalar_t)) {
312 		DBGERROR((CE_CONT, "bad mproto: block length %d\n", len));
313 		merror(q, mp, EPROTO);
314 		return (0);
315 	}
316 	dlp = (union DL_primitives *)mp->b_rptr;
317 	prim = dlp->dl_primitive;
318 	if (prim > DL_MAXPRIM) {
319 		DBGERROR((CE_CONT, "bad mproto: primitive %d > %d\n", prim,
320 		    DL_MAXPRIM));
321 		error = DL_BADPRIM;
322 	} else {
323 		dpi = &dl_pinfo[prim];
324 		if (dpi->pi_funcp == NULL) {
325 			DBGERROR((CE_CONT,
326 			    "bad mproto: primitive %d not supported\n", prim));
327 			error = DL_NOTSUPPORTED;
328 		} else if (len < dpi->pi_minlen) {
329 			DBGERROR((CE_CONT,
330 			    "bad mproto: primitive len %d < %d\n", len,
331 			    dpi->pi_minlen));
332 			error = DL_BADPRIM;
333 		} else if ((dpi->pi_state != 0) &&
334 		    (sps->sps_dlstate != dpi->pi_state)) {
335 			DBGERROR((CE_CONT,
336 			    "bad state %d != %d for primitive %d\n",
337 			    sps->sps_dlstate, dpi->pi_state, prim));
338 			error = DL_OUTSTATE;
339 		}
340 	}
341 	if (error != 0) {
342 		dlerrorack(q, mp, dlp->dl_primitive, error, 0);
343 		return (0);
344 	}
345 #ifdef DBG_DLPI
346 	{
347 		const char *cp = prim2name(prim);
348 		if (cp != NULL)
349 			cmn_err(CE_CONT, "/%d: Dispatching %s\n",
350 			    sps->sps_mn_id, cp);
351 		else
352 			cmn_err(CE_CONT,
353 			    "/%d: Dispatching unknown primitive %d\n",
354 			    sps->sps_mn_id, prim);
355 	}
356 #endif
357 	return ((*dpi->pi_funcp)(q, mp, sps));
358 }
359 
360 /*
361  * sppp_dlattachreq()
362  *
363  * MT-Perimeters:
364  *    shared inner, shared outer.
365  *
366  * Description:
367  *    Perform DL_ATTACH_REQ request, called by sppp_mproto.
368  */
369 static int
370 sppp_dlattachreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
371 {
372 	int	error = 0;
373 	union DL_primitives *dlp;
374 
375 	ASSERT(q != NULL && q->q_ptr != NULL);
376 	ASSERT(mp != NULL && mp->b_rptr != NULL);
377 	dlp = (union DL_primitives *)mp->b_rptr;
378 	ASSERT(sps != NULL);
379 	ASSERT(sps->sps_dlstate == DL_UNATTACHED);
380 
381 	if (IS_SPS_PIOATTACH(sps)) {
382 		DBGERROR((CE_CONT, "DLPI attach: already attached\n"));
383 		error = EINVAL;
384 	}
385 	if (error != 0) {
386 		dlerrorack(q, mp, dlp->dl_primitive, DL_OUTSTATE, error);
387 	} else {
388 		qwriter(q, mp, sppp_dl_attach_upper, PERIM_OUTER);
389 	}
390 	return (0);
391 }
392 
393 /*
394  * sppp_dl_attach_upper()
395  *
396  * MT-Perimeters:
397  *    exclusive inner, exclusive outer.
398  *
399  * Description:
400  *    Called by qwriter (INNER) from sppp_dlattachreq as the result of
401  *    receiving a DL_ATTACH_REQ message.
402  */
403 static void
404 sppp_dl_attach_upper(queue_t *q, mblk_t *mp)
405 {
406 	sppa_t		*ppa;
407 	spppstr_t	*sps;
408 	union DL_primitives *dlp;
409 
410 	ASSERT(q != NULL && q->q_ptr != NULL);
411 	sps = (spppstr_t *)q->q_ptr;
412 	ASSERT(!IS_SPS_PIOATTACH(sps));
413 	ASSERT(mp != NULL && mp->b_rptr != NULL);
414 	dlp = (union DL_primitives *)mp->b_rptr;
415 
416 	/* If there's something here, it's detached. */
417 	if (sps->sps_ppa != NULL) {
418 		sppp_remove_ppa(sps);
419 	}
420 
421 	ppa = sppp_find_ppa(dlp->attach_req.dl_ppa);
422 	if (ppa == NULL)
423 		ppa = sppp_create_ppa(dlp->attach_req.dl_ppa);
424 
425 	/*
426 	 * If we can't find it, then it's either because the requestor
427 	 * has supplied a wrong dl_ppa to be attached to, or because
428 	 * the control stream for the specified ppa has been closed
429 	 * before we get here.
430 	 */
431 	if (ppa == NULL) {
432 		DBGERROR((CE_CONT, "DLPI attach: cannot create ppa %u\n",
433 		    dlp->attach_req.dl_ppa));
434 		dlerrorack(q, mp, dlp->dl_primitive, DL_SYSERR, ENOMEM);
435 		return;
436 	}
437 	/*
438 	 * Preallocate the hangup message so that we're always able to
439 	 * send this upstream in the event of a catastrophic failure.
440 	 */
441 	if ((sps->sps_hangup = allocb(1, BPRI_MED)) == NULL) {
442 		DBGERROR((CE_CONT, "DLPI attach: cannot allocate hangup\n"));
443 		dlerrorack(q, mp, dlp->dl_primitive, DL_SYSERR, ENOSR);
444 		return;
445 	}
446 	sps->sps_dlstate = DL_UNBOUND;
447 	sps->sps_ppa = ppa;
448 	/*
449 	 * Add this stream to the head of the list of sibling streams
450 	 * which belong to the specified ppa.
451 	 */
452 	rw_enter(&ppa->ppa_sib_lock, RW_WRITER);
453 	ppa->ppa_refcnt++;
454 	sps->sps_nextsib = ppa->ppa_streams;
455 	ppa->ppa_streams = sps;
456 	/*
457 	 * And if this stream was marked as promiscuous (SPS_PROMISC), then we
458 	 * need to update the promiscuous streams count. This should only
459 	 * happen when DL_PROMISCON_REQ was issued prior to attachment.
460 	 */
461 	if (IS_SPS_PROMISC(sps)) {
462 		ppa->ppa_promicnt++;
463 	}
464 	rw_exit(&ppa->ppa_sib_lock);
465 	DBGDLPI((CE_CONT, "/%d: attached to ppa %d\n", sps->sps_mn_id,
466 	    ppa->ppa_ppa_id));
467 	dlokack(q, mp, DL_ATTACH_REQ);
468 }
469 
470 /*
471  * sppp_dldetachreq()
472  *
473  * MT-Perimeters:
474  *    shared inner, shared outer.
475  *
476  * Description:
477  *    Perform DL_DETACH_REQ request, called by sppp_mproto.
478  */
479 /* ARGSUSED */
480 static int
481 sppp_dldetachreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
482 {
483 	ASSERT(q != NULL && q->q_ptr != NULL);
484 	ASSERT(mp != NULL && mp->b_rptr != NULL);
485 	ASSERT(sps != NULL);
486 	ASSERT(sps->sps_dlstate == DL_UNBOUND);
487 	ASSERT(!IS_SPS_PIOATTACH(sps));
488 
489 	qwriter(q, mp, sppp_dl_detach_upper, PERIM_INNER);
490 	return (0);
491 }
492 
493 /*
494  * sppp_dl_detach_upper()
495  *
496  * MT-Perimeters:
497  *    exclusive inner, shared outer.
498  *
499  * Description:
500  *    Called by qwriter (INNER) from sppp_dldetachreq as the result of
501  *    receiving a DL_DETACH_REQ message.
502  */
503 /* ARGSUSED */
504 static void
505 sppp_dl_detach_upper(queue_t *q, mblk_t *mp)
506 {
507 	spppstr_t	*sps;
508 
509 	ASSERT(q != NULL && q->q_ptr != NULL);
510 	ASSERT(mp != NULL && mp->b_rptr != NULL);
511 	sps = (spppstr_t *)q->q_ptr;
512 	/*
513 	 * We don't actually detach from the PPA until closed or
514 	 * reattached.
515 	 */
516 	sps->sps_flags &= ~SPS_PROMISC;	/* clear flag anyway */
517 	sps->sps_dlstate = DL_UNATTACHED;
518 	dlokack(q, mp, DL_DETACH_REQ);
519 }
520 
521 /*
522  * sppp_dlbindreq()
523  *
524  * MT-Perimeters:
525  *    shared inner, shared outer.
526  *
527  * Description:
528  *    Perform DL_BIND_REQ request, called by sppp_mproto.
529  */
530 static int
531 sppp_dlbindreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
532 {
533 	sppa_t			*ppa;
534 	union DL_primitives	*dlp;
535 	spppreqsap_t		req_sap;
536 	int			error = 0;
537 
538 	ASSERT(q != NULL && q->q_ptr != NULL);
539 	ASSERT(mp != NULL && mp->b_rptr != NULL);
540 	dlp = (union DL_primitives *)mp->b_rptr;
541 	req_sap = dlp->bind_req.dl_sap;
542 	ASSERT(sps != NULL);
543 	ASSERT(!IS_SPS_PIOATTACH(sps));
544 	ASSERT(sps->sps_dlstate == DL_UNBOUND);
545 
546 	ppa = sps->sps_ppa;
547 	if (ppa == NULL) {
548 		DBGERROR((CE_CONT, "DLPI bind: no attached ppa\n"));
549 		error = DL_OUTSTATE;
550 	} else if ((req_sap != ETHERTYPE_IP) && (req_sap != ETHERTYPE_IPV6) &&
551 		(req_sap != ETHERTYPE_ALLSAP)) {
552 		DBGERROR((CE_CONT, "DLPI bind: unknown SAP %x\n", req_sap));
553 		error = DL_BADADDR;
554 	}
555 	if (error != 0) {
556 		dlerrorack(q, mp, dlp->dl_primitive, error, 0);
557 	} else {
558 		qwriter(q, mp, sppp_dl_bind, PERIM_INNER);
559 	}
560 	return (0);
561 }
562 
563 /*
564  * sppp_dl_bind()
565  *
566  * MT-Perimeters:
567  *    exclusive inner, shared outer.
568  *
569  * Description:
570  *    Called by qwriter (INNER) from sppp_dlbindreq as the result of
571  *    receiving a DL_BIND_REQ message.
572  */
573 static void
574 sppp_dl_bind(queue_t *q, mblk_t *mp)
575 {
576 	spppstr_t		*sps;
577 	sppa_t			*ppa;
578 	union DL_primitives	*dlp;
579 	t_scalar_t		sap;
580 	spppreqsap_t		req_sap;
581 	mblk_t			*lsmp;
582 
583 	ASSERT(q != NULL && q->q_ptr != NULL);
584 	sps = (spppstr_t *)q->q_ptr;
585 	ASSERT(mp != NULL && mp->b_rptr != NULL);
586 	dlp = (union DL_primitives *)mp->b_rptr;
587 	ppa = sps->sps_ppa;
588 	ASSERT(ppa != NULL);
589 	req_sap = dlp->bind_req.dl_sap;
590 	ASSERT((req_sap == ETHERTYPE_IP) || (req_sap == ETHERTYPE_IPV6) ||
591 		(req_sap == ETHERTYPE_ALLSAP));
592 
593 	if (req_sap == ETHERTYPE_IP) {
594 		sap = PPP_IP;
595 	} else if (req_sap == ETHERTYPE_IPV6) {
596 		sap = PPP_IPV6;
597 	} else if (req_sap == ETHERTYPE_ALLSAP) {
598 		sap = PPP_ALLSAP;
599 	}
600 	/*
601 	 * If there's another stream with the same sap has already been bound
602 	 * to the same ppa, then return with DL_NOADDR. However, we do make an
603 	 * exception for snoop (req_sap=0x00, sap=0xff) since multiple
604 	 * instances of snoop may execute an a given device.
605 	 */
606 	lsmp = NULL;
607 	if (sap != PPP_ALLSAP) {
608 		if ((sap == PPP_IP) && (ppa->ppa_ip_cache == NULL)) {
609 			ppa->ppa_ip_cache = sps;
610 			if (ppa->ppa_ctl != NULL) {
611 				lsmp = create_lsmsg(PPP_LINKSTAT_IPV4_BOUND);
612 			}
613 		} else if ((sap == PPP_IPV6) && (ppa->ppa_ip6_cache == NULL)) {
614 			ppa->ppa_ip6_cache = sps;
615 			if (ppa->ppa_ctl != NULL) {
616 				lsmp = create_lsmsg(PPP_LINKSTAT_IPV6_BOUND);
617 			}
618 		} else {
619 			DBGERROR((CE_CONT, "DLPI bind: bad SAP %x\n", sap));
620 			dlerrorack(q, mp, dlp->dl_primitive, DL_NOADDR,
621 			    EEXIST);
622 			return;
623 		}
624 		sps->sps_flags |= SPS_CACHED;
625 	}
626 	/*
627 	 * Tell the daemon that a DLPI bind has happened on this stream,
628 	 * and we'll only do this for PPP_IP or PPP_IPV6 sap (not snoop).
629 	 */
630 	if (lsmp != NULL && ppa->ppa_ctl != NULL) {
631 #ifdef DBG_DLPI
632 		cmn_err(CE_CONT, "sending up %s\n",
633 		    ((sap == PPP_IP) ? "PPP_LINKSTAT_IPV4_BOUND" :
634 		    "PPP_LINKSTAT_IPV6_BOUND"));
635 #endif
636 		putnext(ppa->ppa_ctl->sps_rq, lsmp);
637 	}
638 	DBGDLPI((CE_CONT, "/%d: bound to sap %X (req %X)\n", sps->sps_mn_id,
639 	    sap, req_sap));
640 	sps->sps_req_sap = req_sap;
641 	sps->sps_sap = sap;
642 	sps->sps_dlstate = DL_IDLE;
643 	dlbindack(q, mp, req_sap, &sap, sizeof (int32_t), 0, 0);
644 }
645 
646 /*
647  * sppp_dlunbindreq()
648  *
649  * MT-Perimeters:
650  *    shared inner, shared outer.
651  *
652  * Description:
653  *    Perform DL_UNBIND_REQ request, called by sppp_mproto.
654  */
655 /* ARGSUSED */
656 static int
657 sppp_dlunbindreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
658 {
659 	ASSERT(q != NULL && q->q_ptr != NULL);
660 	ASSERT(mp != NULL && mp->b_rptr != NULL);
661 	ASSERT(sps != NULL);
662 	ASSERT(!IS_SPS_PIOATTACH(sps));
663 	ASSERT(sps->sps_dlstate == DL_IDLE);
664 
665 	qwriter(q, mp, sppp_dl_unbind, PERIM_INNER);
666 	return (0);
667 }
668 
669 /*
670  * sppp_dl_unbind()
671  *
672  * MT-Perimeters:
673  *    exclusive inner, shared outer.
674  *
675  * Description:
676  *    Called by qwriter (INNER) from sppp_dlunbindreq as the result of
677  *    receiving a DL_UNBIND_REQ message.
678  */
679 static void
680 sppp_dl_unbind(queue_t *q, mblk_t *mp)
681 {
682 	spppstr_t	*sps;
683 	sppa_t		*ppa;
684 	t_scalar_t	sap;
685 	mblk_t		*msg;
686 	boolean_t	saydown;
687 
688 	ASSERT(q != NULL && q->q_ptr != NULL);
689 	sps = (spppstr_t *)q->q_ptr;
690 	ppa = sps->sps_ppa;
691 	ASSERT(mp != NULL && mp->b_rptr != NULL);
692 	sap = sps->sps_sap;
693 	ASSERT((sap == PPP_IP) || (sap == PPP_IPV6) || (sap == PPP_ALLSAP));
694 
695 	/* Flush messages on unbind, per DLPI specification. */
696 	flushq(WR(q), FLUSHALL);
697 	flushq(RD(q), FLUSHALL);
698 
699 	if ((ppa != NULL) && IS_SPS_CACHED(sps)) {
700 		sps->sps_flags &= ~SPS_CACHED;
701 		msg = NULL;
702 		saydown = (ppa->ppa_ctl != NULL &&
703 		    (sps->sps_npmode == NPMODE_PASS ||
704 			sps->sps_npmode == NPMODE_QUEUE));
705 		if (sap == PPP_IP) {
706 			ppa->ppa_ip_cache = NULL;
707 			if (saydown)
708 				msg = create_lsmsg(PPP_LINKSTAT_IPV4_UNBOUND);
709 		} else if (sap == PPP_IPV6) {
710 			ppa->ppa_ip6_cache = NULL;
711 			if (saydown)
712 				msg = create_lsmsg(PPP_LINKSTAT_IPV6_UNBOUND);
713 		}
714 		if (msg != NULL) {
715 #ifdef DBG_DLPI
716 			cmn_err(CE_CONT, "sending up %s\n",
717 			    ((sap == PPP_IP) ? "PPP_LINKSTAT_IPV4_UNBOUND" :
718 			    "PPP_LINKSTAT_IPV6_UNBOUND"));
719 #endif
720 			putnext(ppa->ppa_ctl->sps_rq, msg);
721 		}
722 	}
723 	DBGDLPI((CE_CONT, "/%d: unbound from sap %X (req %X)\n", sps->sps_mn_id,
724 	    sps->sps_sap, sps->sps_req_sap));
725 	sps->sps_req_sap = 0;
726 	sps->sps_sap = -1;
727 	sps->sps_dlstate = DL_UNBOUND;
728 
729 	dlokack(q, mp, DL_UNBIND_REQ);
730 }
731 
732 /*
733  * sppp_dlinforeq()
734  *
735  * MT-Perimeters:
736  *    shared inner, shared outer.
737  *
738  * Description:
739  *    Perform DL_INFO_REQ request, called by sppp_mproto.
740  */
741 static int
742 sppp_dlinforeq(queue_t *q, mblk_t *mp, spppstr_t *sps)
743 {
744 	dl_info_ack_t	*dlip;
745 	uint32_t	size;
746 	uint32_t	addr_size;
747 	sppa_t		*ppa;
748 
749 	ASSERT(q != NULL && q->q_ptr != NULL);
750 	ASSERT(mp != NULL && mp->b_rptr != NULL);
751 	ASSERT(sps != NULL);
752 	ppa = sps->sps_ppa;
753 
754 	/* Exchange current msg for a DL_INFO_ACK. */
755 	addr_size = SPPP_ADDRL;
756 	size = sizeof (dl_info_ack_t) + addr_size;
757 	if ((mp = mexchange(q, mp, size, M_PCPROTO, DL_INFO_ACK)) == NULL) {
758 		DBGERROR((CE_CONT, "DLPI info: mexchange failed\n"));
759 		/* mexchange already sent up an merror ENOSR */
760 		return (0);
761 	}
762 	/* Fill in DL_INFO_ACK fields and reply */
763 	dlip = (dl_info_ack_t *)mp->b_rptr;
764 	*dlip = sppp_infoack;
765 	dlip->dl_current_state = sps->sps_dlstate;
766 	dlip->dl_max_sdu = ppa != NULL ? ppa->ppa_mtu : PPP_MAXMTU;
767 #ifdef DBG_DLPI
768 	{
769 		const char *cp = state2name(dlip->dl_current_state);
770 		if (cp != NULL)
771 			cmn_err(CE_CONT, "info returns state %s, max sdu %d\n",
772 			    cp, dlip->dl_max_sdu);
773 		else
774 			cmn_err(CE_CONT, "info returns state %d, max sdu %d\n",
775 			    dlip->dl_current_state, dlip->dl_max_sdu);
776 	}
777 #endif
778 	qreply(q, mp);
779 	return (0);
780 }
781 
782 /*
783  * sppp_dlunitdatareq()
784  *
785  * MT-Perimeters:
786  *    shared inner, shared outer.
787  *
788  * Description:
789  *    Handle DL_UNITDATA_REQ request, called by sppp_mproto. This procedure
790  *    gets called for M_PROTO (DLPI) style of transmission. The fact that we
791  *    have acknowledged IP's fastpath probing (DL_IOC_HDR_INFO) does not
792  *    guarantee that IP will always transmit via M_DATA, and it merely implies
793  *    that such situation _may_ happen. In other words, IP may decide to use
794  *    M_PROTO (DLPI) for data transmission should it decide to do so.
795  *    Therefore, we should never place any restrictions or checks against
796  *    streams marked with SPS_FASTPATH, since it is legal for this procedure
797  *    to be entered with or without the bit set.
798  */
799 static int
800 sppp_dlunitdatareq(queue_t *q, mblk_t *mp, spppstr_t *sps)
801 {
802 	sppa_t		*ppa;
803 	mblk_t		*hdrmp;
804 	mblk_t		*pktmp;
805 	dl_unitdata_req_t *dludp;
806 	int		dladdroff;
807 	int		dladdrlen;
808 	int		msize;
809 	int		error = 0;
810 	boolean_t	is_promisc;
811 
812 	ASSERT(q != NULL && q->q_ptr != NULL);
813 	ASSERT(mp != NULL && mp->b_rptr != NULL);
814 	ASSERT((MTYPE(mp) == M_PCPROTO) || (MTYPE(mp) == M_PROTO));
815 	dludp = (dl_unitdata_req_t *)mp->b_rptr;
816 	dladdroff = dludp->dl_dest_addr_offset;
817 	dladdrlen = dludp->dl_dest_addr_length;
818 	ASSERT(sps != NULL);
819 	ASSERT(!IS_SPS_PIOATTACH(sps));
820 	ASSERT(sps->sps_dlstate == DL_IDLE);
821 	ASSERT(q->q_ptr == sps);
822 	/*
823 	 * If this stream is not attached to any ppas, then discard data
824 	 * coming down through this stream.
825 	 */
826 	ppa = sps->sps_ppa;
827 	if (ppa == NULL) {
828 		DBGERROR((CE_CONT, "DLPI unitdata: no attached ppa\n"));
829 		error = ENOLINK;
830 	} else if (mp->b_cont == NULL) {
831 		DBGERROR((CE_CONT, "DLPI unitdata: missing data\n"));
832 		error = EPROTO;
833 	}
834 	if (error != 0) {
835 		dluderrorind(q, mp, mp->b_rptr + dladdroff, dladdrlen,
836 		    DL_BADDATA, error);
837 		return (0);
838 	}
839 	ASSERT(mp->b_cont->b_rptr != NULL);
840 	/*
841 	 * Check if outgoing packet size is larger than allowed. We use
842 	 * msgdsize to count all of M_DATA blocks in the message.
843 	 */
844 	msize = msgdsize(mp);
845 	if (msize > ppa->ppa_mtu) {
846 		/* Log, and send it anyway */
847 		mutex_enter(&ppa->ppa_sta_lock);
848 		ppa->ppa_otoolongs++;
849 		mutex_exit(&ppa->ppa_sta_lock);
850 	}
851 	if (IS_SPS_KDEBUG(sps)) {
852 		SPDEBUG(PPP_DRV_NAME
853 		    "/%d: DL_UNITDATA_REQ (%d bytes) sps=0x%p flags=0x%b "
854 		    "ppa=0x%p flags=0x%b\n", sps->sps_mn_id, msize,
855 		    (void *)sps, sps->sps_flags, SPS_FLAGS_STR,
856 		    (void *)ppa, ppa->ppa_flags, PPA_FLAGS_STR);
857 	}
858 	/* Allocate a message (M_DATA) to contain PPP header bytes. */
859 	if ((hdrmp = allocb(PPP_HDRLEN, BPRI_MED)) == NULL) {
860 		mutex_enter(&ppa->ppa_sta_lock);
861 		ppa->ppa_allocbfail++;
862 		mutex_exit(&ppa->ppa_sta_lock);
863 		DBGERROR((CE_CONT,
864 		    "DLPI unitdata: can't allocate header buffer\n"));
865 		dluderrorind(q, mp, mp->b_rptr + dladdroff, dladdrlen,
866 		    DL_SYSERR, ENOSR);
867 		return (0);
868 	}
869 	/*
870 	 * Should there be any promiscuous stream(s), send the data up
871 	 * for each promiscuous stream that we recognize.
872 	 */
873 	rw_enter(&ppa->ppa_sib_lock, RW_READER);
874 	is_promisc = ppa->ppa_promicnt;
875 	if (is_promisc) {
876 		ASSERT(ppa->ppa_streams != NULL);
877 		sppp_dlprsendup(ppa->ppa_streams, mp->b_cont, sps->sps_sap,
878 		    B_FALSE);
879 	}
880 	rw_exit(&ppa->ppa_sib_lock);
881 	/* Discard DLPI header and keep only IP payload (mp->b_cont). */
882 	pktmp = mp->b_cont;
883 	mp->b_cont = NULL;
884 	freemsg(mp);
885 	mp = hdrmp;
886 
887 	*(uchar_t *)mp->b_wptr++ = PPP_ALLSTATIONS;
888 	*(uchar_t *)mp->b_wptr++ = PPP_UI;
889 	*(uchar_t *)mp->b_wptr++ = ((uint16_t)sps->sps_sap >> 8) & 0xff;
890 	*(uchar_t *)mp->b_wptr++ = ((uint16_t)sps->sps_sap) & 0xff;
891 	ASSERT(MBLKL(mp) == PPP_HDRLEN);
892 
893 	linkb(mp, pktmp);
894 	/*
895 	 * Only time-stamp the packet with hrtime if the upper stream
896 	 * is configured to do so.
897 	 */
898 	if (IS_PPA_TIMESTAMP(ppa)) {
899 		ppa->ppa_lasttx = gethrtime();
900 	}
901 	/*
902 	 * Just put this back on the queue and allow the write service
903 	 * routine to handle it.  We're nested too deeply here to
904 	 * rewind the stack sufficiently to prevent overflow.  This is
905 	 * the slow path anyway.
906 	 */
907 	if (putq(q, mp) == 0) {
908 		mutex_enter(&ppa->ppa_sta_lock);
909 		ppa->ppa_oqdropped++;
910 		mutex_exit(&ppa->ppa_sta_lock);
911 		freemsg(mp);
912 	} else {
913 		qenable(q);
914 	}
915 	return (0);
916 }
917 
918 /*
919  * sppp_dlpromisconreq()
920  *
921  * MT-Perimeters:
922  *    shared inner, shared outer.
923  *
924  * Description:
925  *    Perform DL_PROMISCON_REQ request, called by sppp_mproto.
926  */
927 static int
928 sppp_dlpromisconreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
929 {
930 	t_uscalar_t	level;
931 
932 	ASSERT(q != NULL && q->q_ptr != NULL);
933 	ASSERT(mp != NULL && mp->b_rptr != NULL);
934 	level = ((dl_promiscon_req_t *)mp->b_rptr)->dl_level;
935 	ASSERT(sps != NULL);
936 
937 	/* snoop issues DL_PROMISCON_REQ more than once. */
938 	if (IS_SPS_PROMISC(sps)) {
939 		dlokack(q, mp, DL_PROMISCON_REQ);
940 	} else if ((level != DL_PROMISC_PHYS) && (level != DL_PROMISC_SAP) &&
941 	    (level != DL_PROMISC_MULTI)) {
942 		DBGERROR((CE_CONT, "DLPI promiscon: bad level %d\n", level));
943 		dlerrorack(q, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED, 0);
944 	} else {
945 		qwriter(q, mp, sppp_dl_promiscon, PERIM_INNER);
946 	}
947 	return (0);
948 }
949 
950 /*
951  * sppp_dl_promiscon()
952  *
953  * MT-Perimeters:
954  *    exclusive inner, shared outer.
955  *
956  * Description:
957  *    Called by qwriter (INNER) from sppp_dlpromisconreq as the result of
958  *    receiving a DL_PROMISCON_REQ message.
959  */
960 static void
961 sppp_dl_promiscon(queue_t *q, mblk_t *mp)
962 {
963 	spppstr_t	*sps;
964 	sppa_t		*ppa;
965 
966 	ASSERT(q != NULL && q->q_ptr != NULL);
967 	sps = (spppstr_t *)q->q_ptr;
968 	ASSERT(!IS_SPS_PROMISC(sps));
969 	ASSERT(mp != NULL && mp->b_rptr != NULL);
970 	ppa = sps->sps_ppa;
971 
972 	sps->sps_flags |= SPS_PROMISC;
973 	/*
974 	 * We can't be sure that the sps_ppa field is valid, since the DLPI
975 	 * spec says that DL_PROMISCON_REQ can be issued at any state, i.e.,
976 	 * the request can be issued even before DL_ATTACH_REQ or PPPIO_ATTACH
977 	 * be issued to associate this stream with a ppa.
978 	 */
979 	if (ppa != NULL) {
980 		rw_enter(&ppa->ppa_sib_lock, RW_WRITER);
981 		ppa->ppa_promicnt++;
982 		rw_exit(&ppa->ppa_sib_lock);
983 	}
984 	DBGDLPI((CE_CONT, "/%d: promiscuous mode on\n", sps->sps_mn_id));
985 	dlokack(q, mp, DL_PROMISCON_REQ);
986 }
987 
988 /*
989  * sppp_dlpromiscoffreq()
990  *
991  * MT-Perimeters:
992  *    shared inner, shared outer.
993  *
994  * Description:
995  *    Perform DL_PROMISCOFF_REQ request, called by sppp_mproto.
996  */
997 static int
998 sppp_dlpromiscoffreq(queue_t *q, mblk_t *mp, spppstr_t *sps)
999 {
1000 	t_uscalar_t	level;
1001 
1002 	ASSERT(q != NULL && q->q_ptr != NULL);
1003 	ASSERT(mp != NULL && mp->b_rptr != NULL);
1004 	level = ((dl_promiscoff_req_t *)mp->b_rptr)->dl_level;
1005 	ASSERT(sps != NULL);
1006 
1007 	if (!IS_SPS_PROMISC(sps)) {
1008 		DBGERROR((CE_CONT, "DLPI promiscoff: not promiscuous\n"));
1009 		dlerrorack(q, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0);
1010 	} else if ((level != DL_PROMISC_PHYS) && (level != DL_PROMISC_SAP) &&
1011 	    (level != DL_PROMISC_MULTI)) {
1012 		dlerrorack(q, mp, DL_PROMISCOFF_REQ, DL_NOTSUPPORTED, 0);
1013 		DBGERROR((CE_CONT, "DLPI promiscoff: bad level %d\n", level));
1014 	} else {
1015 		qwriter(q, mp, sppp_dl_promiscoff, PERIM_INNER);
1016 	}
1017 	return (0);
1018 
1019 }
1020 
1021 /*
1022  * sppp_dl_promiscoff()
1023  *
1024  * MT-Perimeters:
1025  *    exclusive inner, shared outer.
1026  *
1027  * Description:
1028  *    Called by qwriter (INNER) from sppp_dlpromiscoffreq as the result of
1029  *    receiving a DL_PROMISCOFF_REQ message.
1030  */
1031 static void
1032 sppp_dl_promiscoff(queue_t *q, mblk_t *mp)
1033 {
1034 	spppstr_t	*sps;
1035 	sppa_t		*ppa;
1036 
1037 	ASSERT(q != NULL && q->q_ptr != NULL);
1038 	sps = (spppstr_t *)q->q_ptr;
1039 	ASSERT(IS_SPS_PROMISC(sps));
1040 	ASSERT(mp != NULL && mp->b_rptr != NULL);
1041 	ppa = sps->sps_ppa;
1042 
1043 	sps->sps_flags &= ~SPS_PROMISC;
1044 	/*
1045 	 * We can't be guaranteed that the sps_ppa field is still valid, since
1046 	 * the control stream might have been closed earlier, in which case
1047 	 * the close procedure would have NULL'd out the sps_ppa.
1048 	 */
1049 	if (ppa != NULL) {
1050 		rw_enter(&ppa->ppa_sib_lock, RW_WRITER);
1051 		ASSERT(ppa->ppa_promicnt > 0);
1052 		ppa->ppa_promicnt--;
1053 		rw_exit(&ppa->ppa_sib_lock);
1054 	}
1055 	DBGDLPI((CE_CONT, "/%d: promiscuous mode off\n", sps->sps_mn_id));
1056 	dlokack(q, mp, DL_PROMISCOFF_REQ);
1057 }
1058 
1059 /*
1060  * sppp_dlphyreq()
1061  *
1062  * MT-Perimeters:
1063  *    shared inner, shared outer.
1064  *
1065  * Description:
1066  *    Perform DL_PHYS_ADDR_REQ request, called by sppp_mproto. This doesn't
1067  *    return anything useful, but it keeps ifconfig happy.
1068  */
1069 /* ARGSUSED */
1070 static int
1071 sppp_dlphyreq(queue_t *q, mblk_t *mp, spppstr_t *us)
1072 {
1073 	static struct ether_addr addr = { 0 };
1074 
1075 	dlphysaddrack(q, mp, (char *)&addr, ETHERADDRL);
1076 	return (0);
1077 }
1078 
1079 /*
1080  * sppp_dladdether()
1081  *
1082  * Description:
1083  *    Prepend an empty Ethernet header to msg for snoop, et al. Free
1084  *    the original mblk if alloc fails. Only called for the purpose of sending
1085  *    packets up the promiscous stream.
1086  */
1087 /* ARGSUSED */
1088 static mblk_t *
1089 sppp_dladdether(spppstr_t *sps, mblk_t *mp, t_scalar_t proto)
1090 {
1091 	mblk_t		*eh;
1092 	t_scalar_t	type;
1093 
1094 	if ((eh = allocb(sizeof (struct ether_header), BPRI_MED)) == NULL) {
1095 		freemsg(mp);
1096 		return (NULL);
1097 	}
1098 	if (proto == PPP_IP) {
1099 		type = ETHERTYPE_IP;
1100 	} else if (proto == PPP_IPV6) {
1101 		type = ETHERTYPE_IPV6;
1102 	} else {
1103 		/*
1104 		 * For all other protocols, end this up as an ETHERTYPE_PPP
1105 		 * type of packet. Since we've skipped the PPP headers in the
1106 		 * caller, make sure that we restore it. We know for sure that
1107 		 * the PPP header still exists in the message (only skipped),
1108 		 * since the sender of this message is pppd and it must have
1109 		 * included the PPP header in front.
1110 		 */
1111 		type = ETHERTYPE_PPP;
1112 		mp->b_rptr -= PPP_HDRLEN;
1113 		ASSERT(mp->b_rptr >= mp->b_datap->db_base);
1114 	}
1115 	eh->b_wptr += sizeof (struct ether_header);
1116 	bzero((caddr_t)eh->b_rptr, sizeof (struct ether_header));
1117 	((struct ether_header *)eh->b_rptr)->ether_type = htons((int16_t)type);
1118 
1119 	linkb(eh, mp);
1120 	return (eh);
1121 }
1122 
1123 /*
1124  * sppp_dladdud()
1125  *
1126  * Description:
1127  *    Prepend DL_UNITDATA_IND mblk to msg, free original alloc fails.
1128  */
1129 /* ARGSUSED */
1130 mblk_t *
1131 sppp_dladdud(spppstr_t *sps, mblk_t *mp, t_scalar_t proto, boolean_t promisc)
1132 {
1133 	dl_unitdata_ind_t *dlu;
1134 	mblk_t		*dh;
1135 	size_t		size;
1136 	t_scalar_t	type;
1137 
1138 	size = sizeof (dl_unitdata_ind_t) + (2 * SPPP_ADDRL);
1139 	if ((dh = allocb(size, BPRI_MED)) == NULL) {
1140 		freemsg(mp);
1141 		return (NULL);
1142 	}
1143 
1144 	dh->b_datap->db_type = M_PROTO;
1145 	dh->b_wptr = dh->b_datap->db_lim;
1146 	dh->b_rptr = dh->b_wptr - size;
1147 
1148 	dlu = (dl_unitdata_ind_t *)dh->b_rptr;
1149 	dlu->dl_primitive = DL_UNITDATA_IND;
1150 	dlu->dl_dest_addr_length = SPPP_ADDRL;
1151 	dlu->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
1152 	dlu->dl_src_addr_length = SPPP_ADDRL;
1153 	dlu->dl_src_addr_offset = sizeof (dl_unitdata_ind_t) + SPPP_ADDRL;
1154 	dlu->dl_group_address = 0;
1155 
1156 	if (promisc) {
1157 		if (proto == PPP_IP) {
1158 			type = ETHERTYPE_IP;
1159 		} else if (proto == PPP_IPV6) {
1160 			type = ETHERTYPE_IPV6;
1161 		} else {
1162 			/*
1163 			 * For all other protocols, send this up as an
1164 			 * ETHERTYPE_PPP type of packet. Since we've skipped
1165 			 * the PPP headers in the caller, make sure that we
1166 			 * restore it. We know for sure that the PPP header
1167 			 * still exists in the message (only skipped), since
1168 			 * the sender of this message is pppd and it must
1169 			 * have included the PPP header in front.
1170 			 */
1171 			type = ETHERTYPE_PPP;
1172 			mp->b_rptr -= PPP_HDRLEN;
1173 			ASSERT(mp->b_rptr >= mp->b_datap->db_base);
1174 		}
1175 	} else {
1176 		type = sps->sps_req_sap;
1177 	}
1178 	/*
1179 	 * Send the DLPI client the data with the SAP they requested,
1180 	 * (e.g. ETHERTYPE_IP) rather than the PPP protocol (e.g. PPP_IP).
1181 	 */
1182 	((spppreqsap_t *)(dlu + 1))[0] = type;
1183 	((spppreqsap_t *)(dlu + 1))[1] = type;
1184 
1185 	linkb(dh, mp);
1186 	return (dh);
1187 }
1188 
1189 /*
1190  * sppp_dlprsendup()
1191  *
1192  * Description:
1193  *    For any valid promiscuous streams (marked with SPS_PROMISC and its
1194  *    sps_dlstate is DL_IDLE), send data upstream. The caller is expected
1195  *    to hold ppa_sib_lock when calling this procedure.
1196  */
1197 void
1198 sppp_dlprsendup(spppstr_t *sps, mblk_t *mp, t_scalar_t proto, boolean_t header)
1199 {
1200 	sppa_t	*ppa;
1201 	mblk_t	*dmp;
1202 
1203 	ASSERT(sps != NULL);
1204 	ASSERT(mp != NULL && mp->b_rptr != NULL);
1205 	ppa = sps->sps_ppa;
1206 	ASSERT(ppa != NULL);
1207 
1208 	/* NOTE: caller must hold ppa_sib_lock in RW_READER mode */
1209 	ASSERT(RW_READ_HELD(&ppa->ppa_sib_lock));
1210 
1211 	for (; sps != NULL; sps = sps->sps_nextsib) {
1212 		/*
1213 		 * We specifically test to ensure that the DLPI state for the
1214 		 * promiscous stream is IDLE (DL_IDLE), since such state tells
1215 		 * us that the promiscous stream has been bound to PPP_ALLSAP.
1216 		 */
1217 		if (IS_SPS_PROMISC(sps) && (sps->sps_dlstate == DL_IDLE) &&
1218 		    canputnext(sps->sps_rq)) {
1219 			if ((dmp = dupmsg(mp)) == NULL) {
1220 				mutex_enter(&ppa->ppa_sta_lock);
1221 				ppa->ppa_allocbfail++;
1222 				mutex_exit(&ppa->ppa_sta_lock);
1223 				continue;
1224 			}
1225 			if (header) {
1226 				dmp->b_rptr += PPP_HDRLEN;
1227 			}
1228 			if (IS_SPS_RAWDATA(sps)) {
1229 				/* function frees original message if fails */
1230 				dmp = sppp_dladdether(sps, dmp, proto);
1231 			} else {
1232 				/* function frees original message if fails */
1233 				dmp = sppp_dladdud(sps, dmp, proto, B_TRUE);
1234 			}
1235 			if (dmp != NULL) {
1236 				putnext(sps->sps_rq, dmp);
1237 			} else {
1238 				mutex_enter(&ppa->ppa_sta_lock);
1239 				ppa->ppa_allocbfail++;
1240 				mutex_exit(&ppa->ppa_sta_lock);
1241 			}
1242 		}
1243 	}
1244 }
1245