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/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 /* Could be a different tracing framework later. */ 43 #ifdef LINUXKPI_DEBUG_80211 44 #define LKPI_80211_TRACE_MO(fmt, ...) \ 45 if (linuxkpi_debug_80211 & D80211_TRACE_MO) \ 46 printf("LKPI_80211_TRACE_MO %s:%d:_" fmt "\n", \ 47 __func__, __LINE__, __VA_ARGS__) 48 #else 49 #define LKPI_80211_TRACE_MO(...) do { } while(0) 50 #endif 51 52 int 53 lkpi_80211_mo_start(struct ieee80211_hw *hw) 54 { 55 struct lkpi_hw *lhw; 56 int error; 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) 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", hw); 88 lhw->ops->stop(hw); 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 error = lhw->ops->get_antenna(hw, txs, rxs); 106 107 out: 108 return (error); 109 } 110 111 int 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 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 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 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 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 lhw = HW_TO_LHW(hw); 219 if (lhw->ops->hw_scan == NULL) { 220 /* XXX-BZ can we hide other scans like we can for sta_add..? */ 221 error = EOPNOTSUPP; 222 goto out; 223 } 224 225 lhw->scan_flags |= LKPI_LHW_SCAN_RUNNING; 226 LKPI_80211_TRACE_MO("hw %p vif %p sr %p", hw, vif, sr); 227 error = lhw->ops->hw_scan(hw, vif, sr); 228 if (error != 0) 229 lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING; 230 231 out: 232 return (error); 233 } 234 235 void 236 lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 237 { 238 struct lkpi_hw *lhw; 239 240 lhw = HW_TO_LHW(hw); 241 if (lhw->ops->cancel_hw_scan == NULL) 242 return; 243 244 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif); 245 lhw->ops->cancel_hw_scan(hw, vif); 246 } 247 248 void 249 lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 250 { 251 struct lkpi_hw *lhw; 252 253 lhw = HW_TO_LHW(hw); 254 if (lhw->ops->sw_scan_complete == NULL) 255 return; 256 257 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif); 258 lhw->ops->sw_scan_complete(hw, vif); 259 lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING; 260 } 261 262 void 263 lkpi_80211_mo_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 264 const u8 *addr) 265 { 266 struct lkpi_hw *lhw; 267 268 lhw = HW_TO_LHW(hw); 269 if (lhw->ops->sw_scan_start == NULL) 270 return; 271 272 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif); 273 lhw->ops->sw_scan_start(hw, vif, addr); 274 } 275 276 277 /* 278 * We keep the Linux type here; it really is an uintptr_t. 279 */ 280 u64 281 lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *hw, 282 struct netdev_hw_addr_list *mc_list) 283 { 284 struct lkpi_hw *lhw; 285 u64 ptr; 286 287 lhw = HW_TO_LHW(hw); 288 if (lhw->ops->prepare_multicast == NULL) 289 return (0); 290 291 LKPI_80211_TRACE_MO("hw %p mc_list %p", hw, mc_list); 292 ptr = lhw->ops->prepare_multicast(hw, mc_list); 293 return (ptr); 294 } 295 296 void 297 lkpi_80211_mo_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, 298 unsigned int *total_flags, u64 mc_ptr) 299 { 300 struct lkpi_hw *lhw; 301 302 lhw = HW_TO_LHW(hw); 303 if (lhw->ops->configure_filter == NULL) 304 return; 305 306 if (mc_ptr == 0) 307 return; 308 309 LKPI_80211_TRACE_MO("hw %p changed_flags %#x total_flags %p mc_ptr %ju", hw, changed_flags, total_flags, (uintmax_t)mc_ptr); 310 lhw->ops->configure_filter(hw, changed_flags, total_flags, mc_ptr); 311 } 312 313 314 /* 315 * So far we only called sta_{add,remove} as an alternative to sta_state. 316 * Let's keep the implementation simpler and hide sta_{add,remove} under the 317 * hood here calling them if state_state is not available from mo_sta_state. 318 */ 319 static int 320 lkpi_80211_mo_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 321 struct ieee80211_sta *sta) 322 { 323 struct lkpi_hw *lhw; 324 struct lkpi_sta *lsta; 325 int error; 326 327 lhw = HW_TO_LHW(hw); 328 if (lhw->ops->sta_add == NULL) { 329 error = EOPNOTSUPP; 330 goto out; 331 } 332 333 lsta = STA_TO_LSTA(sta); 334 if (lsta->added_to_drv) { 335 error = EEXIST; 336 goto out; 337 } 338 339 LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta); 340 error = lhw->ops->sta_add(hw, vif, sta); 341 if (error == 0) 342 lsta->added_to_drv = true; 343 344 out: 345 return error; 346 } 347 348 static int 349 lkpi_80211_mo_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 350 struct ieee80211_sta *sta) 351 { 352 struct lkpi_hw *lhw; 353 struct lkpi_sta *lsta; 354 int error; 355 356 lhw = HW_TO_LHW(hw); 357 if (lhw->ops->sta_remove == NULL) { 358 error = EOPNOTSUPP; 359 goto out; 360 } 361 362 lsta = STA_TO_LSTA(sta); 363 if (!lsta->added_to_drv) { 364 /* If we never added the sta, do not complain on cleanup. */ 365 error = 0; 366 goto out; 367 } 368 369 LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta); 370 error = lhw->ops->sta_remove(hw, vif, sta); 371 if (error == 0) 372 lsta->added_to_drv = false; 373 374 out: 375 return error; 376 } 377 378 int 379 lkpi_80211_mo_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 380 struct lkpi_sta *lsta, enum ieee80211_sta_state nstate) 381 { 382 struct lkpi_hw *lhw; 383 struct ieee80211_sta *sta; 384 int error; 385 386 lhw = HW_TO_LHW(hw); 387 sta = LSTA_TO_STA(lsta); 388 if (lhw->ops->sta_state != NULL) { 389 LKPI_80211_TRACE_MO("hw %p vif %p sta %p nstate %d", hw, vif, sta, nstate); 390 error = lhw->ops->sta_state(hw, vif, sta, lsta->state, nstate); 391 if (error == 0) { 392 if (nstate == IEEE80211_STA_NOTEXIST) 393 lsta->added_to_drv = false; 394 else 395 lsta->added_to_drv = true; 396 lsta->state = nstate; 397 } 398 goto out; 399 } 400 401 /* XXX-BZ is the change state AUTH or ASSOC here? */ 402 if (lsta->state < IEEE80211_STA_ASSOC && nstate == IEEE80211_STA_ASSOC) { 403 error = lkpi_80211_mo_sta_add(hw, vif, sta); 404 if (error == 0) 405 lsta->added_to_drv = true; 406 } else if (lsta->state >= IEEE80211_STA_ASSOC && 407 nstate < IEEE80211_STA_ASSOC) { 408 error = lkpi_80211_mo_sta_remove(hw, vif, sta); 409 if (error == 0) 410 lsta->added_to_drv = false; 411 } else 412 /* Nothing to do. */ 413 error = 0; 414 if (error == 0) 415 lsta->state = nstate; 416 417 out: 418 /* XXX-BZ should we manage state in here? */ 419 return (error); 420 } 421 422 int 423 lkpi_80211_mo_config(struct ieee80211_hw *hw, uint32_t changed) 424 { 425 struct lkpi_hw *lhw; 426 int error; 427 428 lhw = HW_TO_LHW(hw); 429 if (lhw->ops->config == NULL) { 430 error = EOPNOTSUPP; 431 goto out; 432 } 433 434 LKPI_80211_TRACE_MO("hw %p changed %u", hw, changed); 435 error = lhw->ops->config(hw, changed); 436 437 out: 438 return (error); 439 } 440 441 442 int 443 lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 444 struct ieee80211_chanctx_conf *chanctx_conf) 445 { 446 struct lkpi_hw *lhw; 447 int error; 448 449 lhw = HW_TO_LHW(hw); 450 if (lhw->ops->assign_vif_chanctx == NULL) { 451 error = EOPNOTSUPP; 452 goto out; 453 } 454 455 LKPI_80211_TRACE_MO("hw %p vif %p chanctx_conf %p", hw, vif, chanctx_conf); 456 error = lhw->ops->assign_vif_chanctx(hw, vif, NULL, chanctx_conf); 457 if (error == 0) 458 vif->chanctx_conf = chanctx_conf; 459 460 out: 461 return (error); 462 } 463 464 void 465 lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 466 struct ieee80211_chanctx_conf **chanctx_conf) 467 { 468 struct lkpi_hw *lhw; 469 470 lhw = HW_TO_LHW(hw); 471 if (lhw->ops->unassign_vif_chanctx == NULL) 472 return; 473 474 if (*chanctx_conf == NULL) 475 return; 476 477 LKPI_80211_TRACE_MO("hw %p vif %p chanctx_conf %p", hw, vif, *chanctx_conf); 478 lhw->ops->unassign_vif_chanctx(hw, vif, NULL, *chanctx_conf); 479 *chanctx_conf = NULL; 480 } 481 482 483 int 484 lkpi_80211_mo_add_chanctx(struct ieee80211_hw *hw, 485 struct ieee80211_chanctx_conf *chanctx_conf) 486 { 487 struct lkpi_hw *lhw; 488 int error; 489 490 lhw = HW_TO_LHW(hw); 491 if (lhw->ops->add_chanctx == NULL) { 492 error = EOPNOTSUPP; 493 goto out; 494 } 495 496 LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf); 497 error = lhw->ops->add_chanctx(hw, chanctx_conf); 498 499 out: 500 return (error); 501 } 502 503 void 504 lkpi_80211_mo_change_chanctx(struct ieee80211_hw *hw, 505 struct ieee80211_chanctx_conf *chanctx_conf, uint32_t changed) 506 { 507 struct lkpi_hw *lhw; 508 509 lhw = HW_TO_LHW(hw); 510 if (lhw->ops->change_chanctx == NULL) 511 return; 512 513 LKPI_80211_TRACE_MO("hw %p chanctx_conf %p changed %u", hw, chanctx_conf, changed); 514 lhw->ops->change_chanctx(hw, chanctx_conf, changed); 515 } 516 517 void 518 lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *hw, 519 struct ieee80211_chanctx_conf *chanctx_conf) 520 { 521 struct lkpi_hw *lhw; 522 523 lhw = HW_TO_LHW(hw); 524 if (lhw->ops->remove_chanctx == NULL) 525 return; 526 527 LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf); 528 lhw->ops->remove_chanctx(hw, chanctx_conf); 529 } 530 531 void 532 lkpi_80211_mo_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 533 struct ieee80211_bss_conf *conf, uint64_t changed) 534 { 535 struct lkpi_hw *lhw; 536 537 lhw = HW_TO_LHW(hw); 538 if (lhw->ops->bss_info_changed == NULL) 539 return; 540 541 LKPI_80211_TRACE_MO("hw %p vif %p conf %p changed %#jx", hw, vif, conf, (uintmax_t)changed); 542 lhw->ops->bss_info_changed(hw, vif, conf, changed); 543 } 544 545 546 int 547 lkpi_80211_mo_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 548 uint16_t ac, const struct ieee80211_tx_queue_params *txqp) 549 { 550 struct lkpi_hw *lhw; 551 int error; 552 553 lhw = HW_TO_LHW(hw); 554 if (lhw->ops->conf_tx == NULL) { 555 error = EOPNOTSUPP; 556 goto out; 557 } 558 559 LKPI_80211_TRACE_MO("hw %p vif %p ac %u txpq %p", hw, vif, ac, txqp); 560 error = lhw->ops->conf_tx(hw, vif, 0, ac, txqp); 561 562 out: 563 return (error); 564 } 565 566 void 567 lkpi_80211_mo_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 568 uint32_t nqueues, bool drop) 569 { 570 struct lkpi_hw *lhw; 571 572 lhw = HW_TO_LHW(hw); 573 if (lhw->ops->flush == NULL) 574 return; 575 576 LKPI_80211_TRACE_MO("hw %p vif %p nqueues %u drop %d", hw, vif, nqueues, drop); 577 lhw->ops->flush(hw, vif, nqueues, drop); 578 } 579 580 void 581 lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 582 struct ieee80211_prep_tx_info *txinfo) 583 { 584 struct lkpi_hw *lhw; 585 586 lhw = HW_TO_LHW(hw); 587 if (lhw->ops->mgd_prepare_tx == NULL) 588 return; 589 590 LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo); 591 lhw->ops->mgd_prepare_tx(hw, vif, txinfo); 592 } 593 594 void 595 lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 596 struct ieee80211_prep_tx_info *txinfo) 597 { 598 struct lkpi_hw *lhw; 599 600 lhw = HW_TO_LHW(hw); 601 if (lhw->ops->mgd_complete_tx == NULL) 602 return; 603 604 LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo); 605 lhw->ops->mgd_complete_tx(hw, vif, txinfo); 606 } 607 608 void 609 lkpi_80211_mo_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *txctrl, 610 struct sk_buff *skb) 611 { 612 struct lkpi_hw *lhw; 613 614 lhw = HW_TO_LHW(hw); 615 if (lhw->ops->tx == NULL) 616 return; 617 618 LKPI_80211_TRACE_MO("hw %p txctrl %p skb %p", hw, txctrl, skb); 619 lhw->ops->tx(hw, txctrl, skb); 620 } 621 622 void 623 lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq) 624 { 625 struct lkpi_hw *lhw; 626 627 lhw = HW_TO_LHW(hw); 628 if (lhw->ops->wake_tx_queue == NULL) 629 return; 630 631 LKPI_80211_TRACE_MO("hw %p txq %p", hw, txq); 632 lhw->ops->wake_tx_queue(hw, txq); 633 } 634 635 void 636 lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw *hw) 637 { 638 struct lkpi_hw *lhw; 639 640 lhw = HW_TO_LHW(hw); 641 if (lhw->ops->sync_rx_queues == NULL) 642 return; 643 644 LKPI_80211_TRACE_MO("hw %p", hw); 645 lhw->ops->sync_rx_queues(hw); 646 } 647 648 void 649 lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw *hw, 650 struct ieee80211_vif *vif, struct ieee80211_sta *sta) 651 { 652 struct lkpi_hw *lhw; 653 654 lhw = HW_TO_LHW(hw); 655 if (lhw->ops->sta_pre_rcu_remove == NULL) 656 return; 657 658 LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta); 659 lhw->ops->sta_pre_rcu_remove(hw, vif, sta); 660 } 661 662 int 663 lkpi_80211_mo_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 664 struct ieee80211_vif *vif, struct ieee80211_sta *sta, 665 struct ieee80211_key_conf *kc) 666 { 667 struct lkpi_hw *lhw; 668 int error; 669 670 lhw = HW_TO_LHW(hw); 671 if (lhw->ops->set_key == NULL) { 672 error = EOPNOTSUPP; 673 goto out; 674 } 675 676 LKPI_80211_TRACE_MO("hw %p cmd %d vif %p sta %p kc %p", hw, cmd, vif, sta, kc); 677 error = lhw->ops->set_key(hw, cmd, vif, sta, kc); 678 679 out: 680 return (error); 681 } 682