1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2010-2011 Monthadar Al Jaberi, TerraNet AB 5 * All rights reserved. 6 * 7 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer, 15 * without modification. 16 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 17 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 18 * redistribution must be conditioned upon including a substantially 19 * similar Disclaimer requirement for further binary redistribution. 20 * 21 * NO WARRANTY 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 25 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 26 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 27 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 30 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 * THE POSSIBILITY OF SUCH DAMAGES. 33 * 34 * $FreeBSD$ 35 */ 36 #include "if_wtapvar.h" 37 #include <sys/uio.h> /* uio struct */ 38 #include <sys/jail.h> 39 #include <net/if_var.h> 40 #include <net/vnet.h> 41 42 #include <net80211/ieee80211_ratectl.h> 43 #include "if_medium.h" 44 45 /* 46 * This _requires_ vimage to be useful. 47 */ 48 #ifndef VIMAGE 49 #error if_wtap requires VIMAGE. 50 #endif /* VIMAGE */ 51 52 /* device for IOCTL and read/write for debuggin purposes */ 53 /* Function prototypes */ 54 static d_open_t wtap_node_open; 55 static d_close_t wtap_node_close; 56 static d_write_t wtap_node_write; 57 static d_ioctl_t wtap_node_ioctl; 58 59 static struct cdevsw wtap_cdevsw = { 60 .d_version = D_VERSION, 61 .d_flags = 0, 62 .d_open = wtap_node_open, 63 .d_close = wtap_node_close, 64 .d_write = wtap_node_write, 65 .d_ioctl = wtap_node_ioctl, 66 .d_name = "wtapnode", 67 }; 68 69 static int 70 wtap_node_open(struct cdev *dev, int oflags, int devtype, struct thread *p) 71 { 72 73 int err = 0; 74 uprintf("Opened device \"echo\" successfully.\n"); 75 return(err); 76 } 77 78 static int 79 wtap_node_close(struct cdev *dev, int fflag, int devtype, struct thread *p) 80 { 81 82 uprintf("Closing device \"echo.\"\n"); 83 return(0); 84 } 85 86 static int 87 wtap_node_write(struct cdev *dev, struct uio *uio, int ioflag) 88 { 89 int err = 0; 90 struct mbuf *m; 91 struct ifnet *ifp; 92 struct wtap_softc *sc; 93 uint8_t buf[1024]; 94 struct epoch_tracker et; 95 int buf_len; 96 97 uprintf("write device %s \"echo.\"\n", devtoname(dev)); 98 buf_len = MIN(uio->uio_iov->iov_len, 1024); 99 err = copyin(uio->uio_iov->iov_base, buf, buf_len); 100 101 if (err != 0) { 102 uprintf("Write failed: bad address!\n"); 103 return (err); 104 } 105 106 MGETHDR(m, M_NOWAIT, MT_DATA); 107 m_copyback(m, 0, buf_len, buf); 108 109 CURVNET_SET(TD_TO_VNET(curthread)); 110 NET_EPOCH_ENTER(et); 111 112 CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 113 printf("ifp->if_xname = %s\n", ifp->if_xname); 114 if(strcmp(devtoname(dev), ifp->if_xname) == 0){ 115 printf("found match, correspoding wtap = %s\n", 116 ifp->if_xname); 117 sc = (struct wtap_softc *)ifp->if_softc; 118 printf("wtap id = %d\n", sc->id); 119 wtap_inject(sc, m); 120 } 121 } 122 123 NET_EPOCH_EXIT(et); 124 CURVNET_RESTORE(); 125 126 return(err); 127 } 128 129 int 130 wtap_node_ioctl(struct cdev *dev, u_long cmd, caddr_t data, 131 int fflag, struct thread *td) 132 { 133 int error = 0; 134 135 switch(cmd) { 136 default: 137 DWTAP_PRINTF("Unknown WTAP IOCTL\n"); 138 error = EINVAL; 139 } 140 return error; 141 } 142 143 static int wtap_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 144 const struct ieee80211_bpf_params *params); 145 146 static int 147 wtap_medium_enqueue(struct wtap_vap *avp, struct mbuf *m) 148 { 149 150 return medium_transmit(avp->av_md, avp->id, m); 151 } 152 153 /* 154 * Intercept management frames to collect beacon rssi data 155 * and to do ibss merges. 156 */ 157 static void 158 wtap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, 159 int subtype, const struct ieee80211_rx_stats *stats, int rssi, int nf) 160 { 161 struct ieee80211vap *vap = ni->ni_vap; 162 #if 0 163 DWTAP_PRINTF("[%d] %s\n", myath_id(ni), __func__); 164 #endif 165 WTAP_VAP(vap)->av_recv_mgmt(ni, m, subtype, stats, rssi, nf); 166 } 167 168 static int 169 wtap_reset_vap(struct ieee80211vap *vap, u_long cmd) 170 { 171 172 DWTAP_PRINTF("%s\n", __func__); 173 return 0; 174 } 175 176 static void 177 wtap_beacon_update(struct ieee80211vap *vap, int item) 178 { 179 struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; 180 181 DWTAP_PRINTF("%s\n", __func__); 182 setbit(bo->bo_flags, item); 183 } 184 185 /* 186 * Allocate and setup an initial beacon frame. 187 */ 188 static int 189 wtap_beacon_alloc(struct wtap_softc *sc, struct ieee80211_node *ni) 190 { 191 struct ieee80211vap *vap = ni->ni_vap; 192 struct wtap_vap *avp = WTAP_VAP(vap); 193 194 DWTAP_PRINTF("[%s] %s\n", ether_sprintf(ni->ni_macaddr), __func__); 195 196 /* 197 * NB: the beacon data buffer must be 32-bit aligned; 198 * we assume the mbuf routines will return us something 199 * with this alignment (perhaps should assert). 200 */ 201 avp->beacon = ieee80211_beacon_alloc(ni); 202 if (avp->beacon == NULL) { 203 printf("%s: cannot get mbuf\n", __func__); 204 return ENOMEM; 205 } 206 callout_init(&avp->av_swba, 0); 207 avp->bf_node = ieee80211_ref_node(ni); 208 209 return 0; 210 } 211 212 static void 213 wtap_beacon_config(struct wtap_softc *sc, struct ieee80211vap *vap) 214 { 215 216 DWTAP_PRINTF("%s\n", __func__); 217 } 218 219 static void 220 wtap_beacon_intrp(void *arg) 221 { 222 struct wtap_vap *avp = arg; 223 struct ieee80211vap *vap = arg; 224 struct mbuf *m; 225 226 if (vap->iv_state < IEEE80211_S_RUN) { 227 DWTAP_PRINTF("Skip beacon, not running, state %d", vap->iv_state); 228 return ; 229 } 230 DWTAP_PRINTF("[%d] beacon intrp\n", avp->id); //burst mode 231 /* 232 * Update dynamic beacon contents. If this returns 233 * non-zero then we need to remap the memory because 234 * the beacon frame changed size (probably because 235 * of the TIM bitmap). 236 */ 237 m = m_dup(avp->beacon, M_NOWAIT); 238 if (ieee80211_beacon_update(avp->bf_node, m, 0)) { 239 printf("%s, need to remap the memory because the beacon frame" 240 " changed size.\n",__func__); 241 } 242 243 if (ieee80211_radiotap_active_vap(vap)) 244 ieee80211_radiotap_tx(vap, m); 245 246 #if 0 247 medium_transmit(avp->av_md, avp->id, m); 248 #endif 249 wtap_medium_enqueue(avp, m); 250 callout_schedule(&avp->av_swba, avp->av_bcinterval); 251 } 252 253 static int 254 wtap_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 255 { 256 struct ieee80211com *ic = vap->iv_ic; 257 struct wtap_softc *sc = ic->ic_softc; 258 struct wtap_vap *avp = WTAP_VAP(vap); 259 struct ieee80211_node *ni = NULL; 260 int error; 261 262 DWTAP_PRINTF("%s\n", __func__); 263 264 ni = ieee80211_ref_node(vap->iv_bss); 265 /* 266 * Invoke the parent method to do net80211 work. 267 */ 268 error = avp->av_newstate(vap, nstate, arg); 269 if (error != 0) 270 goto bad; 271 272 if (nstate == IEEE80211_S_RUN) { 273 /* NB: collect bss node again, it may have changed */ 274 ieee80211_free_node(ni); 275 ni = ieee80211_ref_node(vap->iv_bss); 276 switch (vap->iv_opmode) { 277 case IEEE80211_M_MBSS: 278 error = wtap_beacon_alloc(sc, ni); 279 if (error != 0) 280 goto bad; 281 wtap_beacon_config(sc, vap); 282 callout_reset(&avp->av_swba, avp->av_bcinterval, 283 wtap_beacon_intrp, vap); 284 break; 285 default: 286 goto bad; 287 } 288 } else if (nstate == IEEE80211_S_INIT) { 289 callout_stop(&avp->av_swba); 290 } 291 ieee80211_free_node(ni); 292 return 0; 293 bad: 294 printf("%s: bad\n", __func__); 295 ieee80211_free_node(ni); 296 return error; 297 } 298 299 static void 300 wtap_bmiss(struct ieee80211vap *vap) 301 { 302 struct wtap_vap *avp = (struct wtap_vap *)vap; 303 304 DWTAP_PRINTF("%s\n", __func__); 305 avp->av_bmiss(vap); 306 } 307 308 static struct ieee80211vap * 309 wtap_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], 310 int unit, enum ieee80211_opmode opmode, int flags, 311 const uint8_t bssid[IEEE80211_ADDR_LEN], 312 const uint8_t mac[IEEE80211_ADDR_LEN]) 313 { 314 struct wtap_softc *sc = ic->ic_softc; 315 struct ieee80211vap *vap; 316 struct wtap_vap *avp; 317 int error; 318 struct ieee80211_node *ni; 319 320 DWTAP_PRINTF("%s\n", __func__); 321 322 avp = malloc(sizeof(struct wtap_vap), M_80211_VAP, M_WAITOK | M_ZERO); 323 avp->id = sc->id; 324 avp->av_md = sc->sc_md; 325 avp->av_bcinterval = msecs_to_ticks(BEACON_INTRERVAL + 100*sc->id); 326 vap = (struct ieee80211vap *) avp; 327 error = ieee80211_vap_setup(ic, vap, name, unit, IEEE80211_M_MBSS, 328 flags | IEEE80211_CLONE_NOBEACONS, bssid); 329 if (error) { 330 free(avp, M_80211_VAP); 331 return (NULL); 332 } 333 334 /* override various methods */ 335 avp->av_recv_mgmt = vap->iv_recv_mgmt; 336 vap->iv_recv_mgmt = wtap_recv_mgmt; 337 vap->iv_reset = wtap_reset_vap; 338 vap->iv_update_beacon = wtap_beacon_update; 339 avp->av_newstate = vap->iv_newstate; 340 vap->iv_newstate = wtap_newstate; 341 avp->av_bmiss = vap->iv_bmiss; 342 vap->iv_bmiss = wtap_bmiss; 343 344 /* complete setup */ 345 ieee80211_vap_attach(vap, ieee80211_media_change, 346 ieee80211_media_status, mac); 347 avp->av_dev = make_dev(&wtap_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 348 "%s", (const char *)sc->name); 349 350 /* TODO this is a hack to force it to choose the rate we want */ 351 ni = ieee80211_ref_node(vap->iv_bss); 352 ni->ni_txrate = 130; 353 ieee80211_free_node(ni); 354 return vap; 355 } 356 357 static void 358 wtap_vap_delete(struct ieee80211vap *vap) 359 { 360 struct wtap_vap *avp = WTAP_VAP(vap); 361 362 DWTAP_PRINTF("%s\n", __func__); 363 destroy_dev(avp->av_dev); 364 callout_stop(&avp->av_swba); 365 ieee80211_vap_detach(vap); 366 free(avp, M_80211_VAP); 367 } 368 369 static void 370 wtap_parent(struct ieee80211com *ic) 371 { 372 struct wtap_softc *sc = ic->ic_softc; 373 374 if (ic->ic_nrunning > 0) { 375 sc->up = 1; 376 ieee80211_start_all(ic); 377 } else 378 sc->up = 0; 379 } 380 381 static void 382 wtap_scan_start(struct ieee80211com *ic) 383 { 384 385 #if 0 386 DWTAP_PRINTF("%s\n", __func__); 387 #endif 388 } 389 390 static void 391 wtap_scan_end(struct ieee80211com *ic) 392 { 393 394 #if 0 395 DWTAP_PRINTF("%s\n", __func__); 396 #endif 397 } 398 399 static void 400 wtap_set_channel(struct ieee80211com *ic) 401 { 402 403 #if 0 404 DWTAP_PRINTF("%s\n", __func__); 405 #endif 406 } 407 408 static int 409 wtap_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 410 const struct ieee80211_bpf_params *params) 411 { 412 #if 0 413 DWTAP_PRINTF("%s, %p\n", __func__, m); 414 #endif 415 struct ieee80211vap *vap = ni->ni_vap; 416 struct wtap_vap *avp = WTAP_VAP(vap); 417 418 if (ieee80211_radiotap_active_vap(vap)) { 419 ieee80211_radiotap_tx(vap, m); 420 } 421 if (m->m_flags & M_TXCB) 422 ieee80211_process_callback(ni, m, 0); 423 ieee80211_free_node(ni); 424 return wtap_medium_enqueue(avp, m); 425 } 426 427 void 428 wtap_inject(struct wtap_softc *sc, struct mbuf *m) 429 { 430 struct wtap_buf *bf = (struct wtap_buf *)malloc(sizeof(struct wtap_buf), 431 M_WTAP_RXBUF, M_NOWAIT | M_ZERO); 432 KASSERT(bf != NULL, ("could not allocated a new wtap_buf\n")); 433 bf->m = m; 434 435 mtx_lock(&sc->sc_mtx); 436 STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); 437 taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); 438 mtx_unlock(&sc->sc_mtx); 439 } 440 441 static void 442 wtap_rx_proc(void *arg, int npending) 443 { 444 struct epoch_tracker et; 445 struct wtap_softc *sc = (struct wtap_softc *)arg; 446 struct ieee80211com *ic = &sc->sc_ic; 447 struct mbuf *m; 448 struct ieee80211_node *ni; 449 int type; 450 struct wtap_buf *bf; 451 452 #if 0 453 DWTAP_PRINTF("%s\n", __func__); 454 #endif 455 456 for(;;) { 457 mtx_lock(&sc->sc_mtx); 458 bf = STAILQ_FIRST(&sc->sc_rxbuf); 459 if (bf == NULL) { 460 mtx_unlock(&sc->sc_mtx); 461 return; 462 } 463 STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list); 464 mtx_unlock(&sc->sc_mtx); 465 KASSERT(bf != NULL, ("wtap_buf is NULL\n")); 466 m = bf->m; 467 DWTAP_PRINTF("[%d] receiving m=%p\n", sc->id, bf->m); 468 if (m == NULL) { /* NB: shouldn't happen */ 469 ic_printf(ic, "%s: no mbuf!\n", __func__); 470 free(bf, M_WTAP_RXBUF); 471 return; 472 } 473 #if 0 474 ieee80211_dump_pkt(ic, mtod(m, caddr_t), 0,0,0); 475 #endif 476 477 /* 478 * Locate the node for sender, track state, and then 479 * pass the (referenced) node up to the 802.11 layer 480 * for its use. 481 */ 482 ni = ieee80211_find_rxnode_withkey(ic, 483 mtod(m, const struct ieee80211_frame_min *), 484 IEEE80211_KEYIX_NONE); 485 NET_EPOCH_ENTER(et); 486 if (ni != NULL) { 487 /* 488 * Sending station is known, dispatch directly. 489 */ 490 type = ieee80211_input(ni, m, 1<<7, 10); 491 ieee80211_free_node(ni); 492 } else { 493 type = ieee80211_input_all(ic, m, 1<<7, 10); 494 } 495 NET_EPOCH_EXIT(et); 496 497 /* The mbufs are freed by the Net80211 stack */ 498 free(bf, M_WTAP_RXBUF); 499 } 500 } 501 502 static void 503 wtap_newassoc(struct ieee80211_node *ni, int isnew) 504 { 505 506 DWTAP_PRINTF("%s\n", __func__); 507 } 508 509 /* 510 * Callback from the 802.11 layer to update WME parameters. 511 */ 512 static int 513 wtap_wme_update(struct ieee80211com *ic) 514 { 515 516 DWTAP_PRINTF("%s\n", __func__); 517 return 0; 518 } 519 520 static void 521 wtap_update_mcast(struct ieee80211com *ic) 522 { 523 524 DWTAP_PRINTF("%s\n", __func__); 525 } 526 527 static void 528 wtap_update_promisc(struct ieee80211com *ic) 529 { 530 531 DWTAP_PRINTF("%s\n", __func__); 532 } 533 534 static int 535 wtap_transmit(struct ieee80211com *ic, struct mbuf *m) 536 { 537 struct ieee80211_node *ni = 538 (struct ieee80211_node *) m->m_pkthdr.rcvif; 539 struct ieee80211vap *vap = ni->ni_vap; 540 struct wtap_vap *avp = WTAP_VAP(vap); 541 542 if(ni == NULL){ 543 printf("m->m_pkthdr.rcvif is NULL we cant radiotap_tx\n"); 544 }else{ 545 if (ieee80211_radiotap_active_vap(vap)) 546 ieee80211_radiotap_tx(vap, m); 547 } 548 if (m->m_flags & M_TXCB) 549 ieee80211_process_callback(ni, m, 0); 550 ieee80211_free_node(ni); 551 return wtap_medium_enqueue(avp, m); 552 } 553 554 static struct ieee80211_node * 555 wtap_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) 556 { 557 struct ieee80211_node *ni; 558 559 DWTAP_PRINTF("%s\n", __func__); 560 561 ni = malloc(sizeof(struct ieee80211_node), M_80211_NODE, 562 M_NOWAIT|M_ZERO); 563 if (ni == NULL) 564 return (NULL); 565 566 ni->ni_txrate = 130; 567 return ni; 568 } 569 570 static void 571 wtap_node_free(struct ieee80211_node *ni) 572 { 573 struct ieee80211com *ic = ni->ni_ic; 574 struct wtap_softc *sc = ic->ic_softc; 575 576 DWTAP_PRINTF("%s\n", __func__); 577 sc->sc_node_free(ni); 578 } 579 580 int32_t 581 wtap_attach(struct wtap_softc *sc, const uint8_t *macaddr) 582 { 583 struct ieee80211com *ic = &sc->sc_ic; 584 585 DWTAP_PRINTF("%s\n", __func__); 586 587 sc->up = 0; 588 STAILQ_INIT(&sc->sc_rxbuf); 589 sc->sc_tq = taskqueue_create("wtap_taskq", M_NOWAIT | M_ZERO, 590 taskqueue_thread_enqueue, &sc->sc_tq); 591 taskqueue_start_threads(&sc->sc_tq, 1, PI_SOFT, "%s taskQ", sc->name); 592 NET_TASK_INIT(&sc->sc_rxtask, 0, wtap_rx_proc, sc); 593 594 ic->ic_softc = sc; 595 ic->ic_name = sc->name; 596 ic->ic_phytype = IEEE80211_T_DS; 597 ic->ic_opmode = IEEE80211_M_MBSS; 598 ic->ic_caps = IEEE80211_C_MBSS; 599 600 ic->ic_max_keyix = 128; /* A value read from Atheros ATH_KEYMAX */ 601 602 ic->ic_regdomain.regdomain = SKU_ETSI; 603 ic->ic_regdomain.country = CTRY_SWEDEN; 604 ic->ic_regdomain.location = 1; /* Indoors */ 605 ic->ic_regdomain.isocc[0] = 'S'; 606 ic->ic_regdomain.isocc[1] = 'E'; 607 608 ic->ic_nchans = 1; 609 ic->ic_channels[0].ic_flags = IEEE80211_CHAN_B; 610 ic->ic_channels[0].ic_freq = 2412; 611 612 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 613 ieee80211_ifattach(ic); 614 615 /* override default methods */ 616 ic->ic_newassoc = wtap_newassoc; 617 ic->ic_wme.wme_update = wtap_wme_update; 618 ic->ic_vap_create = wtap_vap_create; 619 ic->ic_vap_delete = wtap_vap_delete; 620 ic->ic_raw_xmit = wtap_raw_xmit; 621 ic->ic_update_mcast = wtap_update_mcast; 622 ic->ic_update_promisc = wtap_update_promisc; 623 ic->ic_transmit = wtap_transmit; 624 ic->ic_parent = wtap_parent; 625 626 sc->sc_node_alloc = ic->ic_node_alloc; 627 ic->ic_node_alloc = wtap_node_alloc; 628 sc->sc_node_free = ic->ic_node_free; 629 ic->ic_node_free = wtap_node_free; 630 631 ic->ic_scan_start = wtap_scan_start; 632 ic->ic_scan_end = wtap_scan_end; 633 ic->ic_set_channel = wtap_set_channel; 634 635 ieee80211_radiotap_attach(ic, 636 &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th), 637 WTAP_TX_RADIOTAP_PRESENT, 638 &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th), 639 WTAP_RX_RADIOTAP_PRESENT); 640 641 /* Work here, we must find a way to populate the rate table */ 642 #if 0 643 if(ic->ic_rt == NULL){ 644 printf("no table for ic_curchan\n"); 645 ic->ic_rt = ieee80211_get_ratetable(&ic->ic_channels[0]); 646 } 647 printf("ic->ic_rt =%p\n", ic->ic_rt); 648 printf("rate count %d\n", ic->ic_rt->rateCount); 649 650 uint8_t code = ic->ic_rt->info[0].dot11Rate; 651 uint8_t cix = ic->ic_rt->info[0].ctlRateIndex; 652 uint8_t ctl_rate = ic->ic_rt->info[cix].dot11Rate; 653 printf("code=%d, cix=%d, ctl_rate=%d\n", code, cix, ctl_rate); 654 655 uint8_t rix0 = ic->ic_rt->rateCodeToIndex[130]; 656 uint8_t rix1 = ic->ic_rt->rateCodeToIndex[132]; 657 uint8_t rix2 = ic->ic_rt->rateCodeToIndex[139]; 658 uint8_t rix3 = ic->ic_rt->rateCodeToIndex[150]; 659 printf("rix0 %u,rix1 %u,rix2 %u,rix3 %u\n", rix0,rix1,rix2,rix3); 660 printf("lpAckDuration=%u\n", ic->ic_rt->info[0].lpAckDuration); 661 printf("rate=%d\n", ic->ic_rt->info[0].rateKbps); 662 #endif 663 return 0; 664 } 665 666 int32_t 667 wtap_detach(struct wtap_softc *sc) 668 { 669 struct ieee80211com *ic = &sc->sc_ic; 670 671 DWTAP_PRINTF("%s\n", __func__); 672 ieee80211_ageq_drain(&ic->ic_stageq); 673 ieee80211_ifdetach(ic); 674 return 0; 675 } 676 677 void 678 wtap_resume(struct wtap_softc *sc) 679 { 680 681 DWTAP_PRINTF("%s\n", __func__); 682 } 683 684 void 685 wtap_suspend(struct wtap_softc *sc) 686 { 687 688 DWTAP_PRINTF("%s\n", __func__); 689 } 690 691 void 692 wtap_shutdown(struct wtap_softc *sc) 693 { 694 695 DWTAP_PRINTF("%s\n", __func__); 696 } 697 698 void 699 wtap_intr(struct wtap_softc *sc) 700 { 701 702 DWTAP_PRINTF("%s\n", __func__); 703 } 704