1d62bc4baSyz147064 /* 2d62bc4baSyz147064 * CDDL HEADER START 3d62bc4baSyz147064 * 4d62bc4baSyz147064 * The contents of this file are subject to the terms of the 5d62bc4baSyz147064 * Common Development and Distribution License (the "License"). 6d62bc4baSyz147064 * You may not use this file except in compliance with the License. 7d62bc4baSyz147064 * 8d62bc4baSyz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d62bc4baSyz147064 * or http://www.opensolaris.org/os/licensing. 10d62bc4baSyz147064 * See the License for the specific language governing permissions 11d62bc4baSyz147064 * and limitations under the License. 12d62bc4baSyz147064 * 13d62bc4baSyz147064 * When distributing Covered Code, include this CDDL HEADER in each 14d62bc4baSyz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d62bc4baSyz147064 * If applicable, add the following below this CDDL HEADER, with the 16d62bc4baSyz147064 * fields enclosed by brackets "[]" replaced with your own identifying 17d62bc4baSyz147064 * information: Portions Copyright [yyyy] [name of copyright owner] 18d62bc4baSyz147064 * 19d62bc4baSyz147064 * CDDL HEADER END 20d62bc4baSyz147064 */ 21d62bc4baSyz147064 /* 22*5d460eafSCathy Zhou * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23d62bc4baSyz147064 * Use is subject to license terms. 24d62bc4baSyz147064 */ 25d62bc4baSyz147064 26d62bc4baSyz147064 #include <sys/stropts.h> 27da14cebeSEric Cheng #include <sys/strsubr.h> 28da14cebeSEric Cheng #include <sys/callb.h> 29d62bc4baSyz147064 #include <sys/softmac_impl.h> 30d62bc4baSyz147064 31d62bc4baSyz147064 int 32d62bc4baSyz147064 softmac_send_notify_req(softmac_lower_t *slp, uint32_t notifications) 33d62bc4baSyz147064 { 34d62bc4baSyz147064 mblk_t *reqmp; 35d62bc4baSyz147064 36d62bc4baSyz147064 /* 37d62bc4baSyz147064 * create notify req message and send it down 38d62bc4baSyz147064 */ 39d62bc4baSyz147064 reqmp = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO, 40d62bc4baSyz147064 DL_NOTIFY_REQ); 41d62bc4baSyz147064 if (reqmp == NULL) 42d62bc4baSyz147064 return (ENOMEM); 43d62bc4baSyz147064 44d62bc4baSyz147064 ((dl_notify_req_t *)reqmp->b_rptr)->dl_notifications = notifications; 45d62bc4baSyz147064 46d62bc4baSyz147064 return (softmac_proto_tx(slp, reqmp, NULL)); 47d62bc4baSyz147064 } 48d62bc4baSyz147064 49d62bc4baSyz147064 int 50d62bc4baSyz147064 softmac_send_bind_req(softmac_lower_t *slp, uint_t sap) 51d62bc4baSyz147064 { 52d62bc4baSyz147064 dl_bind_req_t *bind; 53d62bc4baSyz147064 mblk_t *reqmp; 54d62bc4baSyz147064 55d62bc4baSyz147064 /* 56d62bc4baSyz147064 * create bind req message and send it down 57d62bc4baSyz147064 */ 58d62bc4baSyz147064 reqmp = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ); 59d62bc4baSyz147064 if (reqmp == NULL) 60d62bc4baSyz147064 return (ENOMEM); 61d62bc4baSyz147064 62d62bc4baSyz147064 bind = (dl_bind_req_t *)reqmp->b_rptr; 63d62bc4baSyz147064 bind->dl_sap = sap; 64d62bc4baSyz147064 bind->dl_conn_mgmt = 0; 65d62bc4baSyz147064 bind->dl_max_conind = 0; 66d62bc4baSyz147064 bind->dl_xidtest_flg = 0; 67d62bc4baSyz147064 bind->dl_service_mode = DL_CLDLS; 68d62bc4baSyz147064 69d62bc4baSyz147064 return (softmac_proto_tx(slp, reqmp, NULL)); 70d62bc4baSyz147064 } 71d62bc4baSyz147064 72d62bc4baSyz147064 int 73*5d460eafSCathy Zhou softmac_send_unbind_req(softmac_lower_t *slp) 74*5d460eafSCathy Zhou { 75*5d460eafSCathy Zhou mblk_t *reqmp; 76*5d460eafSCathy Zhou 77*5d460eafSCathy Zhou /* 78*5d460eafSCathy Zhou * create unbind req message and send it down 79*5d460eafSCathy Zhou */ 80*5d460eafSCathy Zhou reqmp = mexchange(NULL, NULL, DL_UNBIND_REQ_SIZE, M_PROTO, 81*5d460eafSCathy Zhou DL_UNBIND_REQ); 82*5d460eafSCathy Zhou if (reqmp == NULL) 83*5d460eafSCathy Zhou return (ENOMEM); 84*5d460eafSCathy Zhou 85*5d460eafSCathy Zhou return (softmac_proto_tx(slp, reqmp, NULL)); 86*5d460eafSCathy Zhou } 87*5d460eafSCathy Zhou 88*5d460eafSCathy Zhou int 89d62bc4baSyz147064 softmac_send_promisc_req(softmac_lower_t *slp, t_uscalar_t level, boolean_t on) 90d62bc4baSyz147064 { 91d62bc4baSyz147064 mblk_t *reqmp; 92d62bc4baSyz147064 size_t size; 93d62bc4baSyz147064 t_uscalar_t dl_prim; 94d62bc4baSyz147064 95d62bc4baSyz147064 /* 96d62bc4baSyz147064 * create promisc message and send it down 97d62bc4baSyz147064 */ 98d62bc4baSyz147064 if (on) { 99d62bc4baSyz147064 dl_prim = DL_PROMISCON_REQ; 100d62bc4baSyz147064 size = DL_PROMISCON_REQ_SIZE; 101d62bc4baSyz147064 } else { 102d62bc4baSyz147064 dl_prim = DL_PROMISCOFF_REQ; 103d62bc4baSyz147064 size = DL_PROMISCOFF_REQ_SIZE; 104d62bc4baSyz147064 } 105d62bc4baSyz147064 106d62bc4baSyz147064 reqmp = mexchange(NULL, NULL, size, M_PROTO, dl_prim); 107d62bc4baSyz147064 if (reqmp == NULL) 108d62bc4baSyz147064 return (ENOMEM); 109d62bc4baSyz147064 110d62bc4baSyz147064 if (on) 111d62bc4baSyz147064 ((dl_promiscon_req_t *)reqmp->b_rptr)->dl_level = level; 112d62bc4baSyz147064 else 113d62bc4baSyz147064 ((dl_promiscoff_req_t *)reqmp->b_rptr)->dl_level = level; 114d62bc4baSyz147064 115d62bc4baSyz147064 return (softmac_proto_tx(slp, reqmp, NULL)); 116d62bc4baSyz147064 } 117d62bc4baSyz147064 118d62bc4baSyz147064 int 119d62bc4baSyz147064 softmac_m_promisc(void *arg, boolean_t on) 120d62bc4baSyz147064 { 121d62bc4baSyz147064 softmac_t *softmac = arg; 122d62bc4baSyz147064 softmac_lower_t *slp = softmac->smac_lower; 123d62bc4baSyz147064 124*5d460eafSCathy Zhou ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 125d62bc4baSyz147064 ASSERT(slp != NULL); 126d62bc4baSyz147064 return (softmac_send_promisc_req(slp, DL_PROMISC_PHYS, on)); 127d62bc4baSyz147064 } 128d62bc4baSyz147064 129d62bc4baSyz147064 int 130d62bc4baSyz147064 softmac_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 131d62bc4baSyz147064 { 132d62bc4baSyz147064 softmac_t *softmac = arg; 133d62bc4baSyz147064 softmac_lower_t *slp; 134d62bc4baSyz147064 dl_enabmulti_req_t *enabmulti; 135d62bc4baSyz147064 dl_disabmulti_req_t *disabmulti; 136d62bc4baSyz147064 mblk_t *reqmp; 137d62bc4baSyz147064 t_uscalar_t dl_prim; 138d62bc4baSyz147064 uint32_t size, addr_length; 139d62bc4baSyz147064 140*5d460eafSCathy Zhou ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 141d62bc4baSyz147064 /* 142d62bc4baSyz147064 * create multicst message and send it down 143d62bc4baSyz147064 */ 144d62bc4baSyz147064 addr_length = softmac->smac_addrlen; 145d62bc4baSyz147064 if (add) { 146d62bc4baSyz147064 size = sizeof (dl_enabmulti_req_t) + addr_length; 147d62bc4baSyz147064 dl_prim = DL_ENABMULTI_REQ; 148d62bc4baSyz147064 } else { 149d62bc4baSyz147064 size = sizeof (dl_disabmulti_req_t) + addr_length; 150d62bc4baSyz147064 dl_prim = DL_DISABMULTI_REQ; 151d62bc4baSyz147064 } 152d62bc4baSyz147064 153d62bc4baSyz147064 reqmp = mexchange(NULL, NULL, size, M_PROTO, dl_prim); 154d62bc4baSyz147064 if (reqmp == NULL) 155d62bc4baSyz147064 return (ENOMEM); 156d62bc4baSyz147064 157d62bc4baSyz147064 if (add) { 158d62bc4baSyz147064 enabmulti = (dl_enabmulti_req_t *)reqmp->b_rptr; 159d62bc4baSyz147064 enabmulti->dl_addr_offset = sizeof (dl_enabmulti_req_t); 160d62bc4baSyz147064 enabmulti->dl_addr_length = addr_length; 161d62bc4baSyz147064 (void) memcpy(&enabmulti[1], mca, addr_length); 162d62bc4baSyz147064 } else { 163d62bc4baSyz147064 disabmulti = (dl_disabmulti_req_t *)reqmp->b_rptr; 164d62bc4baSyz147064 disabmulti->dl_addr_offset = sizeof (dl_disabmulti_req_t); 165d62bc4baSyz147064 disabmulti->dl_addr_length = addr_length; 166d62bc4baSyz147064 (void) memcpy(&disabmulti[1], mca, addr_length); 167d62bc4baSyz147064 } 168d62bc4baSyz147064 169d62bc4baSyz147064 slp = softmac->smac_lower; 170d62bc4baSyz147064 ASSERT(slp != NULL); 171d62bc4baSyz147064 return (softmac_proto_tx(slp, reqmp, NULL)); 172d62bc4baSyz147064 } 173d62bc4baSyz147064 174d62bc4baSyz147064 int 175d62bc4baSyz147064 softmac_m_unicst(void *arg, const uint8_t *macaddr) 176d62bc4baSyz147064 { 177d62bc4baSyz147064 softmac_t *softmac = arg; 178d62bc4baSyz147064 softmac_lower_t *slp; 179d62bc4baSyz147064 dl_set_phys_addr_req_t *phyaddr; 180d62bc4baSyz147064 mblk_t *reqmp; 181d62bc4baSyz147064 size_t size; 182d62bc4baSyz147064 183*5d460eafSCathy Zhou ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 184d62bc4baSyz147064 /* 185d62bc4baSyz147064 * create set_phys_addr message and send it down 186d62bc4baSyz147064 */ 187d62bc4baSyz147064 size = DL_SET_PHYS_ADDR_REQ_SIZE + softmac->smac_addrlen; 188d62bc4baSyz147064 reqmp = mexchange(NULL, NULL, size, M_PROTO, DL_SET_PHYS_ADDR_REQ); 189d62bc4baSyz147064 if (reqmp == NULL) 190d62bc4baSyz147064 return (ENOMEM); 191d62bc4baSyz147064 192d62bc4baSyz147064 phyaddr = (dl_set_phys_addr_req_t *)reqmp->b_rptr; 193d62bc4baSyz147064 phyaddr->dl_addr_offset = sizeof (dl_set_phys_addr_req_t); 194d62bc4baSyz147064 phyaddr->dl_addr_length = softmac->smac_addrlen; 195d62bc4baSyz147064 (void) memcpy(&phyaddr[1], macaddr, softmac->smac_addrlen); 196d62bc4baSyz147064 197d62bc4baSyz147064 slp = softmac->smac_lower; 198d62bc4baSyz147064 ASSERT(slp != NULL); 199d62bc4baSyz147064 return (softmac_proto_tx(slp, reqmp, NULL)); 200d62bc4baSyz147064 } 201d62bc4baSyz147064 202d62bc4baSyz147064 void 203d62bc4baSyz147064 softmac_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 204d62bc4baSyz147064 { 205d62bc4baSyz147064 softmac_lower_t *slp = ((softmac_t *)arg)->smac_lower; 206d62bc4baSyz147064 mblk_t *ackmp; 207d62bc4baSyz147064 208d62bc4baSyz147064 ASSERT(slp != NULL); 209d62bc4baSyz147064 softmac_ioctl_tx(slp, mp, &ackmp); 210d62bc4baSyz147064 qreply(wq, ackmp); 211d62bc4baSyz147064 } 212d62bc4baSyz147064 213d62bc4baSyz147064 static void 214da14cebeSEric Cheng softmac_process_notify_ind(softmac_t *softmac, mblk_t *mp) 215d62bc4baSyz147064 { 216d62bc4baSyz147064 dl_notify_ind_t *dlnip = (dl_notify_ind_t *)mp->b_rptr; 217d62bc4baSyz147064 uint_t addroff, addrlen; 218d62bc4baSyz147064 219d62bc4baSyz147064 ASSERT(dlnip->dl_primitive == DL_NOTIFY_IND); 220d62bc4baSyz147064 221d62bc4baSyz147064 switch (dlnip->dl_notification) { 222d62bc4baSyz147064 case DL_NOTE_PHYS_ADDR: 223d62bc4baSyz147064 if (dlnip->dl_data != DL_CURR_PHYS_ADDR) 224d62bc4baSyz147064 break; 225d62bc4baSyz147064 226d62bc4baSyz147064 addroff = dlnip->dl_addr_offset; 227d62bc4baSyz147064 addrlen = dlnip->dl_addr_length - softmac->smac_saplen; 228d62bc4baSyz147064 if (addroff == 0 || addrlen != softmac->smac_addrlen || 229d62bc4baSyz147064 !MBLKIN(mp, addroff, addrlen)) { 230d62bc4baSyz147064 cmn_err(CE_NOTE, "softmac: got malformed " 231d62bc4baSyz147064 "DL_NOTIFY_IND; length/offset %d/%d", 232d62bc4baSyz147064 addrlen, addroff); 233d62bc4baSyz147064 break; 234d62bc4baSyz147064 } 235d62bc4baSyz147064 236d62bc4baSyz147064 mac_unicst_update(softmac->smac_mh, mp->b_rptr + addroff); 237d62bc4baSyz147064 break; 238d62bc4baSyz147064 239d62bc4baSyz147064 case DL_NOTE_LINK_UP: 240d62bc4baSyz147064 mac_link_update(softmac->smac_mh, LINK_STATE_UP); 241d62bc4baSyz147064 break; 242d62bc4baSyz147064 243d62bc4baSyz147064 case DL_NOTE_LINK_DOWN: 244d62bc4baSyz147064 mac_link_update(softmac->smac_mh, LINK_STATE_DOWN); 245d62bc4baSyz147064 break; 246d62bc4baSyz147064 } 247d62bc4baSyz147064 248d62bc4baSyz147064 freemsg(mp); 249d62bc4baSyz147064 } 250d62bc4baSyz147064 251da14cebeSEric Cheng void 252da14cebeSEric Cheng softmac_notify_thread(void *arg) 253da14cebeSEric Cheng { 254da14cebeSEric Cheng softmac_t *softmac = arg; 255da14cebeSEric Cheng callb_cpr_t cprinfo; 256da14cebeSEric Cheng 257da14cebeSEric Cheng CALLB_CPR_INIT(&cprinfo, &softmac->smac_mutex, callb_generic_cpr, 258da14cebeSEric Cheng "softmac_notify_thread"); 259da14cebeSEric Cheng 260da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex); 261da14cebeSEric Cheng 262da14cebeSEric Cheng /* 263da14cebeSEric Cheng * Quit the thread if smac_mh is unregistered. 264da14cebeSEric Cheng */ 265da14cebeSEric Cheng while (softmac->smac_mh != NULL && 266da14cebeSEric Cheng !(softmac->smac_flags & SOFTMAC_NOTIFY_QUIT)) { 267da14cebeSEric Cheng mblk_t *mp, *nextmp; 268da14cebeSEric Cheng 269da14cebeSEric Cheng if ((mp = softmac->smac_notify_head) == NULL) { 270da14cebeSEric Cheng CALLB_CPR_SAFE_BEGIN(&cprinfo); 271da14cebeSEric Cheng cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 272da14cebeSEric Cheng CALLB_CPR_SAFE_END(&cprinfo, &softmac->smac_mutex); 273da14cebeSEric Cheng continue; 274da14cebeSEric Cheng } 275da14cebeSEric Cheng 276da14cebeSEric Cheng softmac->smac_notify_head = softmac->smac_notify_tail = NULL; 277da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex); 278da14cebeSEric Cheng 279da14cebeSEric Cheng while (mp != NULL) { 280da14cebeSEric Cheng nextmp = mp->b_next; 281da14cebeSEric Cheng mp->b_next = NULL; 282da14cebeSEric Cheng softmac_process_notify_ind(softmac, mp); 283da14cebeSEric Cheng mp = nextmp; 284da14cebeSEric Cheng } 285da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex); 286da14cebeSEric Cheng } 287da14cebeSEric Cheng 288da14cebeSEric Cheng /* 289da14cebeSEric Cheng * The softmac is being destroyed, simply free all of the DL_NOTIFY_IND 290da14cebeSEric Cheng * messages left in the queue which did not have the chance to be 291da14cebeSEric Cheng * processed. 292da14cebeSEric Cheng */ 293da14cebeSEric Cheng freemsgchain(softmac->smac_notify_head); 294da14cebeSEric Cheng softmac->smac_notify_head = softmac->smac_notify_tail = NULL; 295da14cebeSEric Cheng softmac->smac_notify_thread = NULL; 296da14cebeSEric Cheng cv_broadcast(&softmac->smac_cv); 297da14cebeSEric Cheng CALLB_CPR_EXIT(&cprinfo); 298da14cebeSEric Cheng thread_exit(); 299da14cebeSEric Cheng } 300da14cebeSEric Cheng 301da14cebeSEric Cheng static void 302da14cebeSEric Cheng softmac_enqueue_notify_ind(queue_t *rq, mblk_t *mp) 303da14cebeSEric Cheng { 304da14cebeSEric Cheng softmac_lower_t *slp = rq->q_ptr; 305da14cebeSEric Cheng softmac_t *softmac = slp->sl_softmac; 306da14cebeSEric Cheng 307da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex); 308da14cebeSEric Cheng if (softmac->smac_notify_tail == NULL) { 309da14cebeSEric Cheng softmac->smac_notify_head = softmac->smac_notify_tail = mp; 310da14cebeSEric Cheng } else { 311da14cebeSEric Cheng softmac->smac_notify_tail->b_next = mp; 312da14cebeSEric Cheng softmac->smac_notify_tail = mp; 313da14cebeSEric Cheng } 314da14cebeSEric Cheng cv_broadcast(&softmac->smac_cv); 315da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex); 316da14cebeSEric Cheng } 317da14cebeSEric Cheng 318d62bc4baSyz147064 static void 319d62bc4baSyz147064 softmac_process_dlpi(softmac_lower_t *slp, mblk_t *mp, uint_t minlen, 320d62bc4baSyz147064 t_uscalar_t reqprim) 321d62bc4baSyz147064 { 322d62bc4baSyz147064 const char *ackname; 323d62bc4baSyz147064 324d62bc4baSyz147064 ackname = dl_primstr(((union DL_primitives *)mp->b_rptr)->dl_primitive); 325d62bc4baSyz147064 326d62bc4baSyz147064 if (MBLKL(mp) < minlen) { 327d62bc4baSyz147064 cmn_err(CE_WARN, "softmac: got short %s", ackname); 328d62bc4baSyz147064 freemsg(mp); 329d62bc4baSyz147064 return; 330d62bc4baSyz147064 } 331d62bc4baSyz147064 332d62bc4baSyz147064 mutex_enter(&slp->sl_mutex); 333d62bc4baSyz147064 if (slp->sl_pending_prim != reqprim) { 334d62bc4baSyz147064 cmn_err(CE_NOTE, "softmac: got unexpected %s", ackname); 335d62bc4baSyz147064 mutex_exit(&slp->sl_mutex); 336d62bc4baSyz147064 freemsg(mp); 337d62bc4baSyz147064 return; 338d62bc4baSyz147064 } 339d62bc4baSyz147064 340d62bc4baSyz147064 slp->sl_pending_prim = DL_PRIM_INVAL; 341d62bc4baSyz147064 slp->sl_ack_mp = mp; 342d62bc4baSyz147064 cv_signal(&slp->sl_cv); 343d62bc4baSyz147064 mutex_exit(&slp->sl_mutex); 344d62bc4baSyz147064 } 345d62bc4baSyz147064 346d62bc4baSyz147064 void 347d62bc4baSyz147064 softmac_rput_process_proto(queue_t *rq, mblk_t *mp) 348d62bc4baSyz147064 { 349d62bc4baSyz147064 softmac_lower_t *slp = rq->q_ptr; 350d62bc4baSyz147064 union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr; 351d62bc4baSyz147064 ssize_t len = MBLKL(mp); 352d62bc4baSyz147064 const char *primstr; 353d62bc4baSyz147064 354d62bc4baSyz147064 if (len < sizeof (t_uscalar_t)) { 355d62bc4baSyz147064 cmn_err(CE_WARN, "softmac: got runt DLPI message"); 356d62bc4baSyz147064 goto exit; 357d62bc4baSyz147064 } 358d62bc4baSyz147064 359d62bc4baSyz147064 primstr = dl_primstr(dlp->dl_primitive); 360d62bc4baSyz147064 361d62bc4baSyz147064 switch (dlp->dl_primitive) { 362d62bc4baSyz147064 case DL_OK_ACK: 363d62bc4baSyz147064 if (len < DL_OK_ACK_SIZE) 364d62bc4baSyz147064 goto runt; 365d62bc4baSyz147064 366d62bc4baSyz147064 softmac_process_dlpi(slp, mp, DL_OK_ACK_SIZE, 367d62bc4baSyz147064 dlp->ok_ack.dl_correct_primitive); 368d62bc4baSyz147064 return; 369d62bc4baSyz147064 370d62bc4baSyz147064 case DL_ERROR_ACK: 371d62bc4baSyz147064 if (len < DL_ERROR_ACK_SIZE) 372d62bc4baSyz147064 goto runt; 373d62bc4baSyz147064 374d62bc4baSyz147064 softmac_process_dlpi(slp, mp, DL_ERROR_ACK_SIZE, 375d62bc4baSyz147064 dlp->error_ack.dl_error_primitive); 376d62bc4baSyz147064 return; 377d62bc4baSyz147064 378d62bc4baSyz147064 case DL_NOTIFY_IND: 379d62bc4baSyz147064 if (len < DL_NOTIFY_IND_SIZE) 380d62bc4baSyz147064 goto runt; 381d62bc4baSyz147064 382da14cebeSEric Cheng /* 383da14cebeSEric Cheng * Enqueue all the DL_NOTIFY_IND messages and process them 384da14cebeSEric Cheng * in another separate thread to avoid deadlock. Here is an 385da14cebeSEric Cheng * example of the deadlock scenario: 386da14cebeSEric Cheng * 387da14cebeSEric Cheng * Thread A: mac_promisc_set()->softmac_m_promisc() 388da14cebeSEric Cheng * 389da14cebeSEric Cheng * The softmac driver waits for the ACK of the 390da14cebeSEric Cheng * DL_PROMISC_PHYS request with the MAC perimeter; 391da14cebeSEric Cheng * 392da14cebeSEric Cheng * Thread B: 393da14cebeSEric Cheng * 394da14cebeSEric Cheng * The driver handles the DL_PROMISC_PHYS request. Before 395da14cebeSEric Cheng * it sends back the ACK, it could first send a 396da14cebeSEric Cheng * DL_NOTE_PROMISC_ON_PHYS notification. 397da14cebeSEric Cheng * 398da14cebeSEric Cheng * Since DL_NOTIFY_IND could eventually cause softmac to call 399da14cebeSEric Cheng * mac_xxx_update(), which requires MAC perimeter, this would 400da14cebeSEric Cheng * cause deadlock between the two threads. Enqueuing the 401da14cebeSEric Cheng * DL_NOTIFY_IND message and defer its processing would 402da14cebeSEric Cheng * avoid the potential deadlock. 403da14cebeSEric Cheng */ 404da14cebeSEric Cheng softmac_enqueue_notify_ind(rq, mp); 405d62bc4baSyz147064 return; 406d62bc4baSyz147064 407d62bc4baSyz147064 case DL_NOTIFY_ACK: 408d62bc4baSyz147064 softmac_process_dlpi(slp, mp, DL_NOTIFY_ACK_SIZE, 409d62bc4baSyz147064 DL_NOTIFY_REQ); 410d62bc4baSyz147064 return; 411d62bc4baSyz147064 412d62bc4baSyz147064 case DL_CAPABILITY_ACK: 413d62bc4baSyz147064 softmac_process_dlpi(slp, mp, DL_CAPABILITY_ACK_SIZE, 414d62bc4baSyz147064 DL_CAPABILITY_REQ); 415d62bc4baSyz147064 return; 416d62bc4baSyz147064 417d62bc4baSyz147064 case DL_BIND_ACK: 418d62bc4baSyz147064 softmac_process_dlpi(slp, mp, DL_BIND_ACK_SIZE, DL_BIND_REQ); 419d62bc4baSyz147064 return; 420d62bc4baSyz147064 421d62bc4baSyz147064 case DL_CONTROL_ACK: 422d62bc4baSyz147064 softmac_process_dlpi(slp, mp, DL_CONTROL_ACK_SIZE, 423d62bc4baSyz147064 DL_CONTROL_REQ); 424d62bc4baSyz147064 return; 425d62bc4baSyz147064 426d62bc4baSyz147064 case DL_UNITDATA_IND: 427d62bc4baSyz147064 case DL_PHYS_ADDR_ACK: 428d62bc4baSyz147064 /* 429d62bc4baSyz147064 * a. Because the stream is in DLIOCRAW mode, 430d62bc4baSyz147064 * DL_UNITDATA_IND messages are not expected. 431d62bc4baSyz147064 * b. The lower stream should not receive DL_PHYS_ADDR_REQ, 432d62bc4baSyz147064 * so DL_PHYS_ADDR_ACK messages are also unexpected. 433d62bc4baSyz147064 */ 434d62bc4baSyz147064 default: 435d62bc4baSyz147064 cmn_err(CE_WARN, "softmac: got unexpected %s", primstr); 436d62bc4baSyz147064 break; 437d62bc4baSyz147064 } 438d62bc4baSyz147064 exit: 439d62bc4baSyz147064 freemsg(mp); 440d62bc4baSyz147064 return; 441d62bc4baSyz147064 runt: 442d62bc4baSyz147064 cmn_err(CE_WARN, "softmac: got runt %s", primstr); 443d62bc4baSyz147064 freemsg(mp); 444d62bc4baSyz147064 } 445d62bc4baSyz147064 446d62bc4baSyz147064 void 447*5d460eafSCathy Zhou softmac_rput_process_notdata(queue_t *rq, softmac_upper_t *sup, mblk_t *mp) 448d62bc4baSyz147064 { 449d62bc4baSyz147064 softmac_lower_t *slp = rq->q_ptr; 450*5d460eafSCathy Zhou union DL_primitives *dlp; 451*5d460eafSCathy Zhou ssize_t len = MBLKL(mp); 452d62bc4baSyz147064 453d62bc4baSyz147064 switch (DB_TYPE(mp)) { 454d62bc4baSyz147064 case M_PROTO: 455d62bc4baSyz147064 case M_PCPROTO: 456*5d460eafSCathy Zhou /* 457*5d460eafSCathy Zhou * If this is a shared-lower-stream, pass it to softmac to 458*5d460eafSCathy Zhou * process. 459*5d460eafSCathy Zhou */ 460*5d460eafSCathy Zhou if (sup == NULL) { 461d62bc4baSyz147064 softmac_rput_process_proto(rq, mp); 462d62bc4baSyz147064 break; 463*5d460eafSCathy Zhou } 464d62bc4baSyz147064 465*5d460eafSCathy Zhou /* 466*5d460eafSCathy Zhou * Dedicated-lower-stream. 467*5d460eafSCathy Zhou */ 468*5d460eafSCathy Zhou dlp = (union DL_primitives *)mp->b_rptr; 469*5d460eafSCathy Zhou ASSERT(len >= sizeof (dlp->dl_primitive)); 470*5d460eafSCathy Zhou switch (dlp->dl_primitive) { 471*5d460eafSCathy Zhou case DL_OK_ACK: 472*5d460eafSCathy Zhou if (len < DL_OK_ACK_SIZE) 473*5d460eafSCathy Zhou goto runt; 474*5d460eafSCathy Zhou 475*5d460eafSCathy Zhou /* 476*5d460eafSCathy Zhou * If this is a DL_OK_ACK for a DL_UNBIND_REQ, pass it 477*5d460eafSCathy Zhou * to softmac to process, otherwise directly pass it to 478*5d460eafSCathy Zhou * the upper stream. 479*5d460eafSCathy Zhou */ 480*5d460eafSCathy Zhou if (dlp->ok_ack.dl_correct_primitive == DL_UNBIND_REQ) { 481*5d460eafSCathy Zhou softmac_rput_process_proto(rq, mp); 482*5d460eafSCathy Zhou break; 483*5d460eafSCathy Zhou } 484*5d460eafSCathy Zhou 485*5d460eafSCathy Zhou putnext(sup->su_rq, mp); 486*5d460eafSCathy Zhou break; 487*5d460eafSCathy Zhou case DL_ERROR_ACK: 488*5d460eafSCathy Zhou if (len < DL_ERROR_ACK_SIZE) 489*5d460eafSCathy Zhou goto runt; 490*5d460eafSCathy Zhou 491*5d460eafSCathy Zhou /* 492*5d460eafSCathy Zhou * If this is a DL_ERROR_ACK for a DL_UNBIND_REQ, pass 493*5d460eafSCathy Zhou * it to softmac to process, otherwise directly pass it 494*5d460eafSCathy Zhou * to the upper stream. 495*5d460eafSCathy Zhou */ 496*5d460eafSCathy Zhou if (dlp->error_ack.dl_error_primitive == 497*5d460eafSCathy Zhou DL_UNBIND_REQ) { 498*5d460eafSCathy Zhou softmac_rput_process_proto(rq, mp); 499*5d460eafSCathy Zhou break; 500*5d460eafSCathy Zhou } 501*5d460eafSCathy Zhou 502*5d460eafSCathy Zhou putnext(sup->su_rq, mp); 503*5d460eafSCathy Zhou break; 504*5d460eafSCathy Zhou case DL_BIND_ACK: 505*5d460eafSCathy Zhou case DL_CAPABILITY_ACK: 506*5d460eafSCathy Zhou softmac_rput_process_proto(rq, mp); 507*5d460eafSCathy Zhou break; 508*5d460eafSCathy Zhou default: 509*5d460eafSCathy Zhou putnext(sup->su_rq, mp); 510*5d460eafSCathy Zhou break; 511*5d460eafSCathy Zhou } 512*5d460eafSCathy Zhou break; 513d62bc4baSyz147064 case M_FLUSH: 514d62bc4baSyz147064 if (*mp->b_rptr & FLUSHR) 515d62bc4baSyz147064 flushq(rq, FLUSHDATA); 516d62bc4baSyz147064 if (*mp->b_rptr & FLUSHW) 517d62bc4baSyz147064 flushq(OTHERQ(rq), FLUSHDATA); 518d62bc4baSyz147064 putnext(rq, mp); 519d62bc4baSyz147064 break; 520d62bc4baSyz147064 521d62bc4baSyz147064 case M_IOCACK: 522d62bc4baSyz147064 case M_IOCNAK: 523d62bc4baSyz147064 case M_COPYIN: 524d62bc4baSyz147064 case M_COPYOUT: 525*5d460eafSCathy Zhou if (sup != NULL) { 526*5d460eafSCathy Zhou putnext(sup->su_rq, mp); 527*5d460eafSCathy Zhou break; 528*5d460eafSCathy Zhou } 529*5d460eafSCathy Zhou 530d62bc4baSyz147064 mutex_enter(&slp->sl_mutex); 531d62bc4baSyz147064 if (!slp->sl_pending_ioctl) { 532d62bc4baSyz147064 mutex_exit(&slp->sl_mutex); 533d62bc4baSyz147064 cmn_err(CE_NOTE, "softmac: got unexpected mblk " 534d62bc4baSyz147064 "type 0x%x", DB_TYPE(mp)); 535d62bc4baSyz147064 freemsg(mp); 536d62bc4baSyz147064 break; 537d62bc4baSyz147064 } 538d62bc4baSyz147064 539d62bc4baSyz147064 slp->sl_pending_ioctl = B_FALSE; 540d62bc4baSyz147064 slp->sl_ack_mp = mp; 541d62bc4baSyz147064 cv_broadcast(&slp->sl_cv); 542d62bc4baSyz147064 mutex_exit(&slp->sl_mutex); 543*5d460eafSCathy Zhou break; 544d62bc4baSyz147064 545d62bc4baSyz147064 default: 546d62bc4baSyz147064 cmn_err(CE_NOTE, "softmac: got unsupported mblk type 0x%x", 547d62bc4baSyz147064 DB_TYPE(mp)); 548d62bc4baSyz147064 freemsg(mp); 549d62bc4baSyz147064 break; 550d62bc4baSyz147064 } 551*5d460eafSCathy Zhou return; 552*5d460eafSCathy Zhou runt: 553*5d460eafSCathy Zhou cmn_err(CE_WARN, "softmac: got runt %s", dl_primstr(dlp->dl_primitive)); 554*5d460eafSCathy Zhou freemsg(mp); 555d62bc4baSyz147064 } 556