Home | History | Annotate | Download | only in sppp
      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 (at) cs.anu.edu.au>.
     43  *
     44  * Adi Masputra <adi.masputra (at) 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(