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