xref: /freebsd/sys/compat/linuxkpi/common/src/linux_80211_macops.c (revision 897cf423a39474096dc699f7b9d173e4a97d3510)
1 /*-
2  * Copyright (c) 2021-2022 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
lkpi_80211_mo_start(struct ieee80211_hw * hw)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
lkpi_80211_mo_stop(struct ieee80211_hw * hw,bool suspend)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
lkpi_80211_mo_get_antenna(struct ieee80211_hw * hw,u32 * txs,u32 * rxs)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 	error = lhw->ops->get_antenna(hw, txs, rxs);
106 
107 out:
108 	return (error);
109 }
110 
111 int
lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw * hw,uint32_t frag_th)112 lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw *hw, uint32_t frag_th)
113 {
114 	struct lkpi_hw *lhw;
115 	int error;
116 
117 	lhw = HW_TO_LHW(hw);
118 	if (lhw->ops->set_frag_threshold == NULL) {
119 		error = EOPNOTSUPP;
120 		goto out;
121 	}
122 
123 	LKPI_80211_TRACE_MO("hw %p frag_th %u", hw, frag_th);
124 	error = lhw->ops->set_frag_threshold(hw, frag_th);
125 
126 out:
127 	return (error);
128 }
129 
130 int
lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw * hw,uint32_t rts_th)131 lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw *hw, uint32_t rts_th)
132 {
133 	struct lkpi_hw *lhw;
134 	int error;
135 
136 	lhw = HW_TO_LHW(hw);
137 	if (lhw->ops->set_rts_threshold == NULL) {
138 		error = EOPNOTSUPP;
139 		goto out;
140 	}
141 
142 	LKPI_80211_TRACE_MO("hw %p rts_th %u", hw, rts_th);
143 	error = lhw->ops->set_rts_threshold(hw, rts_th);
144 
145 out:
146 	return (error);
147 }
148 
149 
150 int
lkpi_80211_mo_add_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)151 lkpi_80211_mo_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
152 {
153 	struct lkpi_hw *lhw;
154 	struct lkpi_vif *lvif;
155 	int error;
156 
157 	lhw = HW_TO_LHW(hw);
158 	if (lhw->ops->add_interface == NULL) {
159 		error = EOPNOTSUPP;
160 		goto out;
161 	}
162 
163 	lvif = VIF_TO_LVIF(vif);
164 	LKPI_80211_LVIF_LOCK(lvif);
165 	if (lvif->added_to_drv) {
166 		LKPI_80211_LVIF_UNLOCK(lvif);
167 		/* Trying to add twice is an error. */
168 		error = EEXIST;
169 		goto out;
170 	}
171 	LKPI_80211_LVIF_UNLOCK(lvif);
172 
173 	LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
174 	error = lhw->ops->add_interface(hw, vif);
175 	if (error == 0) {
176 		LKPI_80211_LVIF_LOCK(lvif);
177 		lvif->added_to_drv = true;
178 		LKPI_80211_LVIF_UNLOCK(lvif);
179 	}
180 
181 out:
182 	return (error);
183 }
184 
185 void
lkpi_80211_mo_remove_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)186 lkpi_80211_mo_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
187 {
188 	struct lkpi_hw *lhw;
189 	struct lkpi_vif *lvif;
190 
191 	lhw = HW_TO_LHW(hw);
192 	if (lhw->ops->remove_interface == NULL)
193 		return;
194 
195 	lvif = VIF_TO_LVIF(vif);
196 	LKPI_80211_LVIF_LOCK(lvif);
197 	if (!lvif->added_to_drv) {
198 		LKPI_80211_LVIF_UNLOCK(lvif);
199 		return;
200 	}
201 	LKPI_80211_LVIF_UNLOCK(lvif);
202 
203 	LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
204 	lhw->ops->remove_interface(hw, vif);
205 	LKPI_80211_LVIF_LOCK(lvif);
206 	lvif->added_to_drv = false;
207 	LKPI_80211_LVIF_UNLOCK(lvif);
208 }
209 
210 
211 int
lkpi_80211_mo_hw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_scan_request * sr)212 lkpi_80211_mo_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
213     struct ieee80211_scan_request *sr)
214 {
215 	struct lkpi_hw *lhw;
216 	int error;
217 
218 	/*
219 	 * MUST NOT return EPERM as that is a "magic number 1" based on rtw88
220 	 * driver indicating hw_scan is not supported despite the ops call
221 	 * being available.
222 	 */
223 
224 	lhw = HW_TO_LHW(hw);
225 	if (lhw->ops->hw_scan == NULL) {
226 		/* Return magic number to use sw scan. */
227 		error = 1;
228 		goto out;
229 	}
230 
231 	LKPI_80211_TRACE_MO("CALLING hw %p vif %p sr %p", hw, vif, sr);
232 	error = lhw->ops->hw_scan(hw, vif, sr);
233 	LKPI_80211_TRACE_MO("RETURNING hw %p vif %p sr %p error %d", hw, vif, sr, error);
234 
235 out:
236 	return (error);
237 }
238 
239 void
lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif)240 lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
241 {
242 	struct lkpi_hw *lhw;
243 
244 	lhw = HW_TO_LHW(hw);
245 	if (lhw->ops->cancel_hw_scan == NULL)
246 		return;
247 
248 	LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
249 	lhw->ops->cancel_hw_scan(hw, vif);
250 }
251 
252 void
lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw * hw,struct ieee80211_vif * vif)253 lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
254 {
255 	struct lkpi_hw *lhw;
256 
257 	lhw = HW_TO_LHW(hw);
258 	if (lhw->ops->sw_scan_complete == NULL)
259 		return;
260 
261 	LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
262 	lhw->ops->sw_scan_complete(hw, vif);
263 	lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
264 }
265 
266 void
lkpi_80211_mo_sw_scan_start(struct ieee80211_hw * hw,struct ieee80211_vif * vif,const u8 * addr)267 lkpi_80211_mo_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
268     const u8 *addr)
269 {
270 	struct lkpi_hw *lhw;
271 
272 	lhw = HW_TO_LHW(hw);
273 	if (lhw->ops->sw_scan_start == NULL)
274 		return;
275 
276 	LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
277 	lhw->ops->sw_scan_start(hw, vif, addr);
278 }
279 
280 
281 /*
282  * We keep the Linux type here;  it really is an uintptr_t.
283  */
284 u64
lkpi_80211_mo_prepare_multicast(struct ieee80211_hw * hw,struct netdev_hw_addr_list * mc_list)285 lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *hw,
286     struct netdev_hw_addr_list *mc_list)
287 {
288 	struct lkpi_hw *lhw;
289 	u64 ptr;
290 
291 	lhw = HW_TO_LHW(hw);
292 	if (lhw->ops->prepare_multicast == NULL)
293 		return (0);
294 
295 	LKPI_80211_TRACE_MO("hw %p mc_list %p", hw, mc_list);
296 	ptr = lhw->ops->prepare_multicast(hw, mc_list);
297 	return (ptr);
298 }
299 
300 void
lkpi_80211_mo_configure_filter(struct ieee80211_hw * hw,unsigned int changed_flags,unsigned int * total_flags,u64 mc_ptr)301 lkpi_80211_mo_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
302     unsigned int *total_flags, u64 mc_ptr)
303 {
304 	struct lkpi_hw *lhw;
305 
306 	lhw = HW_TO_LHW(hw);
307 	if (lhw->ops->configure_filter == NULL)
308 		return;
309 
310 	if (mc_ptr == 0)
311 		return;
312 
313 	LKPI_80211_TRACE_MO("hw %p changed_flags %#x total_flags %p mc_ptr %ju", hw, changed_flags, total_flags, (uintmax_t)mc_ptr);
314 	lhw->ops->configure_filter(hw, changed_flags, total_flags, mc_ptr);
315 }
316 
317 
318 /*
319  * So far we only called sta_{add,remove} as an alternative to sta_state.
320  * Let's keep the implementation simpler and hide sta_{add,remove} under the
321  * hood here calling them if state_state is not available from mo_sta_state.
322  */
323 static int
lkpi_80211_mo_sta_add(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)324 lkpi_80211_mo_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
325     struct ieee80211_sta *sta)
326 {
327 	struct lkpi_hw *lhw;
328 	struct lkpi_sta *lsta;
329 	int error;
330 
331 	lhw = HW_TO_LHW(hw);
332 	if (lhw->ops->sta_add == NULL) {
333 		error = EOPNOTSUPP;
334 		goto out;
335 	}
336 
337 	lsta = STA_TO_LSTA(sta);
338 	if (lsta->added_to_drv) {
339 		error = EEXIST;
340 		goto out;
341 	}
342 
343 	LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
344 	error = lhw->ops->sta_add(hw, vif, sta);
345 	if (error == 0)
346 		lsta->added_to_drv = true;
347 
348 out:
349 	return error;
350 }
351 
352 static int
lkpi_80211_mo_sta_remove(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)353 lkpi_80211_mo_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
354     struct ieee80211_sta *sta)
355 {
356 	struct lkpi_hw *lhw;
357 	struct lkpi_sta *lsta;
358 	int error;
359 
360 	lhw = HW_TO_LHW(hw);
361 	if (lhw->ops->sta_remove == NULL) {
362 		error = EOPNOTSUPP;
363 		goto out;
364 	}
365 
366 	lsta = STA_TO_LSTA(sta);
367 	if (!lsta->added_to_drv) {
368 		/* If we never added the sta, do not complain on cleanup. */
369 		error = 0;
370 		goto out;
371 	}
372 
373 	LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
374 	error = lhw->ops->sta_remove(hw, vif, sta);
375 	if (error == 0)
376 		lsta->added_to_drv = false;
377 
378 out:
379 	return error;
380 }
381 
382 int
lkpi_80211_mo_sta_state(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct lkpi_sta * lsta,enum ieee80211_sta_state nstate)383 lkpi_80211_mo_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
384     struct lkpi_sta *lsta, enum ieee80211_sta_state nstate)
385 {
386 	struct lkpi_hw *lhw;
387 	struct ieee80211_sta *sta;
388 	int error;
389 
390 	lhw = HW_TO_LHW(hw);
391 	sta = LSTA_TO_STA(lsta);
392 	if (lhw->ops->sta_state != NULL) {
393 		LKPI_80211_TRACE_MO("hw %p vif %p sta %p nstate %d", hw, vif, sta, nstate);
394 		error = lhw->ops->sta_state(hw, vif, sta, lsta->state, nstate);
395 		if (error == 0) {
396 			if (nstate == IEEE80211_STA_NOTEXIST)
397 				lsta->added_to_drv = false;
398 			else
399 				lsta->added_to_drv = true;
400 			lsta->state = nstate;
401 		}
402 		goto out;
403 	}
404 
405 	/* XXX-BZ is the change state AUTH or ASSOC here? */
406 	if (lsta->state < IEEE80211_STA_ASSOC && nstate == IEEE80211_STA_ASSOC) {
407 		error = lkpi_80211_mo_sta_add(hw, vif, sta);
408 		if (error == 0)
409 			lsta->added_to_drv = true;
410 	} else if (lsta->state >= IEEE80211_STA_ASSOC &&
411 	    nstate < IEEE80211_STA_ASSOC) {
412 		error = lkpi_80211_mo_sta_remove(hw, vif, sta);
413 		if (error == 0)
414 			lsta->added_to_drv = false;
415 	} else
416 		/* Nothing to do. */
417 		error = 0;
418 	if (error == 0)
419 		lsta->state = nstate;
420 
421 out:
422 	/* XXX-BZ should we manage state in here? */
423 	return (error);
424 }
425 
426 int
lkpi_80211_mo_config(struct ieee80211_hw * hw,uint32_t changed)427 lkpi_80211_mo_config(struct ieee80211_hw *hw, uint32_t changed)
428 {
429 	struct lkpi_hw *lhw;
430 	int error;
431 
432 	lhw = HW_TO_LHW(hw);
433 	if (lhw->ops->config == NULL) {
434 		error = EOPNOTSUPP;
435 		goto out;
436 	}
437 
438 	LKPI_80211_TRACE_MO("hw %p changed %u", hw, changed);
439 	error = lhw->ops->config(hw, changed);
440 
441 out:
442 	return (error);
443 }
444 
445 
446 int
lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * conf,struct ieee80211_chanctx_conf * chanctx_conf)447 lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
448     struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf)
449 {
450 	struct lkpi_hw *lhw;
451 	int error;
452 
453 	lhw = HW_TO_LHW(hw);
454 	if (lhw->ops->assign_vif_chanctx == NULL) {
455 		error = EOPNOTSUPP;
456 		goto out;
457 	}
458 
459 	LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p",
460 	    hw, vif, conf, chanctx_conf);
461 	error = lhw->ops->assign_vif_chanctx(hw, vif, conf, chanctx_conf);
462 	if (error == 0)
463 		vif->bss_conf.chanctx_conf = chanctx_conf;
464 
465 out:
466 	return (error);
467 }
468 
469 void
lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * conf,struct ieee80211_chanctx_conf * chanctx_conf)470 lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
471     struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf)
472 {
473 	struct lkpi_hw *lhw;
474 
475 	might_sleep();
476 	lockdep_assert_wiphy(hw->wiphy);
477 
478 	lhw = HW_TO_LHW(hw);
479 	if (lhw->ops->unassign_vif_chanctx == NULL)
480 		return;
481 
482 	if (chanctx_conf == NULL)
483 		return;
484 
485 	LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p",
486 	    hw, vif, conf, chanctx_conf);
487 	lhw->ops->unassign_vif_chanctx(hw, vif, conf, chanctx_conf);
488 }
489 
490 
491 int
lkpi_80211_mo_add_chanctx(struct ieee80211_hw * hw,struct ieee80211_chanctx_conf * chanctx_conf)492 lkpi_80211_mo_add_chanctx(struct ieee80211_hw *hw,
493     struct ieee80211_chanctx_conf *chanctx_conf)
494 {
495 	struct lkpi_hw *lhw;
496 	struct lkpi_chanctx *lchanctx;
497 	int error;
498 
499 	lhw = HW_TO_LHW(hw);
500 	if (lhw->ops->add_chanctx == NULL) {
501 		error = EOPNOTSUPP;
502 		goto out;
503 	}
504 
505 	LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);
506 	error = lhw->ops->add_chanctx(hw, chanctx_conf);
507 	if (error == 0) {
508 		lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);
509 		lchanctx->added_to_drv = true;
510 	}
511 
512 out:
513 	return (error);
514 }
515 
516 void
lkpi_80211_mo_change_chanctx(struct ieee80211_hw * hw,struct ieee80211_chanctx_conf * chanctx_conf,uint32_t changed)517 lkpi_80211_mo_change_chanctx(struct ieee80211_hw *hw,
518     struct ieee80211_chanctx_conf *chanctx_conf, uint32_t changed)
519 {
520 	struct lkpi_hw *lhw;
521 
522 	lhw = HW_TO_LHW(hw);
523 	if (lhw->ops->change_chanctx == NULL)
524 		return;
525 
526 	LKPI_80211_TRACE_MO("hw %p chanctx_conf %p changed %u", hw, chanctx_conf, changed);
527 	lhw->ops->change_chanctx(hw, chanctx_conf, changed);
528 }
529 
530 void
lkpi_80211_mo_remove_chanctx(struct ieee80211_hw * hw,struct ieee80211_chanctx_conf * chanctx_conf)531 lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *hw,
532     struct ieee80211_chanctx_conf *chanctx_conf)
533 {
534 	struct lkpi_hw *lhw;
535 	struct lkpi_chanctx *lchanctx;
536 
537 	lhw = HW_TO_LHW(hw);
538 	if (lhw->ops->remove_chanctx == NULL)
539 		return;
540 
541 	LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);
542 	lhw->ops->remove_chanctx(hw, chanctx_conf);
543 	lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);
544 	lchanctx->added_to_drv = false;
545 }
546 
547 void
lkpi_80211_mo_bss_info_changed(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * conf,uint64_t changed)548 lkpi_80211_mo_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
549     struct ieee80211_bss_conf *conf, uint64_t changed)
550 {
551 	struct lkpi_hw *lhw;
552 
553 	lhw = HW_TO_LHW(hw);
554 	if (lhw->ops->link_info_changed == NULL &&
555 	    lhw->ops->bss_info_changed == NULL)
556 		return;
557 
558 	if (changed == 0)
559 		return;
560 
561 	LKPI_80211_TRACE_MO("hw %p vif %p conf %p changed %#jx", hw, vif, conf, (uintmax_t)changed);
562 	if (lhw->ops->link_info_changed != NULL)
563 		lhw->ops->link_info_changed(hw, vif, conf, changed);
564 	else
565 		lhw->ops->bss_info_changed(hw, vif, conf, changed);
566 }
567 
568 int
lkpi_80211_mo_conf_tx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,uint32_t link_id,uint16_t ac,const struct ieee80211_tx_queue_params * txqp)569 lkpi_80211_mo_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
570     uint32_t link_id, uint16_t ac, const struct ieee80211_tx_queue_params *txqp)
571 {
572 	struct lkpi_hw *lhw;
573 	int error;
574 
575 	lhw = HW_TO_LHW(hw);
576 	if (lhw->ops->conf_tx == NULL) {
577 		error = EOPNOTSUPP;
578 		goto out;
579 	}
580 
581 	LKPI_80211_TRACE_MO("hw %p vif %p link_id %u ac %u txpq %p",
582 	    hw, vif, link_id, ac, txqp);
583 	error = lhw->ops->conf_tx(hw, vif, link_id, ac, txqp);
584 
585 out:
586 	return (error);
587 }
588 
589 void
lkpi_80211_mo_flush(struct ieee80211_hw * hw,struct ieee80211_vif * vif,uint32_t nqueues,bool drop)590 lkpi_80211_mo_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
591     uint32_t nqueues, bool drop)
592 {
593 	struct lkpi_hw *lhw;
594 
595 	lhw = HW_TO_LHW(hw);
596 	if (lhw->ops->flush == NULL)
597 		return;
598 
599 	LKPI_80211_TRACE_MO("hw %p vif %p nqueues %u drop %d", hw, vif, nqueues, drop);
600 	lhw->ops->flush(hw, vif, nqueues, drop);
601 }
602 
603 void
lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_prep_tx_info * txinfo)604 lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
605     struct ieee80211_prep_tx_info *txinfo)
606 {
607 	struct lkpi_hw *lhw;
608 
609 	lhw = HW_TO_LHW(hw);
610 	if (lhw->ops->mgd_prepare_tx == NULL)
611 		return;
612 
613 	LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);
614 	lhw->ops->mgd_prepare_tx(hw, vif, txinfo);
615 }
616 
617 void
lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_prep_tx_info * txinfo)618 lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
619     struct ieee80211_prep_tx_info *txinfo)
620 {
621 	struct lkpi_hw *lhw;
622 
623 	lhw = HW_TO_LHW(hw);
624 	if (lhw->ops->mgd_complete_tx == NULL)
625 		return;
626 
627 	LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);
628 	lhw->ops->mgd_complete_tx(hw, vif, txinfo);
629 }
630 
631 void
lkpi_80211_mo_tx(struct ieee80211_hw * hw,struct ieee80211_tx_control * txctrl,struct sk_buff * skb)632 lkpi_80211_mo_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *txctrl,
633     struct sk_buff *skb)
634 {
635 	struct lkpi_hw *lhw;
636 
637 	lhw = HW_TO_LHW(hw);
638 	if (lhw->ops->tx == NULL)
639 		return;
640 
641 	LKPI_80211_TRACE_MO("hw %p txctrl %p skb %p", hw, txctrl, skb);
642 	lhw->ops->tx(hw, txctrl, skb);
643 }
644 
645 void
lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw * hw,struct ieee80211_txq * txq)646 lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
647 {
648 	struct lkpi_hw *lhw;
649 
650 	lhw = HW_TO_LHW(hw);
651 	if (lhw->ops->wake_tx_queue == NULL)
652 		return;
653 
654 	LKPI_80211_TRACE_MO("hw %p txq %p", hw, txq);
655 	lhw->ops->wake_tx_queue(hw, txq);
656 }
657 
658 void
lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw * hw)659 lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw *hw)
660 {
661 	struct lkpi_hw *lhw;
662 
663 	lhw = HW_TO_LHW(hw);
664 	if (lhw->ops->sync_rx_queues == NULL)
665 		return;
666 
667 	LKPI_80211_TRACE_MO("hw %p", hw);
668 	lhw->ops->sync_rx_queues(hw);
669 }
670 
671 void
lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)672 lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw *hw,
673     struct ieee80211_vif *vif, struct ieee80211_sta *sta)
674 {
675 	struct lkpi_hw *lhw;
676 
677 	lhw = HW_TO_LHW(hw);
678 	if (lhw->ops->sta_pre_rcu_remove == NULL)
679 		return;
680 
681 	LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
682 	lhw->ops->sta_pre_rcu_remove(hw, vif, sta);
683 }
684 
685 int
lkpi_80211_mo_set_key(struct ieee80211_hw * hw,enum set_key_cmd cmd,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * kc)686 lkpi_80211_mo_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
687     struct ieee80211_vif *vif, struct ieee80211_sta *sta,
688     struct ieee80211_key_conf *kc)
689 {
690 	struct lkpi_hw *lhw;
691 	int error;
692 
693 	lockdep_assert_wiphy(hw->wiphy);
694 
695 	lhw = HW_TO_LHW(hw);
696 	if (lhw->ops->set_key == NULL) {
697 		error = EOPNOTSUPP;
698 		goto out;
699 	}
700 
701 	LKPI_80211_TRACE_MO("hw %p cmd %d vif %p sta %p kc %p", hw, cmd, vif, sta, kc);
702 	error = lhw->ops->set_key(hw, cmd, vif, sta, kc);
703 
704 out:
705 	return (error);
706 }
707 
708 int
lkpi_80211_mo_ampdu_action(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_ampdu_params * params)709 lkpi_80211_mo_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
710     struct ieee80211_ampdu_params *params)
711 {
712 	struct lkpi_hw *lhw;
713 	int error;
714 
715 	lhw = HW_TO_LHW(hw);
716 	if (lhw->ops->ampdu_action == NULL) {
717 		error = EOPNOTSUPP;
718 		goto out;
719 	}
720 
721 	LKPI_80211_TRACE_MO("hw %p vif %p params %p { %p, %d, %u, %u, %u, %u, %d }",
722 	    hw, vif, params, params->sta, params->action, params->buf_size,
723 	    params->timeout, params->ssn, params->tid, params->amsdu);
724 	error = lhw->ops->ampdu_action(hw, vif, params);
725 
726 out:
727 	return (error);
728 }
729 
730 int
lkpi_80211_mo_sta_statistics(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct station_info * sinfo)731 lkpi_80211_mo_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
732     struct ieee80211_sta *sta, struct station_info *sinfo)
733 {
734 	struct lkpi_hw *lhw;
735 	struct lkpi_sta *lsta;
736 	int error;
737 
738 	lhw = HW_TO_LHW(hw);
739 	if (lhw->ops->sta_statistics == NULL) {
740 		error = EOPNOTSUPP;
741 		goto out;
742 	}
743 
744 	lsta = STA_TO_LSTA(sta);
745 	if (!lsta->added_to_drv) {
746 		error = EEXIST;
747 		goto out;
748 	}
749 
750 	lockdep_assert_wiphy(hw->wiphy);
751 
752 	LKPI_80211_TRACE_MO("hw %p vif %p sta %p sinfo %p", hw, vif, sta, sinfo);
753 	lhw->ops->sta_statistics(hw, vif, sta, sinfo);
754 	error = 0;
755 
756 out:
757 	return (error);
758 }
759