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