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
softmac_send_notify_req(softmac_lower_t * slp,uint32_t notifications)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
softmac_send_bind_req(softmac_lower_t * slp,uint_t sap)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
softmac_send_unbind_req(softmac_lower_t * slp)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
softmac_send_promisc_req(softmac_lower_t * slp,t_uscalar_t level,boolean_t on)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
softmac_m_promisc(void * arg,boolean_t on)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
softmac_m_multicst(void * arg,boolean_t add,const uint8_t * mca)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
softmac_m_unicst(void * arg,const uint8_t * macaddr)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
softmac_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)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
softmac_process_notify_ind(softmac_t * softmac,mblk_t * mp)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
softmac_notify_thread(void * arg)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
softmac_enqueue_notify_ind(queue_t * rq,mblk_t * mp)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
softmac_process_dlpi(softmac_lower_t * slp,mblk_t * mp,uint_t minlen,t_uscalar_t reqprim)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
softmac_rput_process_proto(queue_t * rq,mblk_t * mp)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
softmac_rput_process_notdata(queue_t * rq,softmac_upper_t * sup,mblk_t * mp)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