xref: /freebsd/sys/compat/linuxkpi/common/src/linux_80211_macops.c (revision 994297b01b98816bea1abf45ae4bac1bc69ee7a0)
1 /*-
2  * Copyright (c) 2021 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/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/kernel.h>
35 #include <sys/errno.h>
36 
37 #define	LINUXKPI_NET80211
38 #include <net/mac80211.h>
39 
40 #include "linux_80211.h"
41 
42 int
43 lkpi_80211_mo_start(struct ieee80211_hw *hw)
44 {
45 	struct lkpi_hw *lhw;
46 	int error;
47 
48 	lhw = HW_TO_LHW(hw);
49 	if (lhw->ops->start == NULL) {
50 		error = EOPNOTSUPP;
51 		goto out;
52 	}
53 
54 	if ((lhw->sc_flags & LKPI_MAC80211_DRV_STARTED)) {
55 		/* Trying to start twice is an error. */
56 		error = EEXIST;
57 		goto out;
58 	}
59 	error = lhw->ops->start(hw);
60 	if (error == 0)
61 		lhw->sc_flags |= LKPI_MAC80211_DRV_STARTED;
62 
63 out:
64 	return (error);
65 }
66 
67 void
68 lkpi_80211_mo_stop(struct ieee80211_hw *hw)
69 {
70 	struct lkpi_hw *lhw;
71 
72 	lhw = HW_TO_LHW(hw);
73 	if (lhw->ops->stop == NULL)
74 		return;
75 
76 	lhw->ops->stop(hw);
77 	lhw->sc_flags &= ~LKPI_MAC80211_DRV_STARTED;
78 }
79 
80 int
81 lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw *hw, uint32_t frag_th)
82 {
83 	struct lkpi_hw *lhw;
84 	int error;
85 
86 	lhw = HW_TO_LHW(hw);
87 	if (lhw->ops->set_frag_threshold == NULL) {
88 		error = EOPNOTSUPP;
89 		goto out;
90 	}
91 
92 	error = lhw->ops->set_frag_threshold(hw, frag_th);
93 
94 out:
95 	return (error);
96 }
97 
98 int
99 lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw *hw, uint32_t rts_th)
100 {
101 	struct lkpi_hw *lhw;
102 	int error;
103 
104 	lhw = HW_TO_LHW(hw);
105 	if (lhw->ops->set_rts_threshold == NULL) {
106 		error = EOPNOTSUPP;
107 		goto out;
108 	}
109 
110 	error = lhw->ops->set_rts_threshold(hw, rts_th);
111 
112 out:
113 	return (error);
114 }
115 
116 
117 int
118 lkpi_80211_mo_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
119 {
120 	struct lkpi_hw *lhw;
121 	struct lkpi_vif *lvif;
122 	int error;
123 
124 	lhw = HW_TO_LHW(hw);
125 	if (lhw->ops->add_interface == NULL) {
126 		error = EOPNOTSUPP;
127 		goto out;
128 	}
129 
130 	lvif = VIF_TO_LVIF(vif);
131 	LKPI_80211_LVIF_LOCK(lvif);
132 	if (lvif->added_to_drv) {
133 		LKPI_80211_LVIF_UNLOCK(lvif);
134 		/* Trying to add twice is an error. */
135 		error = EEXIST;
136 		goto out;
137 	}
138 	LKPI_80211_LVIF_UNLOCK(lvif);
139 
140 	error = lhw->ops->add_interface(hw, vif);
141 	if (error == 0) {
142 		LKPI_80211_LVIF_LOCK(lvif);
143 		lvif->added_to_drv = true;
144 		LKPI_80211_LVIF_UNLOCK(lvif);
145 	}
146 
147 out:
148 	return (error);
149 }
150 
151 void
152 lkpi_80211_mo_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
153 {
154 	struct lkpi_hw *lhw;
155 	struct lkpi_vif *lvif;
156 
157 	lhw = HW_TO_LHW(hw);
158 	if (lhw->ops->remove_interface == NULL)
159 		return;
160 
161 	lvif = VIF_TO_LVIF(vif);
162 	LKPI_80211_LVIF_LOCK(lvif);
163 	if (!lvif->added_to_drv) {
164 		LKPI_80211_LVIF_UNLOCK(lvif);
165 		return;
166 	}
167 	LKPI_80211_LVIF_UNLOCK(lvif);
168 
169 	lhw->ops->remove_interface(hw, vif);
170 	LKPI_80211_LVIF_LOCK(lvif);
171 	lvif->added_to_drv = false;
172 	LKPI_80211_LVIF_UNLOCK(lvif);
173 }
174 
175 
176 int
177 lkpi_80211_mo_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
178     struct ieee80211_scan_request *sr)
179 {
180 	struct lkpi_hw *lhw;
181 	int error;
182 
183 	lhw = HW_TO_LHW(hw);
184 	if (lhw->ops->hw_scan == NULL) {
185 		/* XXX-BZ can we hide other scans like we can for sta_add..? */
186 		error = EOPNOTSUPP;
187 		goto out;
188 	}
189 
190 	lhw->scan_flags |= LKPI_SCAN_RUNNING;
191 	error = lhw->ops->hw_scan(hw, vif, sr);
192 	if (error != 0)
193 		lhw->scan_flags &= ~LKPI_SCAN_RUNNING;
194 
195 out:
196 	return (error);
197 }
198 
199 void
200 lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
201 {
202 	struct lkpi_hw *lhw;
203 
204 	lhw = HW_TO_LHW(hw);
205 	if (lhw->ops->cancel_hw_scan == NULL)
206 		return;
207 
208 	lhw->ops->cancel_hw_scan(hw, vif);
209 }
210 
211 void
212 lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
213 {
214 	struct lkpi_hw *lhw;
215 
216 	lhw = HW_TO_LHW(hw);
217 	if (lhw->ops->sw_scan_complete == NULL)
218 		return;
219 
220 	lhw->ops->sw_scan_complete(hw, vif);
221 	lhw->scan_flags &= ~LKPI_SCAN_RUNNING;
222 }
223 
224 void
225 lkpi_80211_mo_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
226     const u8 *addr)
227 {
228 	struct lkpi_hw *lhw;
229 
230 	lhw = HW_TO_LHW(hw);
231 	if (lhw->ops->sw_scan_start == NULL)
232 		return;
233 
234 	lhw->ops->sw_scan_start(hw, vif, addr);
235 }
236 
237 
238 /*
239  * We keep the Linux type here;  it really is an uintptr_t.
240  */
241 u64
242 lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *hw,
243     struct netdev_hw_addr_list *mc_list)
244 {
245 	struct lkpi_hw *lhw;
246 	u64 ptr;
247 
248 	lhw = HW_TO_LHW(hw);
249 	if (lhw->ops->prepare_multicast == NULL)
250 		return (0);
251 
252 	ptr = lhw->ops->prepare_multicast(hw, mc_list);
253 	return (ptr);
254 }
255 
256 void
257 lkpi_80211_mo_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
258     unsigned int *total_flags, u64 mc_ptr)
259 {
260 	struct lkpi_hw *lhw;
261 
262 	lhw = HW_TO_LHW(hw);
263 	if (lhw->ops->configure_filter == NULL)
264 		return;
265 
266 	if (mc_ptr == 0)
267 		return;
268 
269 	lhw->ops->configure_filter(hw, changed_flags, total_flags, mc_ptr);
270 }
271 
272 
273 /*
274  * So far we only called sta_{add,remove} as an alternative to sta_state.
275  * Let's keep the implementation simpler and hid sta_{add,remove} under the
276  * hood here calling them if state_state is not available from mo_sta_state.
277  */
278 static int
279 lkpi_80211_mo_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
280     struct ieee80211_sta *sta)
281 {
282 	struct lkpi_hw *lhw;
283 	struct lkpi_sta *lsta;
284 	int error;
285 
286 	lhw = HW_TO_LHW(hw);
287 	if (lhw->ops->sta_add == NULL) {
288 		error = EOPNOTSUPP;
289 		goto out;
290 	}
291 
292 	lsta = STA_TO_LSTA(sta);
293 	if (lsta->added_to_drv) {
294 		error = EEXIST;
295 		goto out;
296 	}
297 
298 	error = lhw->ops->sta_add(hw, vif, sta);
299 	if (error == 0)
300 		lsta->added_to_drv = true;
301 
302 out:
303 	return error;
304 }
305 
306 static int
307 lkpi_80211_mo_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
308     struct ieee80211_sta *sta)
309 {
310 	struct lkpi_hw *lhw;
311 	struct lkpi_sta *lsta;
312 	int error;
313 
314 	lhw = HW_TO_LHW(hw);
315 	if (lhw->ops->sta_remove == NULL) {
316 		error = EOPNOTSUPP;
317 		goto out;
318 	}
319 
320 	lsta = STA_TO_LSTA(sta);
321 	if (!lsta->added_to_drv) {
322 		/* If we never added the sta, do not complain on cleanup. */
323 		error = 0;
324 		goto out;
325 	}
326 
327 	error = lhw->ops->sta_remove(hw, vif, sta);
328 	if (error == 0)
329 		lsta->added_to_drv = false;
330 
331 out:
332 	return error;
333 }
334 
335 int
336 lkpi_80211_mo_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
337     struct ieee80211_sta *sta, enum ieee80211_sta_state nstate)
338 {
339 	struct lkpi_hw *lhw;
340 	struct lkpi_sta *lsta;
341 	int error;
342 
343 	lhw = HW_TO_LHW(hw);
344 	lsta = STA_TO_LSTA(sta);
345 	if (lhw->ops->sta_state != NULL) {
346 		error = lhw->ops->sta_state(hw, vif, sta, lsta->state, nstate);
347 		if (error == 0) {
348 			if (nstate == IEEE80211_STA_NOTEXIST)
349 				lsta->added_to_drv = false;
350 			else
351 				lsta->added_to_drv = true;
352 			lsta->state = nstate;
353 		}
354 		goto out;
355 	}
356 
357 	/* XXX-BZ is the change state AUTH or ASSOC here? */
358 	if (lsta->state < IEEE80211_STA_ASSOC && nstate == IEEE80211_STA_ASSOC)
359 		error = lkpi_80211_mo_sta_add(hw, vif, sta);
360 	else if (lsta->state >= IEEE80211_STA_ASSOC &&
361 	    nstate < IEEE80211_STA_ASSOC)
362 		error = lkpi_80211_mo_sta_remove(hw, vif, sta);
363 	else
364 		/* Nothing to do. */
365 		error = 0;
366 
367 out:
368 	/* XXX-BZ should we manage state in here? */
369 	return (error);
370 }
371 
372 int
373 lkpi_80211_mo_config(struct ieee80211_hw *hw, uint32_t changed)
374 {
375 	struct lkpi_hw *lhw;
376 	int error;
377 
378 	lhw = HW_TO_LHW(hw);
379 	if (lhw->ops->config == NULL) {
380 		error = EOPNOTSUPP;
381 		goto out;
382 	}
383 
384 	error = lhw->ops->config(hw, changed);
385 
386 out:
387 	return (error);
388 }
389 
390 
391 int
392 lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
393     struct ieee80211_chanctx_conf *chanctx_conf)
394 {
395 	struct lkpi_hw *lhw;
396 	int error;
397 
398 	lhw = HW_TO_LHW(hw);
399 	if (lhw->ops->assign_vif_chanctx == NULL) {
400 		error = EOPNOTSUPP;
401 		goto out;
402 	}
403 
404 	error = lhw->ops->assign_vif_chanctx(hw, vif, chanctx_conf);
405 	if (error == 0)
406 		vif->chanctx_conf = chanctx_conf;
407 
408 out:
409 	return (error);
410 }
411 
412 void
413 lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
414     struct ieee80211_chanctx_conf **chanctx_conf)
415 {
416 	struct lkpi_hw *lhw;
417 
418 	lhw = HW_TO_LHW(hw);
419 	if (lhw->ops->unassign_vif_chanctx == NULL)
420 		return;
421 
422 	if (*chanctx_conf == NULL)
423 		return;
424 
425 	lhw->ops->unassign_vif_chanctx(hw, vif, *chanctx_conf);
426 	*chanctx_conf = NULL;
427 }
428 
429 
430 int
431 lkpi_80211_mo_add_chanctx(struct ieee80211_hw *hw,
432     struct ieee80211_chanctx_conf *chanctx_conf)
433 {
434 	struct lkpi_hw *lhw;
435 	int error;
436 
437 	lhw = HW_TO_LHW(hw);
438 	if (lhw->ops->add_chanctx == NULL) {
439 		error = EOPNOTSUPP;
440 		goto out;
441 	}
442 
443 	error = lhw->ops->add_chanctx(hw, chanctx_conf);
444 
445 out:
446 	return (error);
447 }
448 
449 void
450 lkpi_80211_mo_change_chanctx(struct ieee80211_hw *hw,
451     struct ieee80211_chanctx_conf *chanctx_conf, uint32_t changed)
452 {
453 	struct lkpi_hw *lhw;
454 
455 	lhw = HW_TO_LHW(hw);
456 	if (lhw->ops->change_chanctx == NULL)
457 		return;
458 
459 	lhw->ops->change_chanctx(hw, chanctx_conf, changed);
460 }
461 
462 void
463 lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *hw,
464     struct ieee80211_chanctx_conf *chanctx_conf)
465 {
466 	struct lkpi_hw *lhw;
467 
468 	lhw = HW_TO_LHW(hw);
469 	if (lhw->ops->remove_chanctx == NULL)
470 		return;
471 
472 	lhw->ops->remove_chanctx(hw, chanctx_conf);
473 }
474 
475 void
476 lkpi_80211_mo_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
477     struct ieee80211_bss_conf *conf, uint32_t changed)
478 {
479 	struct lkpi_hw *lhw;
480 
481 	lhw = HW_TO_LHW(hw);
482 	if (lhw->ops->bss_info_changed == NULL)
483 		return;
484 
485 	lhw->ops->bss_info_changed(hw, vif, conf, changed);
486 }
487 
488 
489 int
490 lkpi_80211_mo_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
491     uint16_t ac, const struct ieee80211_tx_queue_params *txqp)
492 {
493 	struct lkpi_hw *lhw;
494 	int error;
495 
496 	lhw = HW_TO_LHW(hw);
497 	if (lhw->ops->conf_tx == NULL) {
498 		error = EOPNOTSUPP;
499 		goto out;
500 	}
501 
502 	error = lhw->ops->conf_tx(hw, vif, ac, txqp);
503 
504 out:
505 	return (error);
506 }
507 
508 void
509 lkpi_80211_mo_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
510     uint32_t nqueues, bool drop)
511 {
512 	struct lkpi_hw *lhw;
513 
514 	lhw = HW_TO_LHW(hw);
515 	if (lhw->ops->flush == NULL)
516 		return;
517 
518 	lhw->ops->flush(hw, vif, nqueues, drop);
519 }
520 
521 void
522 lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
523     struct ieee80211_prep_tx_info *txinfo)
524 {
525 	struct lkpi_hw *lhw;
526 
527 	lhw = HW_TO_LHW(hw);
528 	if (lhw->ops->mgd_prepare_tx == NULL)
529 		return;
530 
531 	lhw->ops->mgd_prepare_tx(hw, vif, txinfo);
532 }
533 
534 void
535 lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
536     struct ieee80211_prep_tx_info *txinfo)
537 {
538 	struct lkpi_hw *lhw;
539 
540 	lhw = HW_TO_LHW(hw);
541 	if (lhw->ops->mgd_complete_tx == NULL)
542 		return;
543 
544 	lhw->ops->mgd_complete_tx(hw, vif, txinfo);
545 }
546 
547 void
548 lkpi_80211_mo_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *txctrl,
549     struct sk_buff *skb)
550 {
551 	struct lkpi_hw *lhw;
552 
553 	lhw = HW_TO_LHW(hw);
554 	if (lhw->ops->tx == NULL)
555 		return;
556 
557 	lhw->ops->tx(hw, txctrl, skb);
558 }
559 
560 void
561 lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
562 {
563 	struct lkpi_hw *lhw;
564 
565 	lhw = HW_TO_LHW(hw);
566 	if (lhw->ops->wake_tx_queue == NULL)
567 		return;
568 
569 	lhw->ops->wake_tx_queue(hw, txq);
570 }
571 
572 void
573 lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw *hw)
574 {
575 	struct lkpi_hw *lhw;
576 
577 	lhw = HW_TO_LHW(hw);
578 	if (lhw->ops->sync_rx_queues == NULL)
579 		return;
580 
581 	lhw->ops->sync_rx_queues(hw);
582 }
583 
584 void
585 lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw *hw,
586     struct ieee80211_vif *vif, struct ieee80211_sta *sta)
587 {
588 	struct lkpi_hw *lhw;
589 
590 	lhw = HW_TO_LHW(hw);
591 	if (lhw->ops->sta_pre_rcu_remove == NULL)
592 		return;
593 
594 	lhw->ops->sta_pre_rcu_remove(hw, vif, sta);
595 }
596 
597 int
598 lkpi_80211_mo_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
599     struct ieee80211_vif *vif, struct ieee80211_sta *sta,
600     struct ieee80211_key_conf *kc)
601 {
602 	struct lkpi_hw *lhw;
603 	int error;
604 
605 	lhw = HW_TO_LHW(hw);
606 	if (lhw->ops->set_key == NULL) {
607 		error = EOPNOTSUPP;
608 		goto out;
609 	}
610 
611 	error = lhw->ops->set_key(hw, cmd, vif, sta, kc);
612 
613 out:
614 	return (error);
615 }
616