xref: /freebsd/sys/compat/linuxkpi/common/src/linux_80211_macops.c (revision 4db3872aabc33088cf180599c5eaa23b6f58e6d1)
1 /*-
2  * Copyright (c) 2021-2026 The FreeBSD Foundation
3  *
4  * This software was developed by Björn Zeeb under sponsorship from
5  * the FreeBSD Foundation.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/kernel.h>
32 #include <sys/errno.h>
33 
34 #define	LINUXKPI_NET80211
35 #include <net/mac80211.h>
36 
37 #include "linux_80211.h"
38 
39 /* Could be a different tracing framework later. */
40 #ifdef LINUXKPI_DEBUG_80211
41 #define	LKPI_80211_TRACE_MO(fmt, ...)					\
42     if (linuxkpi_debug_80211 & D80211_TRACE_MO)				\
43 	printf("LKPI_80211_TRACE_MO %s:%d: %d %d %lu: " fmt "\n",	\
44 	    __func__, __LINE__, curcpu, curthread->td_tid,		\
45 	    jiffies, ##__VA_ARGS__)
46 #else
47 #define	LKPI_80211_TRACE_MO(...)	do { } while(0)
48 #endif
49 
50 int
51 lkpi_80211_mo_start(struct ieee80211_hw *hw)
52 {
53 	struct lkpi_hw *lhw;
54 	int error;
55 
56 	lockdep_assert_wiphy(hw->wiphy);
57 
58 	lhw = HW_TO_LHW(hw);
59 	if (lhw->ops->start == NULL) {
60 		error = EOPNOTSUPP;
61 		goto out;
62 	}
63 
64 	if ((lhw->sc_flags & LKPI_MAC80211_DRV_STARTED)) {
65 		/* Trying to start twice is an error. */
66 		error = EEXIST;
67 		goto out;
68 	}
69 	LKPI_80211_TRACE_MO("hw %p", hw);
70 	error = lhw->ops->start(hw);
71 	if (error == 0)
72 		lhw->sc_flags |= LKPI_MAC80211_DRV_STARTED;
73 
74 out:
75 	return (error);
76 }
77 
78 void
79 lkpi_80211_mo_stop(struct ieee80211_hw *hw, bool suspend)
80 {
81 	struct lkpi_hw *lhw;
82 
83 	lhw = HW_TO_LHW(hw);
84 	if (lhw->ops->stop == NULL)
85 		return;
86 
87 	LKPI_80211_TRACE_MO("hw %p suspend %d", hw, suspend);
88 	lhw->ops->stop(hw, suspend);
89 	lhw->sc_flags &= ~LKPI_MAC80211_DRV_STARTED;
90 }
91 
92 int
93 lkpi_80211_mo_get_antenna(struct ieee80211_hw *hw, u32 *txs, u32 *rxs)
94 {
95 	struct lkpi_hw *lhw;
96 	int error;
97 
98 	lhw = HW_TO_LHW(hw);
99 	if (lhw->ops->get_antenna == NULL) {
100 		error = EOPNOTSUPP;
101 		goto out;
102 	}
103 
104 	LKPI_80211_TRACE_MO("hw %p", hw);
105 	LKPI_80211_TRACE_MO("TODO link/radio_idx");
106 	error = lhw->ops->get_antenna(hw, 0, txs, rxs);
107 
108 out:
109 	return (error);
110 }
111 
112 int
113 lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw *hw, uint32_t frag_th)
114 {
115 	struct lkpi_hw *lhw;
116 	int error;
117 
118 	might_sleep();
119 	lockdep_assert_wiphy(hw->wiphy);
120 
121 	lhw = HW_TO_LHW(hw);
122 	if (lhw->ops->set_frag_threshold == NULL) {
123 		error = EOPNOTSUPP;
124 		goto out;
125 	}
126 
127 	LKPI_80211_TRACE_MO("hw %p frag_th %u", hw, frag_th);
128 	LKPI_80211_TRACE_MO("TODO link/radio_idx");
129 	error = lhw->ops->set_frag_threshold(hw, 0, frag_th);
130 
131 out:
132 	return (error);
133 }
134 
135 int
136 lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw *hw, uint32_t rts_th)
137 {
138 	struct lkpi_hw *lhw;
139 	int error;
140 
141 	might_sleep();
142 	lockdep_assert_wiphy(hw->wiphy);
143 
144 	lhw = HW_TO_LHW(hw);
145 	if (lhw->ops->set_rts_threshold == NULL) {
146 		error = EOPNOTSUPP;
147 		goto out;
148 	}
149 
150 	LKPI_80211_TRACE_MO("hw %p rts_th %u", hw, rts_th);
151 	LKPI_80211_TRACE_MO("TODO link/radio_idx");
152 	error = lhw->ops->set_rts_threshold(hw, 0, rts_th);
153 
154 out:
155 	return (error);
156 }
157 
158 
159 int
160 lkpi_80211_mo_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
161 {
162 	struct lkpi_hw *lhw;
163 	struct lkpi_vif *lvif;
164 	int error;
165 
166 	lhw = HW_TO_LHW(hw);
167 	if (lhw->ops->add_interface == NULL) {
168 		error = EOPNOTSUPP;
169 		goto out;
170 	}
171 
172 	lvif = VIF_TO_LVIF(vif);
173 	LKPI_80211_LVIF_LOCK(lvif);
174 	if (lvif->added_to_drv) {
175 		LKPI_80211_LVIF_UNLOCK(lvif);
176 		/* Trying to add twice is an error. */
177 		error = EEXIST;
178 		goto out;
179 	}
180 	LKPI_80211_LVIF_UNLOCK(lvif);
181 
182 	LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
183 	error = lhw->ops->add_interface(hw, vif);
184 	if (error == 0) {
185 		LKPI_80211_LVIF_LOCK(lvif);
186 		lvif->added_to_drv = true;
187 		LKPI_80211_LVIF_UNLOCK(lvif);
188 	}
189 
190 out:
191 	return (error);
192 }
193 
194 void
195 lkpi_80211_mo_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
196 {
197 	struct lkpi_hw *lhw;
198 	struct lkpi_vif *lvif;
199 
200 	lhw = HW_TO_LHW(hw);
201 	if (lhw->ops->remove_interface == NULL)
202 		return;
203 
204 	lvif = VIF_TO_LVIF(vif);
205 	LKPI_80211_LVIF_LOCK(lvif);
206 	if (!lvif->added_to_drv) {
207 		LKPI_80211_LVIF_UNLOCK(lvif);
208 		return;
209 	}
210 	LKPI_80211_LVIF_UNLOCK(lvif);
211 
212 	LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
213 	lhw->ops->remove_interface(hw, vif);
214 	LKPI_80211_LVIF_LOCK(lvif);
215 	lvif->added_to_drv = false;
216 	LKPI_80211_LVIF_UNLOCK(lvif);
217 }
218 
219 
220 int
221 lkpi_80211_mo_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
222     struct ieee80211_scan_request *sr)
223 {
224 	struct lkpi_hw *lhw;
225 	int error;
226 
227 	lockdep_assert_wiphy(hw->wiphy);
228 
229 	/*
230 	 * MUST NOT return EPERM as that is a "magic number 1" based on rtw88
231 	 * driver indicating hw_scan is not supported despite the ops call
232 	 * being available.
233 	 */
234 
235 	lhw = HW_TO_LHW(hw);
236 	if (lhw->ops->hw_scan == NULL) {
237 		/* Return magic number to use sw scan. */
238 		error = 1;
239 		goto out;
240 	}
241 
242 	LKPI_80211_TRACE_MO("CALLING hw %p vif %p sr %p", hw, vif, sr);
243 	error = lhw->ops->hw_scan(hw, vif, sr);
244 	LKPI_80211_TRACE_MO("RETURNING hw %p vif %p sr %p error %d", hw, vif, sr, error);
245 
246 out:
247 	return (error);
248 }
249 
250 void
251 lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
252 {
253 	struct lkpi_hw *lhw;
254 
255 	lockdep_assert_wiphy(hw->wiphy);
256 
257 	lhw = HW_TO_LHW(hw);
258 	if (lhw->ops->cancel_hw_scan == NULL)
259 		return;
260 
261 	LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
262 	lhw->ops->cancel_hw_scan(hw, vif);
263 }
264 
265 void
266 lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
267 {
268 	struct lkpi_hw *lhw;
269 
270 	lhw = HW_TO_LHW(hw);
271 	if (lhw->ops->sw_scan_complete == NULL)
272 		return;
273 
274 	LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
275 	lhw->ops->sw_scan_complete(hw, vif);
276 	lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
277 }
278 
279 void
280 lkpi_80211_mo_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
281     const u8 *addr)
282 {
283 	struct lkpi_hw *lhw;
284 
285 	lhw = HW_TO_LHW(hw);
286 	if (lhw->ops->sw_scan_start == NULL)
287 		return;
288 
289 	LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
290 	lhw->ops->sw_scan_start(hw, vif, addr);
291 }
292 
293 
294 /*
295  * We keep the Linux type here;  it really is an uintptr_t.
296  */
297 u64
298 lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *hw,
299     struct netdev_hw_addr_list *mc_list)
300 {
301 	struct lkpi_hw *lhw;
302 	u64 ptr;
303 
304 	/* This seems fine without the wiphy lock. */
305 
306 	lhw = HW_TO_LHW(hw);
307 	if (lhw->ops->prepare_multicast == NULL)
308 		return (0);
309 
310 	LKPI_80211_TRACE_MO("hw %p mc_list %p", hw, mc_list);
311 	ptr = lhw->ops->prepare_multicast(hw, mc_list);
312 	return (ptr);
313 }
314 
315 void
316 lkpi_80211_mo_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
317     unsigned int *total_flags, u64 mc_ptr)
318 {
319 	struct lkpi_hw *lhw;
320 
321 	lockdep_assert_wiphy(hw->wiphy);
322 
323 	lhw = HW_TO_LHW(hw);
324 	if (lhw->ops->configure_filter == NULL)
325 		return;
326 
327 	LKPI_80211_TRACE_MO("hw %p changed_flags %#x total_flags %p mc_ptr %ju", hw, changed_flags, total_flags, (uintmax_t)mc_ptr);
328 	lhw->ops->configure_filter(hw, changed_flags, total_flags, mc_ptr);
329 }
330 
331 
332 /*
333  * So far we only called sta_{add,remove} as an alternative to sta_state.
334  * Let's keep the implementation simpler and hide sta_{add,remove} under the
335  * hood here calling them if state_state is not available from mo_sta_state.
336  */
337 static int
338 lkpi_80211_mo_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
339     struct ieee80211_sta *sta)
340 {
341 	struct lkpi_hw *lhw;
342 	struct lkpi_sta *lsta;
343 	int error;
344 
345 	lhw = HW_TO_LHW(hw);
346 	if (lhw->ops->sta_add == NULL) {
347 		error = EOPNOTSUPP;
348 		goto out;
349 	}
350 
351 	lsta = STA_TO_LSTA(sta);
352 	if (lsta->added_to_drv) {
353 		error = EEXIST;
354 		goto out;
355 	}
356 
357 	LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
358 	error = lhw->ops->sta_add(hw, vif, sta);
359 	if (error == 0)
360 		lsta->added_to_drv = true;
361 
362 out:
363 	return error;
364 }
365 
366 static int
367 lkpi_80211_mo_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
368     struct ieee80211_sta *sta)
369 {
370 	struct lkpi_hw *lhw;
371 	struct lkpi_sta *lsta;
372 	int error;
373 
374 	lhw = HW_TO_LHW(hw);
375 	if (lhw->ops->sta_remove == NULL) {
376 		error = EOPNOTSUPP;
377 		goto out;
378 	}
379 
380 	lsta = STA_TO_LSTA(sta);
381 	if (!lsta->added_to_drv) {
382 		/* If we never added the sta, do not complain on cleanup. */
383 		error = 0;
384 		goto out;
385 	}
386 
387 	LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
388 	error = lhw->ops->sta_remove(hw, vif, sta);
389 	if (error == 0)
390 		lsta->added_to_drv = false;
391 
392 out:
393 	return error;
394 }
395 
396 int
397 lkpi_80211_mo_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
398     struct lkpi_sta *lsta, enum ieee80211_sta_state nstate)
399 {
400 	struct lkpi_hw *lhw;
401 	struct ieee80211_sta *sta;
402 	int error;
403 
404 	lhw = HW_TO_LHW(hw);
405 	sta = LSTA_TO_STA(lsta);
406 	if (lhw->ops->sta_state != NULL) {
407 		LKPI_80211_TRACE_MO("hw %p vif %p sta %p nstate %d", hw, vif, sta, nstate);
408 		error = lhw->ops->sta_state(hw, vif, sta, lsta->state, nstate);
409 		if (error == 0) {
410 			if (nstate == IEEE80211_STA_NOTEXIST)
411 				lsta->added_to_drv = false;
412 			else
413 				lsta->added_to_drv = true;
414 			lsta->state = nstate;
415 		}
416 		goto out;
417 	}
418 
419 	/* XXX-BZ is the change state AUTH or ASSOC here? */
420 	if (lsta->state < IEEE80211_STA_ASSOC && nstate == IEEE80211_STA_ASSOC) {
421 		error = lkpi_80211_mo_sta_add(hw, vif, sta);
422 		if (error == 0)
423 			lsta->added_to_drv = true;
424 	} else if (lsta->state >= IEEE80211_STA_ASSOC &&
425 	    nstate < IEEE80211_STA_ASSOC) {
426 		error = lkpi_80211_mo_sta_remove(hw, vif, sta);
427 		if (error == 0)
428 			lsta->added_to_drv = false;
429 	} else
430 		/* Nothing to do. */
431 		error = 0;
432 	if (error == 0)
433 		lsta->state = nstate;
434 
435 out:
436 	/* XXX-BZ should we manage state in here? */
437 	return (error);
438 }
439 
440 int
441 lkpi_80211_mo_config(struct ieee80211_hw *hw, uint32_t changed)
442 {
443 	struct lkpi_hw *lhw;
444 	int error;
445 
446 	lockdep_assert_wiphy(hw->wiphy);
447 
448 	lhw = HW_TO_LHW(hw);
449 	if (lhw->ops->config == NULL) {
450 		error = EOPNOTSUPP;
451 		goto out;
452 	}
453 
454 	LKPI_80211_TRACE_MO("hw %p changed %u", hw, changed);
455 	LKPI_80211_TRACE_MO("TODO link/radio_idx");
456 	error = lhw->ops->config(hw, 0, changed);
457 
458 out:
459 	return (error);
460 }
461 
462 
463 int
464 lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
465     struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf)
466 {
467 	struct lkpi_hw *lhw;
468 	int error;
469 
470 	lhw = HW_TO_LHW(hw);
471 	if (lhw->ops->assign_vif_chanctx == NULL) {
472 		error = EOPNOTSUPP;
473 		goto out;
474 	}
475 
476 	LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p",
477 	    hw, vif, conf, chanctx_conf);
478 	error = lhw->ops->assign_vif_chanctx(hw, vif, conf, chanctx_conf);
479 	if (error == 0)
480 		vif->bss_conf.chanctx_conf = chanctx_conf;
481 
482 out:
483 	return (error);
484 }
485 
486 void
487 lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
488     struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf)
489 {
490 	struct lkpi_hw *lhw;
491 
492 	might_sleep();
493 	lockdep_assert_wiphy(hw->wiphy);
494 
495 	lhw = HW_TO_LHW(hw);
496 	if (lhw->ops->unassign_vif_chanctx == NULL)
497 		return;
498 
499 	if (chanctx_conf == NULL)
500 		return;
501 
502 	LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p",
503 	    hw, vif, conf, chanctx_conf);
504 	lhw->ops->unassign_vif_chanctx(hw, vif, conf, chanctx_conf);
505 }
506 
507 
508 int
509 lkpi_80211_mo_add_chanctx(struct ieee80211_hw *hw,
510     struct ieee80211_chanctx_conf *chanctx_conf)
511 {
512 	struct lkpi_hw *lhw;
513 	struct lkpi_chanctx *lchanctx;
514 	int error;
515 
516 	might_sleep();
517 	lockdep_assert_wiphy(hw->wiphy);
518 
519 	lhw = HW_TO_LHW(hw);
520 	if (lhw->ops->add_chanctx == NULL) {
521 		error = EOPNOTSUPP;
522 		goto out;
523 	}
524 
525 	LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);
526 	error = lhw->ops->add_chanctx(hw, chanctx_conf);
527 	if (error == 0) {
528 		lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);
529 		lchanctx->added_to_drv = true;
530 	}
531 
532 out:
533 	return (error);
534 }
535 
536 void
537 lkpi_80211_mo_change_chanctx(struct ieee80211_hw *hw,
538     struct ieee80211_chanctx_conf *chanctx_conf, uint32_t changed)
539 {
540 	struct lkpi_hw *lhw;
541 
542 	might_sleep();
543 	lockdep_assert_wiphy(hw->wiphy);
544 
545 	lhw = HW_TO_LHW(hw);
546 	if (lhw->ops->change_chanctx == NULL)
547 		return;
548 
549 	LKPI_80211_TRACE_MO("hw %p chanctx_conf %p changed %u", hw, chanctx_conf, changed);
550 	lhw->ops->change_chanctx(hw, chanctx_conf, changed);
551 }
552 
553 void
554 lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *hw,
555     struct ieee80211_chanctx_conf *chanctx_conf)
556 {
557 	struct lkpi_hw *lhw;
558 	struct lkpi_chanctx *lchanctx;
559 
560 	might_sleep();
561 	lockdep_assert_wiphy(hw->wiphy);
562 
563 	lhw = HW_TO_LHW(hw);
564 	if (lhw->ops->remove_chanctx == NULL)
565 		return;
566 
567 	LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);
568 	lhw->ops->remove_chanctx(hw, chanctx_conf);
569 	lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);
570 	lchanctx->added_to_drv = false;
571 }
572 
573 void
574 lkpi_80211_mo_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
575     uint64_t vif_cfg_bits, bool fallback)
576 {
577 	struct lkpi_hw *lhw;
578 
579 	might_sleep();
580 	/* XXX-FINISH all callers for lockdep_assert_wiphy(hw->wiphy); */
581 
582 	lhw = HW_TO_LHW(hw);
583 	if (lhw->ops->vif_cfg_changed == NULL &&
584 	    lhw->ops->bss_info_changed == NULL)
585 		return;
586 
587 	if (vif_cfg_bits == 0)
588 		return;
589 
590 	LKPI_80211_TRACE_MO("hw %p vif %p vif_cfg_bits %#jx", hw, vif, (uintmax_t)vif_cfg_bits);
591 	if (lhw->ops->link_info_changed != NULL)
592 		lhw->ops->vif_cfg_changed(hw, vif, vif_cfg_bits);
593 	else if (fallback)
594 		lhw->ops->bss_info_changed(hw, vif, &vif->bss_conf, vif_cfg_bits);
595 }
596 
597 void
598 lkpi_80211_mo_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
599     struct ieee80211_bss_conf *conf, uint64_t link_info_bits, uint8_t link_id,
600     bool fallback)
601 {
602 	struct lkpi_hw *lhw;
603 
604 	might_sleep();
605 	/* XXX-FINISH all callers for lockdep_assert_wiphy(hw->wiphy); */
606 
607 	lhw = HW_TO_LHW(hw);
608 	if (lhw->ops->link_info_changed == NULL &&
609 	    lhw->ops->bss_info_changed == NULL)
610 		return;
611 
612 	if (link_info_bits == 0)
613 		return;
614 
615 	if (!ieee80211_vif_link_active(vif, link_id))
616 		return;
617 
618 	LKPI_80211_TRACE_MO("hw %p vif %p conf %p link_info_bits %#jx", hw, vif, conf, (uintmax_t)link_info_bits);
619 	if (lhw->ops->link_info_changed != NULL)
620 		lhw->ops->link_info_changed(hw, vif, conf, link_info_bits);
621 	else if (fallback)
622 		lhw->ops->bss_info_changed(hw, vif, conf, link_info_bits);
623 }
624 
625 /*
626  * This is basically obsolete but one caller.
627  * The functionality is now split between lkpi_80211_mo_link_info_changed() and
628  * lkpi_80211_mo_vif_cfg_changed().  Those functions have a flag whether to call
629  * the (*bss_info_changed) fallback or not.  See lkpi_bss_info_change().
630  */
631 void
632 lkpi_80211_mo_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
633     struct ieee80211_bss_conf *conf, uint64_t bss_changed)
634 {
635 	struct lkpi_hw *lhw;
636 
637 	/* XXX-FINISH all callers for lockdep_assert_wiphy(hw->wiphy); */
638 
639 	lhw = HW_TO_LHW(hw);
640 	if (lhw->ops->bss_info_changed == NULL)
641 		return;
642 
643 	if (bss_changed == 0)
644 		return;
645 
646 	LKPI_80211_TRACE_MO("hw %p vif %p conf %p changed %#jx", hw, vif, conf, (uintmax_t)bss_changed);
647 	lhw->ops->bss_info_changed(hw, vif, conf, bss_changed);
648 }
649 
650 int
651 lkpi_80211_mo_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
652     uint32_t link_id, uint16_t ac, const struct ieee80211_tx_queue_params *txqp)
653 {
654 	struct lkpi_hw *lhw;
655 	int error;
656 
657 	lhw = HW_TO_LHW(hw);
658 	if (lhw->ops->conf_tx == NULL) {
659 		error = EOPNOTSUPP;
660 		goto out;
661 	}
662 
663 	LKPI_80211_TRACE_MO("hw %p vif %p link_id %u ac %u txpq %p",
664 	    hw, vif, link_id, ac, txqp);
665 	error = lhw->ops->conf_tx(hw, vif, link_id, ac, txqp);
666 
667 out:
668 	return (error);
669 }
670 
671 void
672 lkpi_80211_mo_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
673     uint32_t nqueues, bool drop)
674 {
675 	struct lkpi_hw *lhw;
676 
677 	lhw = HW_TO_LHW(hw);
678 	if (lhw->ops->flush == NULL)
679 		return;
680 
681 	LKPI_80211_TRACE_MO("hw %p vif %p nqueues %u drop %d", hw, vif, nqueues, drop);
682 	lhw->ops->flush(hw, vif, nqueues, drop);
683 }
684 
685 void
686 lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
687     struct ieee80211_prep_tx_info *txinfo)
688 {
689 	struct lkpi_hw *lhw;
690 
691 	lhw = HW_TO_LHW(hw);
692 	if (lhw->ops->mgd_prepare_tx == NULL)
693 		return;
694 
695 	LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);
696 	lhw->ops->mgd_prepare_tx(hw, vif, txinfo);
697 }
698 
699 void
700 lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
701     struct ieee80211_prep_tx_info *txinfo)
702 {
703 	struct lkpi_hw *lhw;
704 
705 	lhw = HW_TO_LHW(hw);
706 	if (lhw->ops->mgd_complete_tx == NULL)
707 		return;
708 
709 	LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);
710 	lhw->ops->mgd_complete_tx(hw, vif, txinfo);
711 }
712 
713 void
714 lkpi_80211_mo_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *txctrl,
715     struct sk_buff *skb)
716 {
717 	struct lkpi_hw *lhw;
718 
719 	lhw = HW_TO_LHW(hw);
720 	if (lhw->ops->tx == NULL)
721 		return;
722 
723 	LKPI_80211_TRACE_MO("hw %p txctrl %p skb %p", hw, txctrl, skb);
724 	lhw->ops->tx(hw, txctrl, skb);
725 }
726 
727 void
728 lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
729     bool schedule)
730 {
731 	struct lkpi_hw *lhw;
732 
733 	lhw = HW_TO_LHW(hw);
734 
735 	/* Do the schedule before the check for wake_tx_queue supported! */
736 	if (schedule)
737 		ieee80211_schedule_txq(hw, txq);
738 
739 	if (lhw->ops->wake_tx_queue == NULL)
740 		return;
741 
742 	LKPI_80211_TRACE_MO("hw %p txq %p", hw, txq);
743 	lhw->ops->wake_tx_queue(hw, txq);
744 }
745 
746 void
747 lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw *hw)
748 {
749 	struct lkpi_hw *lhw;
750 
751 	lhw = HW_TO_LHW(hw);
752 	if (lhw->ops->sync_rx_queues == NULL)
753 		return;
754 
755 	LKPI_80211_TRACE_MO("hw %p", hw);
756 	lhw->ops->sync_rx_queues(hw);
757 }
758 
759 void
760 lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw *hw,
761     struct ieee80211_vif *vif, struct ieee80211_sta *sta)
762 {
763 	struct lkpi_hw *lhw;
764 
765 	lhw = HW_TO_LHW(hw);
766 	if (lhw->ops->sta_pre_rcu_remove == NULL)
767 		return;
768 
769 	LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
770 	lhw->ops->sta_pre_rcu_remove(hw, vif, sta);
771 }
772 
773 void
774 lkpi_80211_mo_link_sta_rc_update(struct ieee80211_hw *hw,
775     struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta,
776     enum ieee80211_rate_control_changed_flags rc_changed)
777 {
778 	struct lkpi_hw *lhw;
779 
780 	lhw = HW_TO_LHW(hw);
781 	if (lhw->ops->link_sta_rc_update == NULL)
782 		return;
783 
784 	LKPI_80211_TRACE_MO("hw %p vif %p link_sta %p rc_changed %#010x",
785 	    hw, vif, link_sta, rc_changed);
786 	lhw->ops->link_sta_rc_update(hw, vif, link_sta, rc_changed);
787 }
788 
789 int
790 lkpi_80211_mo_set_bitrate_mask(struct ieee80211_hw *hw,
791     struct ieee80211_vif *vif, const struct cfg80211_bitrate_mask *br_mask)
792 {
793 	struct lkpi_hw *lhw;
794 	int error;
795 
796 	might_sleep();
797 	lockdep_assert_wiphy(hw->wiphy);
798 
799 	lhw = HW_TO_LHW(hw);
800 	if (lhw->ops->set_bitrate_mask == NULL) {
801 		error = EOPNOTSUPP;
802 		goto out;
803 	}
804 
805 	LKPI_80211_TRACE_MO("hw %p vif %p br_mask %p",
806 	    hw, vif, br_mask);
807 	error = lhw->ops->set_bitrate_mask(hw, vif, br_mask);
808 
809 out:
810 	return (error);
811 }
812 
813 int
814 lkpi_80211_mo_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
815     struct ieee80211_vif *vif, struct ieee80211_sta *sta,
816     struct ieee80211_key_conf *kc)
817 {
818 	struct lkpi_hw *lhw;
819 	int error;
820 
821 	lockdep_assert_wiphy(hw->wiphy);
822 
823 	lhw = HW_TO_LHW(hw);
824 	if (lhw->ops->set_key == NULL) {
825 		error = EOPNOTSUPP;
826 		goto out;
827 	}
828 
829 	/*
830 	 * Drivers will apply different logic depending on sta being set
831 	 * here or not and that depends on whether we have an address or
832 	 * not.  wpa_spplucoant::driver_bsd::bsd_set_key() will set a
833 	 * broadcast address if we do not have one;  further up in
834 	 * wpa_supplicant something presumably sets the broadcast address
835 	 * for group keys as well.
836 	 * We have to "undo" this here and set sta to NULL to avoid
837 	 * problems with hw_crypto in various drivers.
838 	 * We do this here so all set_key calls for (SET_KEY and DISABLE_KEY)
839 	 * are covered.
840 	 */
841 	MPASS(kc->_k != NULL);
842 	if (is_broadcast_ether_addr(kc->_k->wk_macaddr))
843 		sta = NULL;
844 
845 	LKPI_80211_TRACE_MO("hw %p cmd %d vif %p sta %p kc %p", hw, cmd, vif, sta, kc);
846 	error = lhw->ops->set_key(hw, cmd, vif, sta, kc);
847 
848 out:
849 	return (error);
850 }
851 
852 void
853 lkpi_80211_mo_sta_set_decap_offload(struct ieee80211_hw *hw,
854     struct ieee80211_vif *vif, struct ieee80211_sta *sta,
855     bool enable)
856 {
857 	struct lkpi_hw *lhw;
858 
859 	lockdep_assert_wiphy(hw->wiphy);
860 
861 	lhw = HW_TO_LHW(hw);
862 	if (lhw->ops->sta_set_decap_offload == NULL)
863 		return;
864 
865 	LKPI_80211_TRACE_MO("hw %p vif %p sta %p enable %d", hw, vif, sta, enable);
866 	lhw->ops->sta_set_decap_offload(hw, vif, sta, enable);
867 }
868 
869 int
870 lkpi_80211_mo_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
871     struct ieee80211_ampdu_params *params)
872 {
873 	struct lkpi_hw *lhw;
874 	int error;
875 
876 	lhw = HW_TO_LHW(hw);
877 	if (lhw->ops->ampdu_action == NULL) {
878 		error = EOPNOTSUPP;
879 		goto out;
880 	}
881 
882 	LKPI_80211_TRACE_MO("hw %p vif %p params %p { %p, %d, %u, %u, %u, %u, %d }",
883 	    hw, vif, params, params->sta, params->action, params->buf_size,
884 	    params->timeout, params->ssn, params->tid, params->amsdu);
885 	error = lhw->ops->ampdu_action(hw, vif, params);
886 
887 out:
888 	return (error);
889 }
890 
891 int
892 lkpi_80211_mo_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
893     struct ieee80211_sta *sta, struct station_info *sinfo)
894 {
895 	struct lkpi_hw *lhw;
896 	struct lkpi_sta *lsta;
897 	int error;
898 
899 	lhw = HW_TO_LHW(hw);
900 	if (lhw->ops->sta_statistics == NULL) {
901 		error = EOPNOTSUPP;
902 		goto out;
903 	}
904 
905 	lsta = STA_TO_LSTA(sta);
906 	if (!lsta->added_to_drv) {
907 		error = EEXIST;
908 		goto out;
909 	}
910 
911 	lockdep_assert_wiphy(hw->wiphy);
912 
913 	LKPI_80211_TRACE_MO("hw %p vif %p sta %p sinfo %p", hw, vif, sta, sinfo);
914 	lhw->ops->sta_statistics(hw, vif, sta, sinfo);
915 	error = 0;
916 
917 out:
918 	return (error);
919 }
920 
921 int
922 lkpi_80211_mo_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
923 {
924 	struct lkpi_hw *lhw;
925 	int error;
926 
927 	might_sleep();
928 	lockdep_assert_wiphy(hw->wiphy);
929 
930 	lhw = HW_TO_LHW(hw);
931 	if (lhw->ops->suspend == NULL) {
932 		error = EOPNOTSUPP;
933 		goto out;
934 	}
935 
936 	LKPI_80211_TRACE_MO("hw %p wowlan %p", hw, wowlan);
937 	error = lhw->ops->suspend(hw, wowlan);
938 
939 out:
940 	return (error);
941 }
942 
943 int
944 lkpi_80211_mo_resume(struct ieee80211_hw *hw)
945 {
946 	struct lkpi_hw *lhw;
947 	int error;
948 
949 	might_sleep();
950 	lockdep_assert_wiphy(hw->wiphy);
951 
952 	lhw = HW_TO_LHW(hw);
953 	if (lhw->ops->resume == NULL) {
954 		error = EOPNOTSUPP;
955 		goto out;
956 	}
957 
958 	LKPI_80211_TRACE_MO("hw %p", hw);
959 	error = lhw->ops->resume(hw);
960 
961 out:
962 	return (error);
963 }
964 
965 int
966 lkpi_80211_mo_set_wakeup(struct ieee80211_hw *hw, bool enable)
967 {
968 	struct lkpi_hw *lhw;
969 	int error;
970 
971 	might_sleep();
972 	lockdep_assert_wiphy(hw->wiphy);
973 
974 	lhw = HW_TO_LHW(hw);
975 	if (lhw->ops->set_wakeup == NULL) {
976 		error = EOPNOTSUPP;
977 		goto out;
978 	}
979 
980 	LKPI_80211_TRACE_MO("hw %p enable %d", hw, enable);
981 	lhw->ops->set_wakeup(hw, enable);
982 	error = 0;
983 
984 out:
985 	return (error);
986 }
987 
988 int
989 lkpi_80211_mo_set_rekey_data(struct ieee80211_hw *hw,
990     struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *grd)
991 {
992 	struct lkpi_hw *lhw;
993 	int error;
994 
995 	might_sleep();
996 	lockdep_assert_wiphy(hw->wiphy);
997 
998 	lhw = HW_TO_LHW(hw);
999 	if (lhw->ops->set_rekey_data == NULL) {
1000 		error = EOPNOTSUPP;
1001 		goto out;
1002 	}
1003 
1004 	LKPI_80211_TRACE_MO("hw %p vif %p grd %p", hw, vif, grd);
1005 	lhw->ops->set_rekey_data(hw, vif, grd);
1006 	error = 0;
1007 
1008 out:
1009 	return (error);
1010 }
1011 
1012 int
1013 lkpi_80211_mo_set_default_unicast_key(struct ieee80211_hw *hw,
1014     struct ieee80211_vif *vif, int idx)
1015 {
1016 	struct lkpi_hw *lhw;
1017 	int error;
1018 
1019 	might_sleep();
1020 	lockdep_assert_wiphy(hw->wiphy);
1021 
1022 	lhw = HW_TO_LHW(hw);
1023 	if (lhw->ops->set_default_unicast_key == NULL) {
1024 		error = EOPNOTSUPP;
1025 		goto out;
1026 	}
1027 
1028 	LKPI_80211_TRACE_MO("hw %p vif %p idx %d", hw, vif, idx);
1029 	lhw->ops->set_default_unicast_key(hw, vif, idx);
1030 	error = 0;
1031 
1032 out:
1033 	return (error);
1034 }
1035 
1036