Annotation of sys/net80211/ieee80211_ioctl.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ieee80211_ioctl.c,v 1.19 2007/07/18 18:10:31 damien Exp $ */
! 2: /* $NetBSD: ieee80211_ioctl.c,v 1.15 2004/05/06 02:58:16 dyoung Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2001 Atsushi Onoe
! 6: * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. The name of the author may not be used to endorse or promote products
! 18: * derived from this software without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 21: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 22: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 23: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 24: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 25: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 26: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 27: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 28: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 29: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 30: */
! 31:
! 32: /*
! 33: * IEEE 802.11 ioctl support
! 34: */
! 35:
! 36: #include <sys/param.h>
! 37: #include <sys/kernel.h>
! 38: #include <sys/socket.h>
! 39: #include <sys/sockio.h>
! 40: #include <sys/systm.h>
! 41: #include <sys/endian.h>
! 42: #include <sys/proc.h>
! 43: #include <sys/tree.h>
! 44:
! 45: #include <net/if.h>
! 46: #include <net/if_arp.h>
! 47: #include <net/if_media.h>
! 48:
! 49: #ifdef INET
! 50: #include <netinet/in.h>
! 51: #include <netinet/if_ether.h>
! 52: #endif
! 53:
! 54: #include <net80211/ieee80211_var.h>
! 55: #include <net80211/ieee80211_ioctl.h>
! 56:
! 57: void ieee80211_node2req(struct ieee80211com *,
! 58: const struct ieee80211_node *, struct ieee80211_nodereq *);
! 59: void ieee80211_req2node(struct ieee80211com *,
! 60: const struct ieee80211_nodereq *, struct ieee80211_node *);
! 61:
! 62: void
! 63: ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni,
! 64: struct ieee80211_nodereq *nr)
! 65: {
! 66: /* Node address and name information */
! 67: IEEE80211_ADDR_COPY(nr->nr_macaddr, ni->ni_macaddr);
! 68: IEEE80211_ADDR_COPY(nr->nr_bssid, ni->ni_bssid);
! 69: nr->nr_nwid_len = ni->ni_esslen;
! 70: bcopy(ni->ni_essid, nr->nr_nwid, IEEE80211_NWID_LEN);
! 71:
! 72: /* Channel and rates */
! 73: nr->nr_channel = ieee80211_chan2ieee(ic, ni->ni_chan);
! 74: nr->nr_chan_flags = ni->ni_chan->ic_flags;
! 75: nr->nr_nrates = ni->ni_rates.rs_nrates;
! 76: bcopy(ni->ni_rates.rs_rates, nr->nr_rates, IEEE80211_RATE_MAXSIZE);
! 77:
! 78: /* Node status information */
! 79: nr->nr_rssi = (*ic->ic_node_getrssi)(ic, ni);
! 80: nr->nr_max_rssi = ic->ic_max_rssi;
! 81: bcopy(ni->ni_tstamp, nr->nr_tstamp, sizeof(nr->nr_tstamp));
! 82: nr->nr_intval = ni->ni_intval;
! 83: nr->nr_capinfo = ni->ni_capinfo;
! 84: nr->nr_fhdwell = ni->ni_fhdwell;
! 85: nr->nr_fhindex = ni->ni_fhindex;
! 86: nr->nr_erp = ni->ni_erp;
! 87: nr->nr_pwrsave = ni->ni_pwrsave;
! 88: nr->nr_associd = ni->ni_associd;
! 89: nr->nr_txseq = ni->ni_txseq;
! 90: nr->nr_rxseq = ni->ni_rxseq;
! 91: nr->nr_fails = ni->ni_fails;
! 92: nr->nr_inact = ni->ni_inact;
! 93: nr->nr_txrate = ni->ni_txrate;
! 94: nr->nr_state = ni->ni_state;
! 95:
! 96: /* Node flags */
! 97: nr->nr_flags = 0;
! 98: if (bcmp(nr->nr_macaddr, nr->nr_bssid, IEEE80211_ADDR_LEN) == 0)
! 99: nr->nr_flags |= IEEE80211_NODEREQ_AP;
! 100: if (ni == ic->ic_bss)
! 101: nr->nr_flags |= IEEE80211_NODEREQ_AP_BSS;
! 102: }
! 103:
! 104: void
! 105: ieee80211_req2node(struct ieee80211com *ic, const struct ieee80211_nodereq *nr,
! 106: struct ieee80211_node *ni)
! 107: {
! 108: /* Node address and name information */
! 109: IEEE80211_ADDR_COPY(ni->ni_macaddr, nr->nr_macaddr);
! 110: IEEE80211_ADDR_COPY(ni->ni_bssid, nr->nr_bssid);
! 111: ni->ni_esslen = nr->nr_nwid_len;
! 112: bcopy(nr->nr_nwid, ni->ni_essid, IEEE80211_NWID_LEN);
! 113:
! 114: /* Rates */
! 115: ni->ni_rates.rs_nrates = nr->nr_nrates;
! 116: bcopy(nr->nr_rates, ni->ni_rates.rs_rates, IEEE80211_RATE_MAXSIZE);
! 117:
! 118: /* Node information */
! 119: ni->ni_intval = nr->nr_intval;
! 120: ni->ni_capinfo = nr->nr_capinfo;
! 121: ni->ni_fhdwell = nr->nr_fhdwell;
! 122: ni->ni_fhindex = nr->nr_fhindex;
! 123: ni->ni_erp = nr->nr_erp;
! 124: ni->ni_pwrsave = nr->nr_pwrsave;
! 125: ni->ni_associd = nr->nr_associd;
! 126: ni->ni_txseq = nr->nr_txseq;
! 127: ni->ni_rxseq = nr->nr_rxseq;
! 128: ni->ni_fails = nr->nr_fails;
! 129: ni->ni_inact = nr->nr_inact;
! 130: ni->ni_txrate = nr->nr_txrate;
! 131: ni->ni_state = nr->nr_state;
! 132: }
! 133:
! 134: int
! 135: ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 136: {
! 137: struct ieee80211com *ic = (void *)ifp;
! 138: struct ifreq *ifr = (struct ifreq *)data;
! 139: int i, error = 0;
! 140: struct ieee80211_nwid nwid;
! 141: struct ieee80211_nwkey *nwkey;
! 142: struct ieee80211_power *power;
! 143: struct ieee80211_bssid *bssid;
! 144: struct ieee80211chanreq *chanreq;
! 145: struct ieee80211_channel *chan;
! 146: struct ieee80211_txpower *txpower;
! 147: struct ieee80211_key keys[IEEE80211_WEP_NKID];
! 148: static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
! 149: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
! 150: };
! 151: struct ieee80211_nodereq *nr, nrbuf;
! 152: struct ieee80211_nodereq_all *na;
! 153: struct ieee80211_node *ni;
! 154: u_int32_t flags;
! 155:
! 156: switch (cmd) {
! 157: case SIOCSIFADDR:
! 158: case SIOCGIFADDR:
! 159: error = ether_ioctl(ifp, &ic->ic_ac, cmd, data);
! 160: break;
! 161: case SIOCSIFMEDIA:
! 162: case SIOCGIFMEDIA:
! 163: error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
! 164: break;
! 165: case SIOCS80211NWID:
! 166: if ((error = suser(curproc, 0)) != 0)
! 167: break;
! 168: if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
! 169: break;
! 170: if (nwid.i_len > IEEE80211_NWID_LEN) {
! 171: error = EINVAL;
! 172: break;
! 173: }
! 174: memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
! 175: ic->ic_des_esslen = nwid.i_len;
! 176: memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
! 177: error = ENETRESET;
! 178: break;
! 179: case SIOCG80211NWID:
! 180: memset(&nwid, 0, sizeof(nwid));
! 181: switch (ic->ic_state) {
! 182: case IEEE80211_S_INIT:
! 183: case IEEE80211_S_SCAN:
! 184: nwid.i_len = ic->ic_des_esslen;
! 185: memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
! 186: break;
! 187: default:
! 188: nwid.i_len = ic->ic_bss->ni_esslen;
! 189: memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
! 190: break;
! 191: }
! 192: error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
! 193: break;
! 194: case SIOCS80211NWKEY:
! 195: if ((error = suser(curproc, 0)) != 0)
! 196: break;
! 197: nwkey = (struct ieee80211_nwkey *)data;
! 198: if ((ic->ic_caps & IEEE80211_C_WEP) == 0 &&
! 199: nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
! 200: error = EINVAL;
! 201: break;
! 202: }
! 203: /* check and copy keys */
! 204: memset(keys, 0, sizeof(keys));
! 205: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
! 206: keys[i].k_len = nwkey->i_key[i].i_keylen;
! 207: /*
! 208: * Limit the maximal allowed key size to
! 209: * IEEE80211_KEYBUF_SIZE bytes.
! 210: */
! 211: if (keys[i].k_len > sizeof(keys[i].k_key)) {
! 212: error = EINVAL;
! 213: break;
! 214: }
! 215: if (keys[i].k_len <= 0)
! 216: continue;
! 217: if ((error = copyin(nwkey->i_key[i].i_keydat,
! 218: keys[i].k_key, keys[i].k_len)) != 0)
! 219: break;
! 220: }
! 221: if (error)
! 222: break;
! 223: i = nwkey->i_defkid - 1;
! 224: if (i < 0 || i >= IEEE80211_WEP_NKID ||
! 225: keys[i].k_len == 0 ||
! 226: (keys[i].k_len == -1 && ic->ic_nw_keys[i].k_len == 0)) {
! 227: if (nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
! 228: error = EINVAL;
! 229: break;
! 230: }
! 231: } else
! 232: ic->ic_wep_txkey = i;
! 233: /* save the key */
! 234: if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN)
! 235: ic->ic_flags &= ~IEEE80211_F_WEPON;
! 236: else
! 237: ic->ic_flags |= IEEE80211_F_WEPON;
! 238: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
! 239: struct ieee80211_key *k = &ic->ic_nw_keys[i];
! 240: if (keys[i].k_len < 0)
! 241: continue;
! 242: if (keys[i].k_len == 0)
! 243: k->k_cipher = IEEE80211_CIPHER_NONE;
! 244: else if (keys[i].k_len <= 5)
! 245: k->k_cipher = IEEE80211_CIPHER_WEP40;
! 246: else
! 247: k->k_cipher = IEEE80211_CIPHER_WEP104;
! 248: k->k_len = keys[i].k_len;
! 249: memcpy(k->k_key, keys[i].k_key, sizeof(keys[i].k_key));
! 250: }
! 251: error = ENETRESET;
! 252: break;
! 253: case SIOCG80211NWKEY:
! 254: nwkey = (struct ieee80211_nwkey *)data;
! 255: if (ic->ic_flags & IEEE80211_F_WEPON)
! 256: nwkey->i_wepon = IEEE80211_NWKEY_WEP;
! 257: else
! 258: nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
! 259: nwkey->i_defkid = ic->ic_wep_txkey + 1;
! 260: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
! 261: if (nwkey->i_key[i].i_keydat == NULL)
! 262: continue;
! 263: /* do not show any keys to non-root user */
! 264: if ((error = suser(curproc, 0)) != 0)
! 265: break;
! 266: nwkey->i_key[i].i_keylen = ic->ic_nw_keys[i].k_len;
! 267: if ((error = copyout(ic->ic_nw_keys[i].k_key,
! 268: nwkey->i_key[i].i_keydat,
! 269: ic->ic_nw_keys[i].k_len)) != 0)
! 270: break;
! 271: }
! 272: break;
! 273: case SIOCS80211POWER:
! 274: if ((error = suser(curproc, 0)) != 0)
! 275: break;
! 276: power = (struct ieee80211_power *)data;
! 277: ic->ic_lintval = power->i_maxsleep;
! 278: if (power->i_enabled != 0) {
! 279: if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
! 280: error = EINVAL;
! 281: else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
! 282: ic->ic_flags |= IEEE80211_F_PMGTON;
! 283: error = ENETRESET;
! 284: }
! 285: } else {
! 286: if (ic->ic_flags & IEEE80211_F_PMGTON) {
! 287: ic->ic_flags &= ~IEEE80211_F_PMGTON;
! 288: error = ENETRESET;
! 289: }
! 290: }
! 291: break;
! 292: case SIOCG80211POWER:
! 293: power = (struct ieee80211_power *)data;
! 294: power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
! 295: power->i_maxsleep = ic->ic_lintval;
! 296: break;
! 297: case SIOCS80211BSSID:
! 298: if ((error = suser(curproc, 0)) != 0)
! 299: break;
! 300: bssid = (struct ieee80211_bssid *)data;
! 301: if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr))
! 302: ic->ic_flags &= ~IEEE80211_F_DESBSSID;
! 303: else {
! 304: ic->ic_flags |= IEEE80211_F_DESBSSID;
! 305: IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
! 306: }
! 307: if (ic->ic_opmode == IEEE80211_M_HOSTAP)
! 308: break;
! 309: switch (ic->ic_state) {
! 310: case IEEE80211_S_INIT:
! 311: case IEEE80211_S_SCAN:
! 312: error = ENETRESET;
! 313: break;
! 314: default:
! 315: if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
! 316: !IEEE80211_ADDR_EQ(ic->ic_des_bssid,
! 317: ic->ic_bss->ni_bssid))
! 318: error = ENETRESET;
! 319: break;
! 320: }
! 321: break;
! 322: case SIOCG80211BSSID:
! 323: bssid = (struct ieee80211_bssid *)data;
! 324: switch (ic->ic_state) {
! 325: case IEEE80211_S_INIT:
! 326: case IEEE80211_S_SCAN:
! 327: if (ic->ic_opmode == IEEE80211_M_HOSTAP)
! 328: IEEE80211_ADDR_COPY(bssid->i_bssid,
! 329: ic->ic_myaddr);
! 330: else if (ic->ic_flags & IEEE80211_F_DESBSSID)
! 331: IEEE80211_ADDR_COPY(bssid->i_bssid,
! 332: ic->ic_des_bssid);
! 333: else
! 334: memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
! 335: break;
! 336: default:
! 337: IEEE80211_ADDR_COPY(bssid->i_bssid,
! 338: ic->ic_bss->ni_bssid);
! 339: break;
! 340: }
! 341: break;
! 342: case SIOCS80211CHANNEL:
! 343: if ((error = suser(curproc, 0)) != 0)
! 344: break;
! 345: chanreq = (struct ieee80211chanreq *)data;
! 346: if (chanreq->i_channel == IEEE80211_CHAN_ANY)
! 347: ic->ic_des_chan = IEEE80211_CHAN_ANYC;
! 348: else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
! 349: isclr(ic->ic_chan_active, chanreq->i_channel)) {
! 350: error = EINVAL;
! 351: break;
! 352: } else
! 353: ic->ic_ibss_chan = ic->ic_des_chan =
! 354: &ic->ic_channels[chanreq->i_channel];
! 355: switch (ic->ic_state) {
! 356: case IEEE80211_S_INIT:
! 357: case IEEE80211_S_SCAN:
! 358: error = ENETRESET;
! 359: break;
! 360: default:
! 361: if (ic->ic_opmode == IEEE80211_M_STA) {
! 362: if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
! 363: ic->ic_bss->ni_chan != ic->ic_des_chan)
! 364: error = ENETRESET;
! 365: } else {
! 366: if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
! 367: error = ENETRESET;
! 368: }
! 369: break;
! 370: }
! 371: break;
! 372: case SIOCG80211CHANNEL:
! 373: chanreq = (struct ieee80211chanreq *)data;
! 374: switch (ic->ic_state) {
! 375: case IEEE80211_S_INIT:
! 376: case IEEE80211_S_SCAN:
! 377: if (ic->ic_opmode == IEEE80211_M_STA)
! 378: chan = ic->ic_des_chan;
! 379: else
! 380: chan = ic->ic_ibss_chan;
! 381: break;
! 382: default:
! 383: chan = ic->ic_bss->ni_chan;
! 384: break;
! 385: }
! 386: chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
! 387: break;
! 388: #if 0
! 389: case SIOCG80211ZSTATS:
! 390: #endif
! 391: case SIOCG80211STATS:
! 392: ifr = (struct ifreq *)data;
! 393: copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
! 394: #if 0
! 395: if (cmd == SIOCG80211ZSTATS)
! 396: memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
! 397: #endif
! 398: break;
! 399: case SIOCS80211TXPOWER:
! 400: if ((error = suser(curproc, 0)) != 0)
! 401: break;
! 402: txpower = (struct ieee80211_txpower *)data;
! 403: if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
! 404: error = EINVAL;
! 405: break;
! 406: }
! 407: if (!(IEEE80211_TXPOWER_MIN < txpower->i_val &&
! 408: txpower->i_val < IEEE80211_TXPOWER_MAX)) {
! 409: error = EINVAL;
! 410: break;
! 411: }
! 412: ic->ic_txpower = txpower->i_val;
! 413: error = ENETRESET;
! 414: break;
! 415: case SIOCG80211TXPOWER:
! 416: txpower = (struct ieee80211_txpower *)data;
! 417: if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
! 418: error = EINVAL;
! 419: else
! 420: txpower->i_val = ic->ic_txpower;
! 421: break;
! 422: case SIOCSIFMTU:
! 423: ifr = (struct ifreq *)data;
! 424: if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
! 425: ifr->ifr_mtu <= IEEE80211_MTU_MAX))
! 426: error = EINVAL;
! 427: else
! 428: ifp->if_mtu = ifr->ifr_mtu;
! 429: break;
! 430: case SIOCS80211SCAN:
! 431: if ((error = suser(curproc, 0)) != 0)
! 432: break;
! 433: if (ic->ic_opmode == IEEE80211_M_HOSTAP)
! 434: break;
! 435: if ((ifp->if_flags & IFF_UP) == 0) {
! 436: error = ENETDOWN;
! 437: break;
! 438: }
! 439: if ((ic->ic_scan_lock & IEEE80211_SCAN_REQUEST) == 0) {
! 440: if (ic->ic_scan_lock & IEEE80211_SCAN_LOCKED)
! 441: ic->ic_scan_lock |= IEEE80211_SCAN_RESUME;
! 442: ic->ic_scan_lock |= IEEE80211_SCAN_REQUEST;
! 443: if (ic->ic_state != IEEE80211_S_SCAN)
! 444: ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
! 445: }
! 446: /* Let the userspace process wait for completion */
! 447: error = tsleep(&ic->ic_scan_lock, PCATCH, "80211scan",
! 448: hz * IEEE80211_SCAN_TIMEOUT);
! 449: break;
! 450: case SIOCG80211NODE:
! 451: nr = (struct ieee80211_nodereq *)data;
! 452: ni = ieee80211_find_node(ic, nr->nr_macaddr);
! 453: if (ni == NULL) {
! 454: error = ENOENT;
! 455: break;
! 456: }
! 457: ieee80211_node2req(ic, ni, nr);
! 458: break;
! 459: case SIOCS80211NODE:
! 460: if ((error = suser(curproc, 0)) != 0)
! 461: break;
! 462: if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
! 463: error = EINVAL;
! 464: break;
! 465: }
! 466: nr = (struct ieee80211_nodereq *)data;
! 467:
! 468: ni = ieee80211_find_node(ic, nr->nr_macaddr);
! 469: if (ni == NULL)
! 470: ni = ieee80211_alloc_node(ic, nr->nr_macaddr);
! 471: if (ni == NULL) {
! 472: error = ENOENT;
! 473: break;
! 474: }
! 475:
! 476: if (nr->nr_flags & IEEE80211_NODEREQ_COPY)
! 477: ieee80211_req2node(ic, nr, ni);
! 478: break;
! 479: case SIOCS80211DELNODE:
! 480: if ((error = suser(curproc, 0)) != 0)
! 481: break;
! 482: nr = (struct ieee80211_nodereq *)data;
! 483: ni = ieee80211_find_node(ic, nr->nr_macaddr);
! 484: if (ni == NULL)
! 485: error = ENOENT;
! 486: else if (ni == ic->ic_bss)
! 487: error = EPERM;
! 488: else {
! 489: if (ni->ni_state == IEEE80211_STA_COLLECT)
! 490: break;
! 491:
! 492: /* Disassociate station. */
! 493: if (ni->ni_state == IEEE80211_STA_ASSOC)
! 494: IEEE80211_SEND_MGMT(ic, ni,
! 495: IEEE80211_FC0_SUBTYPE_DISASSOC,
! 496: IEEE80211_REASON_ASSOC_LEAVE);
! 497:
! 498: /* Deauth station. */
! 499: if (ni->ni_state >= IEEE80211_STA_AUTH)
! 500: IEEE80211_SEND_MGMT(ic, ni,
! 501: IEEE80211_FC0_SUBTYPE_DEAUTH,
! 502: IEEE80211_REASON_AUTH_LEAVE);
! 503:
! 504: ieee80211_release_node(ic, ni);
! 505: }
! 506: break;
! 507: case SIOCG80211ALLNODES:
! 508: na = (struct ieee80211_nodereq_all *)data;
! 509: na->na_nodes = i = 0;
! 510: ni = RB_MIN(ieee80211_tree, &ic->ic_tree);
! 511: while (ni && na->na_size >=
! 512: i + sizeof(struct ieee80211_nodereq)) {
! 513: ieee80211_node2req(ic, ni, &nrbuf);
! 514: error = copyout(&nrbuf, (caddr_t)na->na_node + i,
! 515: sizeof(struct ieee80211_nodereq));
! 516: if (error)
! 517: break;
! 518: i += sizeof(struct ieee80211_nodereq);
! 519: na->na_nodes++;
! 520: ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni);
! 521: }
! 522: break;
! 523: case SIOCG80211FLAGS:
! 524: flags = ic->ic_flags;
! 525: if (ic->ic_opmode != IEEE80211_M_HOSTAP)
! 526: flags &= ~IEEE80211_F_HOSTAPMASK;
! 527: ifr->ifr_flags = flags >> IEEE80211_F_USERSHIFT;
! 528: break;
! 529: case SIOCS80211FLAGS:
! 530: if ((error = suser(curproc, 0)) != 0)
! 531: break;
! 532: flags = (u_int32_t)ifr->ifr_flags << IEEE80211_F_USERSHIFT;
! 533: if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
! 534: (flags & IEEE80211_F_HOSTAPMASK)) {
! 535: error = EINVAL;
! 536: break;
! 537: }
! 538: ic->ic_flags = (ic->ic_flags & ~IEEE80211_F_USERMASK) | flags;
! 539: error = ENETRESET;
! 540: break;
! 541: default:
! 542: error = EINVAL;
! 543: break;
! 544: }
! 545: return error;
! 546: }
CVSweb