xref: /onnv-gate/usr/src/uts/common/io/softmac/softmac_ctl.c (revision 9073:a5a4bb23741e)
15895Syz147064 /*
25895Syz147064  * CDDL HEADER START
35895Syz147064  *
45895Syz147064  * The contents of this file are subject to the terms of the
55895Syz147064  * Common Development and Distribution License (the "License").
65895Syz147064  * You may not use this file except in compliance with the License.
75895Syz147064  *
85895Syz147064  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95895Syz147064  * or http://www.opensolaris.org/os/licensing.
105895Syz147064  * See the License for the specific language governing permissions
115895Syz147064  * and limitations under the License.
125895Syz147064  *
135895Syz147064  * When distributing Covered Code, include this CDDL HEADER in each
145895Syz147064  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155895Syz147064  * If applicable, add the following below this CDDL HEADER, with the
165895Syz147064  * fields enclosed by brackets "[]" replaced with your own identifying
175895Syz147064  * information: Portions Copyright [yyyy] [name of copyright owner]
185895Syz147064  *
195895Syz147064  * CDDL HEADER END
205895Syz147064  */
215895Syz147064 /*
22*9073SCathy.Zhou@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235895Syz147064  * Use is subject to license terms.
245895Syz147064  */
255895Syz147064 
265895Syz147064 #include <sys/stropts.h>
278275SEric Cheng #include <sys/strsubr.h>
288275SEric Cheng #include <sys/callb.h>
295895Syz147064 #include <sys/softmac_impl.h>
305895Syz147064 
315895Syz147064 int
softmac_send_notify_req(softmac_lower_t * slp,uint32_t notifications)325895Syz147064 softmac_send_notify_req(softmac_lower_t *slp, uint32_t notifications)
335895Syz147064 {
345895Syz147064 	mblk_t		*reqmp;
355895Syz147064 
365895Syz147064 	/*
375895Syz147064 	 * create notify req message and send it down
385895Syz147064 	 */
395895Syz147064 	reqmp = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO,
405895Syz147064 	    DL_NOTIFY_REQ);
415895Syz147064 	if (reqmp == NULL)
425895Syz147064 		return (ENOMEM);
435895Syz147064 
445895Syz147064 	((dl_notify_req_t *)reqmp->b_rptr)->dl_notifications = notifications;
455895Syz147064 
465895Syz147064 	return (softmac_proto_tx(slp, reqmp, NULL));
475895Syz147064 }
485895Syz147064 
495895Syz147064 int
softmac_send_bind_req(softmac_lower_t * slp,uint_t sap)505895Syz147064 softmac_send_bind_req(softmac_lower_t *slp, uint_t sap)
515895Syz147064 {
525895Syz147064 	dl_bind_req_t	*bind;
535895Syz147064 	mblk_t		*reqmp;
545895Syz147064 
555895Syz147064 	/*
565895Syz147064 	 * create bind req message and send it down
575895Syz147064 	 */
585895Syz147064 	reqmp = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ);
595895Syz147064 	if (reqmp == NULL)
605895Syz147064 		return (ENOMEM);
615895Syz147064 
625895Syz147064 	bind = (dl_bind_req_t *)reqmp->b_rptr;
635895Syz147064 	bind->dl_sap = sap;
645895Syz147064 	bind->dl_conn_mgmt = 0;
655895Syz147064 	bind->dl_max_conind = 0;
665895Syz147064 	bind->dl_xidtest_flg = 0;
675895Syz147064 	bind->dl_service_mode = DL_CLDLS;
685895Syz147064 
695895Syz147064 	return (softmac_proto_tx(slp, reqmp, NULL));
705895Syz147064 }
715895Syz147064 
725895Syz147064 int
softmac_send_unbind_req(softmac_lower_t * slp)73*9073SCathy.Zhou@Sun.COM softmac_send_unbind_req(softmac_lower_t *slp)
74*9073SCathy.Zhou@Sun.COM {
75*9073SCathy.Zhou@Sun.COM 	mblk_t			*reqmp;
76*9073SCathy.Zhou@Sun.COM 
77*9073SCathy.Zhou@Sun.COM 	/*
78*9073SCathy.Zhou@Sun.COM 	 * create unbind req message and send it down
79*9073SCathy.Zhou@Sun.COM 	 */
80*9073SCathy.Zhou@Sun.COM 	reqmp = mexchange(NULL, NULL, DL_UNBIND_REQ_SIZE, M_PROTO,
81*9073SCathy.Zhou@Sun.COM 	    DL_UNBIND_REQ);
82*9073SCathy.Zhou@Sun.COM 	if (reqmp == NULL)
83*9073SCathy.Zhou@Sun.COM 		return (ENOMEM);
84*9073SCathy.Zhou@Sun.COM 
85*9073SCathy.Zhou@Sun.COM 	return (softmac_proto_tx(slp, reqmp, NULL));
86*9073SCathy.Zhou@Sun.COM }
87*9073SCathy.Zhou@Sun.COM 
88*9073SCathy.Zhou@Sun.COM int
softmac_send_promisc_req(softmac_lower_t * slp,t_uscalar_t level,boolean_t on)895895Syz147064 softmac_send_promisc_req(softmac_lower_t *slp, t_uscalar_t level, boolean_t on)
905895Syz147064 {
915895Syz147064 	mblk_t		*reqmp;
925895Syz147064 	size_t		size;
935895Syz147064 	t_uscalar_t	dl_prim;
945895Syz147064 
955895Syz147064 	/*
965895Syz147064 	 * create promisc message and send it down
975895Syz147064 	 */
985895Syz147064 	if (on) {
995895Syz147064 		dl_prim = DL_PROMISCON_REQ;
1005895Syz147064 		size = DL_PROMISCON_REQ_SIZE;
1015895Syz147064 	} else {
1025895Syz147064 		dl_prim = DL_PROMISCOFF_REQ;
1035895Syz147064 		size = DL_PROMISCOFF_REQ_SIZE;
1045895Syz147064 	}
1055895Syz147064 
1065895Syz147064 	reqmp = mexchange(NULL, NULL, size, M_PROTO, dl_prim);
1075895Syz147064 	if (reqmp == NULL)
1085895Syz147064 		return (ENOMEM);
1095895Syz147064 
1105895Syz147064 	if (on)
1115895Syz147064 		((dl_promiscon_req_t *)reqmp->b_rptr)->dl_level = level;
1125895Syz147064 	else
1135895Syz147064 		((dl_promiscoff_req_t *)reqmp->b_rptr)->dl_level = level;
1145895Syz147064 
1155895Syz147064 	return (softmac_proto_tx(slp, reqmp, NULL));
1165895Syz147064 }
1175895Syz147064 
1185895Syz147064 int
softmac_m_promisc(void * arg,boolean_t on)1195895Syz147064 softmac_m_promisc(void *arg, boolean_t on)
1205895Syz147064 {
1215895Syz147064 	softmac_t		*softmac = arg;
1225895Syz147064 	softmac_lower_t		*slp = softmac->smac_lower;
1235895Syz147064 
124*9073SCathy.Zhou@Sun.COM 	ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
1255895Syz147064 	ASSERT(slp != NULL);
1265895Syz147064 	return (softmac_send_promisc_req(slp, DL_PROMISC_PHYS, on));
1275895Syz147064 }
1285895Syz147064 
1295895Syz147064 int
softmac_m_multicst(void * arg,boolean_t add,const uint8_t * mca)1305895Syz147064 softmac_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
1315895Syz147064 {
1325895Syz147064 	softmac_t		*softmac = arg;
1335895Syz147064 	softmac_lower_t		*slp;
1345895Syz147064 	dl_enabmulti_req_t	*enabmulti;
1355895Syz147064 	dl_disabmulti_req_t	*disabmulti;
1365895Syz147064 	mblk_t			*reqmp;
1375895Syz147064 	t_uscalar_t		dl_prim;
1385895Syz147064 	uint32_t		size, addr_length;
1395895Syz147064 
140*9073SCathy.Zhou@Sun.COM 	ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
1415895Syz147064 	/*
1425895Syz147064 	 * create multicst message and send it down
1435895Syz147064 	 */
1445895Syz147064 	addr_length = softmac->smac_addrlen;
1455895Syz147064 	if (add) {
1465895Syz147064 		size = sizeof (dl_enabmulti_req_t) + addr_length;
1475895Syz147064 		dl_prim = DL_ENABMULTI_REQ;
1485895Syz147064 	} else {
1495895Syz147064 		size = sizeof (dl_disabmulti_req_t) + addr_length;
1505895Syz147064 		dl_prim = DL_DISABMULTI_REQ;
1515895Syz147064 	}
1525895Syz147064 
1535895Syz147064 	reqmp = mexchange(NULL, NULL, size, M_PROTO, dl_prim);
1545895Syz147064 	if (reqmp == NULL)
1555895Syz147064 		return (ENOMEM);
1565895Syz147064 
1575895Syz147064 	if (add) {
1585895Syz147064 		enabmulti = (dl_enabmulti_req_t *)reqmp->b_rptr;
1595895Syz147064 		enabmulti->dl_addr_offset = sizeof (dl_enabmulti_req_t);
1605895Syz147064 		enabmulti->dl_addr_length = addr_length;
1615895Syz147064 		(void) memcpy(&enabmulti[1], mca, addr_length);
1625895Syz147064 	} else {
1635895Syz147064 		disabmulti = (dl_disabmulti_req_t *)reqmp->b_rptr;
1645895Syz147064 		disabmulti->dl_addr_offset = sizeof (dl_disabmulti_req_t);
1655895Syz147064 		disabmulti->dl_addr_length = addr_length;
1665895Syz147064 		(void) memcpy(&disabmulti[1], mca, addr_length);
1675895Syz147064 	}
1685895Syz147064 
1695895Syz147064 	slp = softmac->smac_lower;
1705895Syz147064 	ASSERT(slp != NULL);
1715895Syz147064 	return (softmac_proto_tx(slp, reqmp, NULL));
1725895Syz147064 }
1735895Syz147064 
1745895Syz147064 int
softmac_m_unicst(void * arg,const uint8_t * macaddr)1755895Syz147064 softmac_m_unicst(void *arg, const uint8_t *macaddr)
1765895Syz147064 {
1775895Syz147064 	softmac_t		*softmac = arg;
1785895Syz147064 	softmac_lower_t		*slp;
1795895Syz147064 	dl_set_phys_addr_req_t	*phyaddr;
1805895Syz147064 	mblk_t			*reqmp;
1815895Syz147064 	size_t			size;
1825895Syz147064 
183*9073SCathy.Zhou@Sun.COM 	ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
1845895Syz147064 	/*
1855895Syz147064 	 * create set_phys_addr message and send it down
1865895Syz147064 	 */
1875895Syz147064 	size = DL_SET_PHYS_ADDR_REQ_SIZE + softmac->smac_addrlen;
1885895Syz147064 	reqmp = mexchange(NULL, NULL, size, M_PROTO, DL_SET_PHYS_ADDR_REQ);
1895895Syz147064 	if (reqmp == NULL)
1905895Syz147064 		return (ENOMEM);
1915895Syz147064 
1925895Syz147064 	phyaddr = (dl_set_phys_addr_req_t *)reqmp->b_rptr;
1935895Syz147064 	phyaddr->dl_addr_offset = sizeof (dl_set_phys_addr_req_t);
1945895Syz147064 	phyaddr->dl_addr_length = softmac->smac_addrlen;
1955895Syz147064 	(void) memcpy(&phyaddr[1], macaddr, softmac->smac_addrlen);
1965895Syz147064 
1975895Syz147064 	slp = softmac->smac_lower;
1985895Syz147064 	ASSERT(slp != NULL);
1995895Syz147064 	return (softmac_proto_tx(slp, reqmp, NULL));
2005895Syz147064 }
2015895Syz147064 
2025895Syz147064 void
softmac_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)2035895Syz147064 softmac_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
2045895Syz147064 {
2055895Syz147064 	softmac_lower_t *slp = ((softmac_t *)arg)->smac_lower;
2065895Syz147064 	mblk_t *ackmp;
2075895Syz147064 
2085895Syz147064 	ASSERT(slp != NULL);
2095895Syz147064 	softmac_ioctl_tx(slp, mp, &ackmp);
2105895Syz147064 	qreply(wq, ackmp);
2115895Syz147064 }
2125895Syz147064 
2135895Syz147064 static void
softmac_process_notify_ind(softmac_t * softmac,mblk_t * mp)2148275SEric Cheng softmac_process_notify_ind(softmac_t *softmac, mblk_t *mp)
2155895Syz147064 {
2165895Syz147064 	dl_notify_ind_t	*dlnip = (dl_notify_ind_t *)mp->b_rptr;
2175895Syz147064 	uint_t		addroff, addrlen;
2185895Syz147064 
2195895Syz147064 	ASSERT(dlnip->dl_primitive == DL_NOTIFY_IND);
2205895Syz147064 
2215895Syz147064 	switch (dlnip->dl_notification) {
2225895Syz147064 	case DL_NOTE_PHYS_ADDR:
2235895Syz147064 		if (dlnip->dl_data != DL_CURR_PHYS_ADDR)
2245895Syz147064 			break;
2255895Syz147064 
2265895Syz147064 		addroff = dlnip->dl_addr_offset;
2275895Syz147064 		addrlen = dlnip->dl_addr_length - softmac->smac_saplen;
2285895Syz147064 		if (addroff == 0 || addrlen != softmac->smac_addrlen ||
2295895Syz147064 		    !MBLKIN(mp, addroff, addrlen)) {
2305895Syz147064 			cmn_err(CE_NOTE, "softmac: got malformed "
2315895Syz147064 			    "DL_NOTIFY_IND; length/offset %d/%d",
2325895Syz147064 			    addrlen, addroff);
2335895Syz147064 			break;
2345895Syz147064 		}
2355895Syz147064 
2365895Syz147064 		mac_unicst_update(softmac->smac_mh, mp->b_rptr + addroff);
2375895Syz147064 		break;
2385895Syz147064 
2395895Syz147064 	case DL_NOTE_LINK_UP:
2405895Syz147064 		mac_link_update(softmac->smac_mh, LINK_STATE_UP);
2415895Syz147064 		break;
2425895Syz147064 
2435895Syz147064 	case DL_NOTE_LINK_DOWN:
2445895Syz147064 		mac_link_update(softmac->smac_mh, LINK_STATE_DOWN);
2455895Syz147064 		break;
2465895Syz147064 	}
2475895Syz147064 
2485895Syz147064 	freemsg(mp);
2495895Syz147064 }
2505895Syz147064 
2518275SEric Cheng void
softmac_notify_thread(void * arg)2528275SEric Cheng softmac_notify_thread(void *arg)
2538275SEric Cheng {
2548275SEric Cheng 	softmac_t	*softmac = arg;
2558275SEric Cheng 	callb_cpr_t	cprinfo;
2568275SEric Cheng 
2578275SEric Cheng 	CALLB_CPR_INIT(&cprinfo, &softmac->smac_mutex, callb_generic_cpr,
2588275SEric Cheng 	    "softmac_notify_thread");
2598275SEric Cheng 
2608275SEric Cheng 	mutex_enter(&softmac->smac_mutex);
2618275SEric Cheng 
2628275SEric Cheng 	/*
2638275SEric Cheng 	 * Quit the thread if smac_mh is unregistered.
2648275SEric Cheng 	 */
2658275SEric Cheng 	while (softmac->smac_mh != NULL &&
2668275SEric Cheng 	    !(softmac->smac_flags & SOFTMAC_NOTIFY_QUIT)) {
2678275SEric Cheng 		mblk_t		*mp, *nextmp;
2688275SEric Cheng 
2698275SEric Cheng 		if ((mp = softmac->smac_notify_head) == NULL) {
2708275SEric Cheng 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
2718275SEric Cheng 			cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
2728275SEric Cheng 			CALLB_CPR_SAFE_END(&cprinfo, &softmac->smac_mutex);
2738275SEric Cheng 			continue;
2748275SEric Cheng 		}
2758275SEric Cheng 
2768275SEric Cheng 		softmac->smac_notify_head = softmac->smac_notify_tail = NULL;
2778275SEric Cheng 		mutex_exit(&softmac->smac_mutex);
2788275SEric Cheng 
2798275SEric Cheng 		while (mp != NULL) {
2808275SEric Cheng 			nextmp = mp->b_next;
2818275SEric Cheng 			mp->b_next = NULL;
2828275SEric Cheng 			softmac_process_notify_ind(softmac, mp);
2838275SEric Cheng 			mp = nextmp;
2848275SEric Cheng 		}
2858275SEric Cheng 		mutex_enter(&softmac->smac_mutex);
2868275SEric Cheng 	}
2878275SEric Cheng 
2888275SEric Cheng 	/*
2898275SEric Cheng 	 * The softmac is being destroyed, simply free all of the DL_NOTIFY_IND
2908275SEric Cheng 	 * messages left in the queue which did not have the chance to be
2918275SEric Cheng 	 * processed.
2928275SEric Cheng 	 */
2938275SEric Cheng 	freemsgchain(softmac->smac_notify_head);
2948275SEric Cheng 	softmac->smac_notify_head = softmac->smac_notify_tail = NULL;
2958275SEric Cheng 	softmac->smac_notify_thread = NULL;
2968275SEric Cheng 	cv_broadcast(&softmac->smac_cv);
2978275SEric Cheng 	CALLB_CPR_EXIT(&cprinfo);
2988275SEric Cheng 	thread_exit();
2998275SEric Cheng }
3008275SEric Cheng 
3018275SEric Cheng static void
softmac_enqueue_notify_ind(queue_t * rq,mblk_t * mp)3028275SEric Cheng softmac_enqueue_notify_ind(queue_t *rq, mblk_t *mp)
3038275SEric Cheng {
3048275SEric Cheng 	softmac_lower_t	*slp = rq->q_ptr;
3058275SEric Cheng 	softmac_t	*softmac = slp->sl_softmac;
3068275SEric Cheng 
3078275SEric Cheng 	mutex_enter(&softmac->smac_mutex);
3088275SEric Cheng 	if (softmac->smac_notify_tail == NULL) {
3098275SEric Cheng 		softmac->smac_notify_head = softmac->smac_notify_tail = mp;
3108275SEric Cheng 	} else {
3118275SEric Cheng 		softmac->smac_notify_tail->b_next = mp;
3128275SEric Cheng 		softmac->smac_notify_tail = mp;
3138275SEric Cheng 	}
3148275SEric Cheng 	cv_broadcast(&softmac->smac_cv);
3158275SEric Cheng 	mutex_exit(&softmac->smac_mutex);
3168275SEric Cheng }
3178275SEric Cheng 
3185895Syz147064 static void
softmac_process_dlpi(softmac_lower_t * slp,mblk_t * mp,uint_t minlen,t_uscalar_t reqprim)3195895Syz147064 softmac_process_dlpi(softmac_lower_t *slp, mblk_t *mp, uint_t minlen,
3205895Syz147064     t_uscalar_t reqprim)
3215895Syz147064 {
3225895Syz147064 	const char *ackname;
3235895Syz147064 
3245895Syz147064 	ackname = dl_primstr(((union DL_primitives *)mp->b_rptr)->dl_primitive);
3255895Syz147064 
3265895Syz147064 	if (MBLKL(mp) < minlen) {
3275895Syz147064 		cmn_err(CE_WARN, "softmac: got short %s", ackname);
3285895Syz147064 		freemsg(mp);
3295895Syz147064 		return;
3305895Syz147064 	}
3315895Syz147064 
3325895Syz147064 	mutex_enter(&slp->sl_mutex);
3335895Syz147064 	if (slp->sl_pending_prim != reqprim) {
3345895Syz147064 		cmn_err(CE_NOTE, "softmac: got unexpected %s", ackname);
3355895Syz147064 		mutex_exit(&slp->sl_mutex);
3365895Syz147064 		freemsg(mp);
3375895Syz147064 		return;
3385895Syz147064 	}
3395895Syz147064 
3405895Syz147064 	slp->sl_pending_prim = DL_PRIM_INVAL;
3415895Syz147064 	slp->sl_ack_mp = mp;
3425895Syz147064 	cv_signal(&slp->sl_cv);
3435895Syz147064 	mutex_exit(&slp->sl_mutex);
3445895Syz147064 }
3455895Syz147064 
3465895Syz147064 void
softmac_rput_process_proto(queue_t * rq,mblk_t * mp)3475895Syz147064 softmac_rput_process_proto(queue_t *rq, mblk_t *mp)
3485895Syz147064 {
3495895Syz147064 	softmac_lower_t		*slp = rq->q_ptr;
3505895Syz147064 	union DL_primitives	*dlp = (union DL_primitives *)mp->b_rptr;
3515895Syz147064 	ssize_t			len = MBLKL(mp);
3525895Syz147064 	const char		*primstr;
3535895Syz147064 
3545895Syz147064 	if (len < sizeof (t_uscalar_t)) {
3555895Syz147064 		cmn_err(CE_WARN, "softmac: got runt DLPI message");
3565895Syz147064 		goto exit;
3575895Syz147064 	}
3585895Syz147064 
3595895Syz147064 	primstr = dl_primstr(dlp->dl_primitive);
3605895Syz147064 
3615895Syz147064 	switch (dlp->dl_primitive) {
3625895Syz147064 	case DL_OK_ACK:
3635895Syz147064 		if (len < DL_OK_ACK_SIZE)
3645895Syz147064 			goto runt;
3655895Syz147064 
3665895Syz147064 		softmac_process_dlpi(slp, mp, DL_OK_ACK_SIZE,
3675895Syz147064 		    dlp->ok_ack.dl_correct_primitive);
3685895Syz147064 		return;
3695895Syz147064 
3705895Syz147064 	case DL_ERROR_ACK:
3715895Syz147064 		if (len < DL_ERROR_ACK_SIZE)
3725895Syz147064 			goto runt;
3735895Syz147064 
3745895Syz147064 		softmac_process_dlpi(slp, mp, DL_ERROR_ACK_SIZE,
3755895Syz147064 		    dlp->error_ack.dl_error_primitive);
3765895Syz147064 		return;
3775895Syz147064 
3785895Syz147064 	case DL_NOTIFY_IND:
3795895Syz147064 		if (len < DL_NOTIFY_IND_SIZE)
3805895Syz147064 			goto runt;
3815895Syz147064 
3828275SEric Cheng 		/*
3838275SEric Cheng 		 * Enqueue all the DL_NOTIFY_IND messages and process them
3848275SEric Cheng 		 * in another separate thread to avoid deadlock. Here is an
3858275SEric Cheng 		 * example of the deadlock scenario:
3868275SEric Cheng 		 *
3878275SEric Cheng 		 * Thread A: mac_promisc_set()->softmac_m_promisc()
3888275SEric Cheng 		 *
3898275SEric Cheng 		 *   The softmac driver waits for the ACK of the
3908275SEric Cheng 		 *   DL_PROMISC_PHYS request with the MAC perimeter;
3918275SEric Cheng 		 *
3928275SEric Cheng 		 * Thread B:
3938275SEric Cheng 		 *
3948275SEric Cheng 		 *   The driver handles the DL_PROMISC_PHYS request. Before
3958275SEric Cheng 		 *   it sends back the ACK, it could first send a
3968275SEric Cheng 		 *   DL_NOTE_PROMISC_ON_PHYS notification.
3978275SEric Cheng 		 *
3988275SEric Cheng 		 * Since DL_NOTIFY_IND could eventually cause softmac to call
3998275SEric Cheng 		 * mac_xxx_update(), which requires MAC perimeter, this would
4008275SEric Cheng 		 * cause deadlock between the two threads. Enqueuing the
4018275SEric Cheng 		 * DL_NOTIFY_IND message and defer its processing would
4028275SEric Cheng 		 * avoid the potential deadlock.
4038275SEric Cheng 		 */
4048275SEric Cheng 		softmac_enqueue_notify_ind(rq, mp);
4055895Syz147064 		return;
4065895Syz147064 
4075895Syz147064 	case DL_NOTIFY_ACK:
4085895Syz147064 		softmac_process_dlpi(slp, mp, DL_NOTIFY_ACK_SIZE,
4095895Syz147064 		    DL_NOTIFY_REQ);
4105895Syz147064 		return;
4115895Syz147064 
4125895Syz147064 	case DL_CAPABILITY_ACK:
4135895Syz147064 		softmac_process_dlpi(slp, mp, DL_CAPABILITY_ACK_SIZE,
4145895Syz147064 		    DL_CAPABILITY_REQ);
4155895Syz147064 		return;
4165895Syz147064 
4175895Syz147064 	case DL_BIND_ACK:
4185895Syz147064 		softmac_process_dlpi(slp, mp, DL_BIND_ACK_SIZE, DL_BIND_REQ);
4195895Syz147064 		return;
4205895Syz147064 
4215895Syz147064 	case DL_CONTROL_ACK:
4225895Syz147064 		softmac_process_dlpi(slp, mp, DL_CONTROL_ACK_SIZE,
4235895Syz147064 		    DL_CONTROL_REQ);
4245895Syz147064 		return;
4255895Syz147064 
4265895Syz147064 	case DL_UNITDATA_IND:
4275895Syz147064 	case DL_PHYS_ADDR_ACK:
4285895Syz147064 		/*
4295895Syz147064 		 * a. Because the stream is in DLIOCRAW mode,
4305895Syz147064 		 *    DL_UNITDATA_IND messages are not expected.
4315895Syz147064 		 * b. The lower stream should not receive DL_PHYS_ADDR_REQ,
4325895Syz147064 		 *    so DL_PHYS_ADDR_ACK messages are also unexpected.
4335895Syz147064 		 */
4345895Syz147064 	default:
4355895Syz147064 		cmn_err(CE_WARN, "softmac: got unexpected %s", primstr);
4365895Syz147064 		break;
4375895Syz147064 	}
4385895Syz147064 exit:
4395895Syz147064 	freemsg(mp);
4405895Syz147064 	return;
4415895Syz147064 runt:
4425895Syz147064 	cmn_err(CE_WARN, "softmac: got runt %s", primstr);
4435895Syz147064 	freemsg(mp);
4445895Syz147064 }
4455895Syz147064 
4465895Syz147064 void
softmac_rput_process_notdata(queue_t * rq,softmac_upper_t * sup,mblk_t * mp)447*9073SCathy.Zhou@Sun.COM softmac_rput_process_notdata(queue_t *rq, softmac_upper_t *sup, mblk_t *mp)
4485895Syz147064 {
449*9073SCathy.Zhou@Sun.COM 	softmac_lower_t		*slp = rq->q_ptr;
450*9073SCathy.Zhou@Sun.COM 	union DL_primitives	*dlp;
451*9073SCathy.Zhou@Sun.COM 	ssize_t			len = MBLKL(mp);
4525895Syz147064 
4535895Syz147064 	switch (DB_TYPE(mp)) {
4545895Syz147064 	case M_PROTO:
4555895Syz147064 	case M_PCPROTO:
456*9073SCathy.Zhou@Sun.COM 		/*
457*9073SCathy.Zhou@Sun.COM 		 * If this is a shared-lower-stream, pass it to softmac to
458*9073SCathy.Zhou@Sun.COM 		 * process.
459*9073SCathy.Zhou@Sun.COM 		 */
460*9073SCathy.Zhou@Sun.COM 		if (sup == NULL) {
461*9073SCathy.Zhou@Sun.COM 			softmac_rput_process_proto(rq, mp);
462*9073SCathy.Zhou@Sun.COM 			break;
463*9073SCathy.Zhou@Sun.COM 		}
464*9073SCathy.Zhou@Sun.COM 
465*9073SCathy.Zhou@Sun.COM 		/*
466*9073SCathy.Zhou@Sun.COM 		 * Dedicated-lower-stream.
467*9073SCathy.Zhou@Sun.COM 		 */
468*9073SCathy.Zhou@Sun.COM 		dlp = (union DL_primitives *)mp->b_rptr;
469*9073SCathy.Zhou@Sun.COM 		ASSERT(len >= sizeof (dlp->dl_primitive));
470*9073SCathy.Zhou@Sun.COM 		switch (dlp->dl_primitive) {
471*9073SCathy.Zhou@Sun.COM 		case DL_OK_ACK:
472*9073SCathy.Zhou@Sun.COM 			if (len < DL_OK_ACK_SIZE)
473*9073SCathy.Zhou@Sun.COM 				goto runt;
474*9073SCathy.Zhou@Sun.COM 
475*9073SCathy.Zhou@Sun.COM 			/*
476*9073SCathy.Zhou@Sun.COM 			 * If this is a DL_OK_ACK for a DL_UNBIND_REQ, pass it
477*9073SCathy.Zhou@Sun.COM 			 * to softmac to process, otherwise directly pass it to
478*9073SCathy.Zhou@Sun.COM 			 * the upper stream.
479*9073SCathy.Zhou@Sun.COM 			 */
480*9073SCathy.Zhou@Sun.COM 			if (dlp->ok_ack.dl_correct_primitive == DL_UNBIND_REQ) {
481*9073SCathy.Zhou@Sun.COM 				softmac_rput_process_proto(rq, mp);
482*9073SCathy.Zhou@Sun.COM 				break;
483*9073SCathy.Zhou@Sun.COM 			}
484*9073SCathy.Zhou@Sun.COM 
485*9073SCathy.Zhou@Sun.COM 			putnext(sup->su_rq, mp);
486*9073SCathy.Zhou@Sun.COM 			break;
487*9073SCathy.Zhou@Sun.COM 		case DL_ERROR_ACK:
488*9073SCathy.Zhou@Sun.COM 			if (len < DL_ERROR_ACK_SIZE)
489*9073SCathy.Zhou@Sun.COM 				goto runt;
490*9073SCathy.Zhou@Sun.COM 
491*9073SCathy.Zhou@Sun.COM 			/*
492*9073SCathy.Zhou@Sun.COM 			 * If this is a DL_ERROR_ACK for a DL_UNBIND_REQ, pass
493*9073SCathy.Zhou@Sun.COM 			 * it to softmac to process, otherwise directly pass it
494*9073SCathy.Zhou@Sun.COM 			 * to the upper stream.
495*9073SCathy.Zhou@Sun.COM 			 */
496*9073SCathy.Zhou@Sun.COM 			if (dlp->error_ack.dl_error_primitive ==
497*9073SCathy.Zhou@Sun.COM 			    DL_UNBIND_REQ) {
498*9073SCathy.Zhou@Sun.COM 				softmac_rput_process_proto(rq, mp);
499*9073SCathy.Zhou@Sun.COM 				break;
500*9073SCathy.Zhou@Sun.COM 			}
501*9073SCathy.Zhou@Sun.COM 
502*9073SCathy.Zhou@Sun.COM 			putnext(sup->su_rq, mp);
503*9073SCathy.Zhou@Sun.COM 			break;
504*9073SCathy.Zhou@Sun.COM 		case DL_BIND_ACK:
505*9073SCathy.Zhou@Sun.COM 		case DL_CAPABILITY_ACK:
506*9073SCathy.Zhou@Sun.COM 			softmac_rput_process_proto(rq, mp);
507*9073SCathy.Zhou@Sun.COM 			break;
508*9073SCathy.Zhou@Sun.COM 		default:
509*9073SCathy.Zhou@Sun.COM 			putnext(sup->su_rq, mp);
510*9073SCathy.Zhou@Sun.COM 			break;
511*9073SCathy.Zhou@Sun.COM 		}
5125895Syz147064 		break;
5135895Syz147064 	case M_FLUSH:
5145895Syz147064 		if (*mp->b_rptr & FLUSHR)
5155895Syz147064 			flushq(rq, FLUSHDATA);
5165895Syz147064 		if (*mp->b_rptr & FLUSHW)
5175895Syz147064 			flushq(OTHERQ(rq), FLUSHDATA);
5185895Syz147064 		putnext(rq, mp);
5195895Syz147064 		break;
5205895Syz147064 
5215895Syz147064 	case M_IOCACK:
5225895Syz147064 	case M_IOCNAK:
5235895Syz147064 	case M_COPYIN:
5245895Syz147064 	case M_COPYOUT:
525*9073SCathy.Zhou@Sun.COM 		if (sup != NULL) {
526*9073SCathy.Zhou@Sun.COM 			putnext(sup->su_rq, mp);
527*9073SCathy.Zhou@Sun.COM 			break;
528*9073SCathy.Zhou@Sun.COM 		}
529*9073SCathy.Zhou@Sun.COM 
5305895Syz147064 		mutex_enter(&slp->sl_mutex);
5315895Syz147064 		if (!slp->sl_pending_ioctl) {
5325895Syz147064 			mutex_exit(&slp->sl_mutex);
5335895Syz147064 			cmn_err(CE_NOTE, "softmac: got unexpected mblk "
5345895Syz147064 			    "type 0x%x", DB_TYPE(mp));
5355895Syz147064 			freemsg(mp);
5365895Syz147064 			break;
5375895Syz147064 		}
5385895Syz147064 
5395895Syz147064 		slp->sl_pending_ioctl = B_FALSE;
5405895Syz147064 		slp->sl_ack_mp = mp;
5415895Syz147064 		cv_broadcast(&slp->sl_cv);
5425895Syz147064 		mutex_exit(&slp->sl_mutex);
543*9073SCathy.Zhou@Sun.COM 		break;
5445895Syz147064 
5455895Syz147064 	default:
5465895Syz147064 		cmn_err(CE_NOTE, "softmac: got unsupported mblk type 0x%x",
5475895Syz147064 		    DB_TYPE(mp));
5485895Syz147064 		freemsg(mp);
5495895Syz147064 		break;
5505895Syz147064 	}
551*9073SCathy.Zhou@Sun.COM 	return;
552*9073SCathy.Zhou@Sun.COM runt:
553*9073SCathy.Zhou@Sun.COM 	cmn_err(CE_WARN, "softmac: got runt %s", dl_primstr(dlp->dl_primitive));
554*9073SCathy.Zhou@Sun.COM 	freemsg(mp);
5555895Syz147064 }
556