1 /* 2 * Copyright 2009, Colin Günther, coling@gmx.de. All rights reserved. 3 * Copyright 2018, Haiku, Inc. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 /*- 9 * Copyright (c) 2003-2009 Sam Leffler, Errno Consulting 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 34 /* 35 * IEEE 802.11 support (Haiku-specific code) 36 */ 37 38 39 #include "ieee80211_haiku.h" 40 41 extern "C" { 42 # include <sys/kernel.h> 43 # include <sys/mbuf.h> 44 # include <sys/bus.h> 45 # include <sys/sockio.h> 46 47 # include <net/if.h> 48 # include <net/if_media.h> 49 # include <net/if_types.h> 50 # include <net/if_var.h> 51 52 # include "ieee80211_var.h" 53 }; 54 55 #include <SupportDefs.h> 56 57 #include <util/KMessage.h> 58 59 #include <ether_driver.h> 60 #include <net_notifications.h> 61 62 #include <shared.h> 63 64 65 #define TRACE_WLAN 66 #ifdef TRACE_WLAN 67 # define TRACE(x...) dprintf(x); 68 #else 69 # define TRACE(x...) ; 70 #endif 71 72 73 #define MC_ALIGN(m, len) \ 74 do { \ 75 (m)->m_data += (MCLBYTES - (len)) &~ (sizeof(long) - 1);\ 76 } while (/* CONSTCOND */ 0) 77 78 79 static net_notifications_module_info* sNotificationModule; 80 81 82 static struct ifnet* 83 get_ifnet(device_t device, int& i) 84 { 85 int unit = device_get_unit(device); 86 87 for (i = 0; i < MAX_DEVICES; i++) { 88 if (gDevices[i] != NULL && gDevices[i]->if_dunit == unit) 89 return gDevices[i]; 90 } 91 92 return NULL; 93 } 94 95 96 status_t 97 init_wlan_stack(void) 98 { 99 get_module(NET_NOTIFICATIONS_MODULE_NAME, 100 (module_info**)&sNotificationModule); 101 102 return B_OK; 103 } 104 105 106 void 107 uninit_wlan_stack(void) 108 { 109 if (sNotificationModule != NULL) 110 put_module(NET_NOTIFICATIONS_MODULE_NAME); 111 } 112 113 114 status_t 115 start_wlan(device_t device) 116 { 117 struct ieee80211com* ic = ieee80211_find_com(device->nameunit); 118 if (ic == NULL) 119 return B_BAD_VALUE; 120 121 struct ieee80211vap* vap = ic->ic_vap_create(ic, "wlan", 122 device_get_unit(device), 123 IEEE80211_M_STA, // mode 124 0, // flags 125 NULL, // BSSID 126 ic->ic_macaddr); // MAC address 127 128 if (vap == NULL) 129 return B_ERROR; 130 131 // ic_vap_create() established that gDevices[i] links to vap->iv_ifp now 132 KASSERT(gDevices[gDeviceCount - 1] == vap->iv_ifp, 133 ("start_wlan: gDevices[i] != vap->iv_ifp")); 134 135 vap->iv_ifp->scan_done_sem = create_sem(0, "wlan scan done"); 136 137 // We aren't connected to a WLAN, yet. 138 if_link_state_change(vap->iv_ifp, LINK_STATE_DOWN); 139 140 dprintf("%s: wlan started.\n", __func__); 141 142 return B_OK; 143 } 144 145 146 status_t 147 stop_wlan(device_t device) 148 { 149 int i; 150 struct ifnet* ifp = get_ifnet(device, i); 151 if (ifp == NULL) 152 return B_BAD_VALUE; 153 154 delete_sem(ifp->scan_done_sem); 155 156 struct ieee80211vap* vap = (ieee80211vap*)ifp->if_softc; 157 struct ieee80211com* ic = vap->iv_ic; 158 159 ic->ic_vap_delete(vap); 160 161 // ic_vap_delete freed gDevices[i] 162 KASSERT(gDevices[i] == NULL, ("stop_wlan: gDevices[i] != NULL")); 163 164 return B_OK; 165 } 166 167 168 status_t 169 wlan_open(void* cookie) 170 { 171 dprintf("wlan_open(%p)\n", cookie); 172 struct ifnet* ifp = (struct ifnet*)cookie; 173 174 ifp->if_init(ifp->if_softc); 175 176 ifp->if_flags |= IFF_UP; 177 ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL); 178 179 return B_OK; 180 } 181 182 183 status_t 184 wlan_close(void* cookie) 185 { 186 dprintf("wlan_close(%p)\n", cookie); 187 struct ifnet* ifp = (struct ifnet*)cookie; 188 189 ifp->if_flags &= ~IFF_UP; 190 ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL); 191 192 return release_sem_etc(ifp->scan_done_sem, 1, B_RELEASE_ALL); 193 } 194 195 196 status_t 197 wlan_control(void* cookie, uint32 op, void* arg, size_t length) 198 { 199 struct ifnet* ifp = (struct ifnet*)cookie; 200 201 switch (op) { 202 case SIOCG80211: 203 case SIOCS80211: 204 { 205 // FreeBSD drivers assume that the request structure has already 206 // been copied into kernel space 207 struct ieee80211req request; 208 if (user_memcpy(&request, arg, sizeof(struct ieee80211req)) != B_OK) 209 return B_BAD_ADDRESS; 210 211 if (request.i_type == IEEE80211_IOC_HAIKU_COMPAT_WLAN_UP) 212 return wlan_open(cookie); 213 else if (request.i_type == IEEE80211_IOC_HAIKU_COMPAT_WLAN_DOWN) 214 return wlan_close(cookie); 215 216 TRACE("wlan_control: %" B_PRIu32 ", %d\n", op, request.i_type); 217 status_t status = ifp->if_ioctl(ifp, op, (caddr_t)&request); 218 if (status != B_OK) 219 return status; 220 221 if (op == SIOCG80211 && user_memcpy(arg, &request, 222 sizeof(struct ieee80211req)) != B_OK) 223 return B_BAD_ADDRESS; 224 return B_OK; 225 } 226 227 case SIOCSIFFLAGS: 228 case SIOCSIFMEDIA: 229 case SIOCGIFMEDIA: 230 case SIOCSIFMTU: 231 // Requests that make it here always come from the kernel 232 return ifp->if_ioctl(ifp, op, (caddr_t)arg); 233 } 234 235 return B_BAD_VALUE; 236 } 237 238 239 void 240 get_random_bytes(void* p, size_t n) 241 { 242 uint8_t* dp = (uint8_t*)p; 243 244 while (n > 0) { 245 uint32_t v = arc4random(); 246 size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n; 247 bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n); 248 dp += sizeof(uint32_t), n -= nb; 249 } 250 } 251 252 253 struct mbuf * 254 ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen) 255 { 256 struct mbuf *m; 257 u_int len; 258 259 /* 260 * NB: we know the mbuf routines will align the data area 261 * so we don't need to do anything special. 262 */ 263 len = roundup2(headroom + pktlen, 4); 264 KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len)); 265 if (len < MINCLSIZE) { 266 m = m_gethdr(M_NOWAIT, MT_DATA); 267 /* 268 * Align the data in case additional headers are added. 269 * This should only happen when a WEP header is added 270 * which only happens for shared key authentication mgt 271 * frames which all fit in MHLEN. 272 */ 273 if (m != NULL) 274 M_ALIGN(m, len); 275 } else { 276 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 277 if (m != NULL) 278 MC_ALIGN(m, len); 279 } 280 if (m != NULL) { 281 m->m_data += headroom; 282 *frm = (uint8_t*)m->m_data; 283 } 284 return m; 285 } 286 287 288 /* 289 * Decrements the reference-counter and 290 * tests whether it became zero. If so, sets it to one. 291 * 292 * @return 1 reference-counter became zero 293 * @return 0 reference-counter didn't became zero 294 */ 295 int 296 ieee80211_node_dectestref(struct ieee80211_node* ni) 297 { 298 atomic_subtract_int(&ni->ni_refcnt, 1); 299 return atomic_cmpset_int(&ni->ni_refcnt, 0, 1); 300 } 301 302 303 void 304 ieee80211_drain_ifq(struct ifqueue* ifq) 305 { 306 struct ieee80211_node* ni; 307 struct mbuf* m; 308 309 for (;;) { 310 IF_DEQUEUE(ifq, m); 311 if (m == NULL) 312 break; 313 314 ni = (struct ieee80211_node*)m->m_pkthdr.rcvif; 315 KASSERT(ni != NULL, ("frame w/o node")); 316 ieee80211_free_node(ni); 317 m->m_pkthdr.rcvif = NULL; 318 319 m_freem(m); 320 } 321 } 322 323 324 void 325 ieee80211_flush_ifq(struct ifqueue* ifq, struct ieee80211vap* vap) 326 { 327 struct ieee80211_node* ni; 328 struct mbuf* m; 329 struct mbuf** mprev; 330 331 IF_LOCK(ifq); 332 mprev = &ifq->ifq_head; 333 while ((m = *mprev) != NULL) { 334 ni = (struct ieee80211_node*)m->m_pkthdr.rcvif; 335 if (ni != NULL && ni->ni_vap == vap) { 336 *mprev = m->m_nextpkt; 337 // remove from list 338 ifq->ifq_len--; 339 340 m_freem(m); 341 ieee80211_free_node(ni); 342 // reclaim ref 343 } else 344 mprev = &m->m_nextpkt; 345 } 346 // recalculate tail ptr 347 m = ifq->ifq_head; 348 for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt); 349 ifq->ifq_tail = m; 350 IF_UNLOCK(ifq); 351 } 352 353 354 #ifndef __NO_STRICT_ALIGNMENT 355 /* 356 * Re-align the payload in the mbuf. This is mainly used (right now) 357 * to handle IP header alignment requirements on certain architectures. 358 */ 359 extern "C" struct mbuf * 360 ieee80211_realign(struct ieee80211vap *vap, struct mbuf *m, size_t align) 361 { 362 int pktlen, space; 363 struct mbuf *n; 364 365 pktlen = m->m_pkthdr.len; 366 space = pktlen + align; 367 if (space < MINCLSIZE) 368 n = m_gethdr(M_NOWAIT, MT_DATA); 369 else { 370 n = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 371 space <= MCLBYTES ? MCLBYTES : 372 #if MJUMPAGESIZE != MCLBYTES 373 space <= MJUMPAGESIZE ? MJUMPAGESIZE : 374 #endif 375 space <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES); 376 } 377 if (__predict_true(n != NULL)) { 378 m_move_pkthdr(n, m); 379 n->m_data = (caddr_t)(ALIGN(n->m_data + align) - align); 380 m_copydata(m, 0, pktlen, mtod(n, caddr_t)); 381 n->m_len = pktlen; 382 } else { 383 IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, 384 mtod(m, const struct ieee80211_frame *), NULL, 385 "%s", "no mbuf to realign"); 386 vap->iv_stats.is_rx_badalign++; 387 } 388 m_freem(m); 389 return n; 390 } 391 #endif /* !__NO_STRICT_ALIGNMENT */ 392 393 394 int 395 ieee80211_add_callback(struct mbuf* m, 396 void (*func)(struct ieee80211_node*, void*, int), void* arg) 397 { 398 struct m_tag* mtag; 399 struct ieee80211_cb* cb; 400 401 mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, 402 sizeof(struct ieee80211_cb), M_NOWAIT); 403 if (mtag == NULL) 404 return 0; 405 406 cb = (struct ieee80211_cb*)(mtag+1); 407 cb->func = func; 408 cb->arg = arg; 409 m_tag_prepend(m, mtag); 410 m->m_flags |= M_TXCB; 411 return 1; 412 } 413 414 415 void 416 ieee80211_process_callback(struct ieee80211_node* ni, struct mbuf* m, 417 int status) 418 { 419 struct m_tag* mtag; 420 421 mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL); 422 if (mtag != NULL) { 423 struct ieee80211_cb* cb = (struct ieee80211_cb*)(mtag+1); 424 cb->func(ni, cb->arg, status); 425 } 426 } 427 428 429 int 430 ieee80211_add_xmit_params(struct mbuf *m, 431 const struct ieee80211_bpf_params *params) 432 { 433 struct m_tag *mtag; 434 struct ieee80211_tx_params *tx; 435 436 mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS, 437 sizeof(struct ieee80211_tx_params), M_NOWAIT); 438 if (mtag == NULL) 439 return (0); 440 441 tx = (struct ieee80211_tx_params *)(mtag+1); 442 memcpy(&tx->params, params, sizeof(struct ieee80211_bpf_params)); 443 m_tag_prepend(m, mtag); 444 return (1); 445 } 446 447 448 int 449 ieee80211_get_xmit_params(struct mbuf *m, 450 struct ieee80211_bpf_params *params) 451 { 452 struct m_tag *mtag; 453 struct ieee80211_tx_params *tx; 454 455 mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS, 456 NULL); 457 if (mtag == NULL) 458 return (-1); 459 tx = (struct ieee80211_tx_params *)(mtag + 1); 460 memcpy(params, &tx->params, sizeof(struct ieee80211_bpf_params)); 461 return (0); 462 } 463 464 465 /* 466 * Add RX parameters to the given mbuf. 467 * 468 * Returns 1 if OK, 0 on error. 469 */ 470 int 471 ieee80211_add_rx_params(struct mbuf *m, const struct ieee80211_rx_stats *rxs) 472 { 473 struct m_tag *mtag; 474 struct ieee80211_rx_params *rx; 475 476 mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS, 477 sizeof(struct ieee80211_rx_stats), M_NOWAIT); 478 if (mtag == NULL) 479 return (0); 480 481 rx = (struct ieee80211_rx_params *)(mtag + 1); 482 memcpy(&rx->params, rxs, sizeof(*rxs)); 483 m_tag_prepend(m, mtag); 484 return (1); 485 } 486 487 488 int 489 ieee80211_get_rx_params(struct mbuf *m, struct ieee80211_rx_stats *rxs) 490 { 491 struct m_tag *mtag; 492 struct ieee80211_rx_params *rx; 493 494 mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS, 495 NULL); 496 if (mtag == NULL) 497 return (-1); 498 rx = (struct ieee80211_rx_params *)(mtag + 1); 499 memcpy(rxs, &rx->params, sizeof(*rxs)); 500 return (0); 501 } 502 503 504 const struct ieee80211_rx_stats * 505 ieee80211_get_rx_params_ptr(struct mbuf *m) 506 { 507 struct m_tag *mtag; 508 struct ieee80211_rx_params *rx; 509 510 mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS, 511 NULL); 512 if (mtag == NULL) 513 return (NULL); 514 rx = (struct ieee80211_rx_params *)(mtag + 1); 515 return (&rx->params); 516 } 517 518 519 /* 520 * Add TOA parameters to the given mbuf. 521 */ 522 int 523 ieee80211_add_toa_params(struct mbuf *m, const struct ieee80211_toa_params *p) 524 { 525 struct m_tag *mtag; 526 struct ieee80211_toa_params *rp; 527 528 mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_TOA_PARAMS, 529 sizeof(struct ieee80211_toa_params), M_NOWAIT); 530 if (mtag == NULL) 531 return (0); 532 533 rp = (struct ieee80211_toa_params *)(mtag + 1); 534 memcpy(rp, p, sizeof(*rp)); 535 m_tag_prepend(m, mtag); 536 return (1); 537 } 538 539 540 int 541 ieee80211_get_toa_params(struct mbuf *m, struct ieee80211_toa_params *p) 542 { 543 struct m_tag *mtag; 544 struct ieee80211_toa_params *rp; 545 546 mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_TOA_PARAMS, 547 NULL); 548 if (mtag == NULL) 549 return (0); 550 rp = (struct ieee80211_toa_params *)(mtag + 1); 551 if (p != NULL) 552 memcpy(p, rp, sizeof(*p)); 553 return (1); 554 } 555 556 557 /* 558 * Transmit a frame to the parent interface. 559 */ 560 int 561 ieee80211_parent_xmitpkt(struct ieee80211com *ic, struct mbuf *m) 562 { 563 int error; 564 565 /* 566 * Assert the IC TX lock is held - this enforces the 567 * processing -> queuing order is maintained 568 */ 569 IEEE80211_TX_LOCK_ASSERT(ic); 570 error = ic->ic_transmit(ic, m); 571 if (error) { 572 struct ieee80211_node *ni; 573 574 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 575 576 /* XXX number of fragments */ 577 if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); 578 ieee80211_free_node(ni); 579 ieee80211_free_mbuf(m); 580 } 581 return (error); 582 } 583 584 585 /* 586 * Transmit a frame to the VAP interface. 587 */ 588 int 589 ieee80211_vap_xmitpkt(struct ieee80211vap *vap, struct mbuf *m) 590 { 591 struct ifnet *ifp = vap->iv_ifp; 592 593 /* 594 * When transmitting via the VAP, we shouldn't hold 595 * any IC TX lock as the VAP TX path will acquire it. 596 */ 597 IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic); 598 599 return (ifp->if_transmit(ifp, m)); 600 601 } 602 603 604 void 605 ieee80211_sysctl_vattach(struct ieee80211vap* vap) 606 { 607 vap->iv_debug = IEEE80211_MSG_XRATE 608 | IEEE80211_MSG_NODE 609 | IEEE80211_MSG_ASSOC 610 | IEEE80211_MSG_AUTH 611 | IEEE80211_MSG_STATE 612 | IEEE80211_MSG_WME 613 | IEEE80211_MSG_DOTH 614 | IEEE80211_MSG_INACT 615 | IEEE80211_MSG_ROAM; 616 } 617 618 619 void 620 ieee80211_sysctl_vdetach(struct ieee80211vap* vap) 621 { 622 dprintf("%s not implemented, yet.\n", __func__); 623 } 624 625 626 void 627 ieee80211_vap_destroy(struct ieee80211vap* vap) 628 { 629 struct ieee80211com* ic = vap->iv_ic; 630 631 ic->ic_vap_delete(vap); 632 dprintf("%s: done.\n", __func__); 633 } 634 635 636 void 637 ieee80211_load_module(const char* modname) 638 { 639 #if 0 640 dprintf("%s not implemented, yet: modname %s\n", __func__, modname); 641 #endif 642 } 643 644 645 void 646 ieee80211_notify_node_join(struct ieee80211_node* ni, int newassoc) 647 { 648 struct ieee80211vap* vap = ni->ni_vap; 649 struct ifnet* ifp = vap->iv_ifp; 650 651 TRACE("%s\n", __FUNCTION__); 652 653 if (ni == vap->iv_bss) 654 if_link_state_change(ifp, LINK_STATE_UP); 655 656 if (sNotificationModule != NULL) { 657 char messageBuffer[512]; 658 KMessage message; 659 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR); 660 message.AddInt32("opcode", B_NETWORK_WLAN_JOINED); 661 message.AddString("interface", ifp->device_name); 662 // TODO: add data about the node 663 664 sNotificationModule->send_notification(&message); 665 } 666 } 667 668 669 void 670 ieee80211_notify_node_leave(struct ieee80211_node* ni) 671 { 672 struct ieee80211vap* vap = ni->ni_vap; 673 struct ifnet* ifp = vap->iv_ifp; 674 675 if (ni == vap->iv_bss) 676 if_link_state_change(ifp, LINK_STATE_DOWN); 677 678 TRACE("%s\n", __FUNCTION__); 679 680 if (sNotificationModule != NULL) { 681 char messageBuffer[512]; 682 KMessage message; 683 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR); 684 message.AddInt32("opcode", B_NETWORK_WLAN_LEFT); 685 message.AddString("interface", ifp->device_name); 686 // TODO: add data about the node 687 688 sNotificationModule->send_notification(&message); 689 } 690 } 691 692 693 void 694 ieee80211_notify_scan_done(struct ieee80211vap* vap) 695 { 696 release_sem_etc(vap->iv_ifp->scan_done_sem, 1, 697 B_DO_NOT_RESCHEDULE | B_RELEASE_ALL); 698 699 TRACE("%s\n", __FUNCTION__); 700 701 if (sNotificationModule != NULL) { 702 char messageBuffer[512]; 703 KMessage message; 704 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR); 705 message.AddInt32("opcode", B_NETWORK_WLAN_SCANNED); 706 message.AddString("interface", vap->iv_ifp->device_name); 707 708 sNotificationModule->send_notification(&message); 709 } 710 } 711 712 713 void 714 ieee80211_notify_replay_failure(struct ieee80211vap* vap, 715 const struct ieee80211_frame* wh, const struct ieee80211_key* k, 716 u_int64_t rsc, int tid) 717 { 718 dprintf("%s not implemented, yet.\n", __func__); 719 } 720 721 722 void 723 ieee80211_notify_michael_failure(struct ieee80211vap* vap, 724 const struct ieee80211_frame* wh, u_int keyix) 725 { 726 dprintf("%s not implemented, yet.\n", __func__); 727 } 728 729 730 void 731 ieee80211_notify_wds_discover(struct ieee80211_node* ni) 732 { 733 dprintf("%s not implemented, yet.\n", __func__); 734 } 735 736 737 void 738 ieee80211_notify_csa(struct ieee80211com* ic, 739 const struct ieee80211_channel* c, int mode, int count) 740 { 741 dprintf("%s not implemented, yet.\n", __func__); 742 } 743 744 745 void 746 ieee80211_notify_radar(struct ieee80211com* ic, 747 const struct ieee80211_channel* c) 748 { 749 dprintf("%s not implemented, yet.\n", __func__); 750 } 751 752 753 void 754 ieee80211_notify_cac(struct ieee80211com* ic, 755 const struct ieee80211_channel* c, enum ieee80211_notify_cac_event type) 756 { 757 dprintf("%s not implemented, yet.\n", __func__); 758 } 759 760 761 void 762 ieee80211_notify_node_deauth(struct ieee80211_node* ni) 763 { 764 dprintf("%s not implemented, yet.\n", __func__); 765 } 766 767 768 void 769 ieee80211_notify_node_auth(struct ieee80211_node* ni) 770 { 771 dprintf("%s not implemented, yet.\n", __func__); 772 } 773 774 775 void 776 ieee80211_notify_country(struct ieee80211vap* vap, 777 const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t cc[2]) 778 { 779 dprintf("%s not implemented, yet.\n", __func__); 780 } 781 782 783 void 784 ieee80211_notify_radio(struct ieee80211com* ic, int state) 785 { 786 dprintf("%s not implemented, yet.\n", __func__); 787 } 788 789 790 void 791 ieee80211_sysctl_attach(struct ieee80211com* ic) 792 { 793 dprintf("%s not implemented, yet.\n", __func__); 794 } 795 796 797 void 798 ieee80211_sysctl_detach(struct ieee80211com* ic) 799 { 800 dprintf("%s not implemented, yet.\n", __func__); 801 } 802