1/* $NetBSD: ieee80211_ioctl.c,v 1.56 2011/06/12 00:07:19 christos Exp $ */ 2/*- 3 * Copyright (c) 2001 Atsushi Onoe 4 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting 5 * All rights reserved. 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 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * Alternatively, this software may be distributed under the terms of the 19 * GNU General Public License ("GPL") version 2 as published by the Free 20 * Software Foundation. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34#include <sys/cdefs.h> 35#ifdef __FreeBSD__ 36__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_ioctl.c,v 1.35 2005/08/30 14:27:47 avatar Exp $"); 37#endif 38#ifdef __NetBSD__ 39__KERNEL_RCSID(0, "$NetBSD: ieee80211_ioctl.c,v 1.56 2011/06/12 00:07:19 christos Exp $"); 40#endif 41 42/* 43 * IEEE 802.11 ioctl support (FreeBSD-specific) 44 */ 45 46#include "opt_inet.h" 47#include "opt_compat_netbsd.h" 48 49#include <sys/endian.h> 50#include <sys/param.h> 51#include <sys/kernel.h> 52#include <sys/socket.h> 53#include <sys/sockio.h> 54#include <sys/systm.h> 55#include <sys/proc.h> 56#include <sys/kauth.h> 57 58#include <net/if.h> 59#include <net/if_arp.h> 60#include <net/if_media.h> 61#include <net/if_ether.h> 62 63#ifdef INET 64#include <netinet/in.h> 65#include <netinet/if_inarp.h> 66#endif 67 68#include <net80211/ieee80211_var.h> 69#include <net80211/ieee80211_ioctl.h> 70 71#include <dev/ic/wi_ieee.h> 72 73#if defined(COMPAT_09) || defined(COMPAT_10) || defined(COMPAT_11) || \ 74 defined(COMPAT_12) || defined(COMPAT_13) || defined(COMPAT_14) || \ 75 defined(COMPAT_15) || defined(COMPAT_16) || defined(COMPAT_20) || \ 76 defined(COMPAT_30) || defined(COMPAT_40) 77#include <compat/sys/sockio.h> 78#endif 79 80#ifdef __FreeBSD__ 81#define IS_UP(_ic) \ 82 (((_ic)->ic_ifp->if_flags & IFF_UP) && \ 83 ((_ic)->ic_ifp->if_drv_flags & IFF_DRV_RUNNING)) 84#endif 85#ifdef __NetBSD__ 86#define IS_UP(_ic) \ 87 (((_ic)->ic_ifp->if_flags & IFF_UP) && \ 88 ((_ic)->ic_ifp->if_flags & IFF_RUNNING)) 89#endif 90#define IS_UP_AUTO(_ic) \ 91 (IS_UP(_ic) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO) 92 93/* 94 * XXX 95 * Wireless LAN specific configuration interface, which is compatible 96 * with wicontrol(8). 97 */ 98 99struct wi_read_ap_args { 100 int i; /* result count */ 101 struct wi_apinfo *ap; /* current entry in result buffer */ 102 void * max; /* result buffer bound */ 103}; 104 105static void 106wi_read_ap_result(void *arg, struct ieee80211_node *ni) 107{ 108 struct ieee80211com *ic = ni->ni_ic; 109 struct wi_read_ap_args *sa = arg; 110 struct wi_apinfo *ap = sa->ap; 111 struct ieee80211_rateset *rs; 112 int j; 113 114 if ((void *)(ap + 1) > sa->max) 115 return; 116 memset(ap, 0, sizeof(struct wi_apinfo)); 117 if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 118 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr); 119 ap->namelen = ic->ic_des_esslen; 120 if (ic->ic_des_esslen) 121 memcpy(ap->name, ic->ic_des_essid, 122 ic->ic_des_esslen); 123 } else { 124 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid); 125 ap->namelen = ni->ni_esslen; 126 if (ni->ni_esslen) 127 memcpy(ap->name, ni->ni_essid, 128 ni->ni_esslen); 129 } 130 ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan); 131 ap->signal = ic->ic_node_getrssi(ni); 132 ap->capinfo = ni->ni_capinfo; 133 ap->interval = ni->ni_intval; 134 rs = &ni->ni_rates; 135 for (j = 0; j < rs->rs_nrates; j++) { 136 if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) { 137 ap->rate = (rs->rs_rates[j] & 138 IEEE80211_RATE_VAL) * 5; /* XXX */ 139 } 140 } 141 sa->i++; 142 sa->ap++; 143} 144 145struct wi_read_prism2_args { 146 int i; /* result count */ 147 struct wi_scan_res *res;/* current entry in result buffer */ 148 void * max; /* result buffer bound */ 149}; 150 151#if 0 152static void 153wi_read_prism2_result(void *arg, struct ieee80211_node *ni) 154{ 155 struct ieee80211com *ic = ni->ni_ic; 156 struct wi_read_prism2_args *sa = arg; 157 struct wi_scan_res *res = sa->res; 158 159 if ((void *)(res + 1) > sa->max) 160 return; 161 res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan); 162 res->wi_noise = 0; 163 res->wi_signal = ic->ic_node_getrssi(ni); 164 IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid); 165 res->wi_interval = ni->ni_intval; 166 res->wi_capinfo = ni->ni_capinfo; 167 res->wi_ssid_len = ni->ni_esslen; 168 memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN); 169 /* NB: assumes wi_srates holds <= ni->ni_rates */ 170 memcpy(res->wi_srates, ni->ni_rates.rs_rates, 171 sizeof(res->wi_srates)); 172 if (ni->ni_rates.rs_nrates < 10) 173 res->wi_srates[ni->ni_rates.rs_nrates] = 0; 174 res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate]; 175 res->wi_rsvd = 0; 176 177 sa->i++; 178 sa->res++; 179} 180 181struct wi_read_sigcache_args { 182 int i; /* result count */ 183 struct wi_sigcache *wsc;/* current entry in result buffer */ 184 void * max; /* result buffer bound */ 185}; 186 187static void 188wi_read_sigcache(void *arg, struct ieee80211_node *ni) 189{ 190 struct ieee80211com *ic = ni->ni_ic; 191 struct wi_read_sigcache_args *sa = arg; 192 struct wi_sigcache *wsc = sa->wsc; 193 194 if ((void *)(wsc + 1) > sa->max) 195 return; 196 memset(wsc, 0, sizeof(struct wi_sigcache)); 197 IEEE80211_ADDR_COPY(wsc->macsrc, ni->ni_macaddr); 198 wsc->signal = ic->ic_node_getrssi(ni); 199 200 sa->wsc++; 201 sa->i++; 202} 203#endif 204 205int 206ieee80211_cfgget(struct ieee80211com *ic, u_long cmd, void *data) 207{ 208 struct ifnet *ifp = ic->ic_ifp; 209 int i, j, error; 210 struct ifreq *ifr = (struct ifreq *)data; 211 struct wi_req *wreq; 212 struct wi_ltv_keys *keys; 213 214 wreq = malloc(sizeof(*wreq), M_TEMP, M_WAITOK); 215 error = copyin(ifr->ifr_data, wreq, sizeof(*wreq)); 216 if (error) 217 goto out; 218 wreq->wi_len = 0; 219 switch (wreq->wi_type) { 220 case WI_RID_SERIALNO: 221 case WI_RID_STA_IDENTITY: 222 /* nothing appropriate */ 223 break; 224 case WI_RID_NODENAME: 225 strlcpy((char *)&wreq->wi_val[1], hostname, 226 sizeof(wreq->wi_val) - sizeof(wreq->wi_val[0])); 227 wreq->wi_val[0] = htole16(strlen(hostname)); 228 wreq->wi_len = (1 + strlen(hostname) + 1) / 2; 229 break; 230 case WI_RID_CURRENT_SSID: 231 if (ic->ic_state != IEEE80211_S_RUN) { 232 wreq->wi_val[0] = 0; 233 wreq->wi_len = 1; 234 break; 235 } 236 wreq->wi_val[0] = htole16(ic->ic_bss->ni_esslen); 237 memcpy(&wreq->wi_val[1], ic->ic_bss->ni_essid, 238 ic->ic_bss->ni_esslen); 239 wreq->wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2; 240 break; 241 case WI_RID_OWN_SSID: 242 case WI_RID_DESIRED_SSID: 243 wreq->wi_val[0] = htole16(ic->ic_des_esslen); 244 memcpy(&wreq->wi_val[1], ic->ic_des_essid, ic->ic_des_esslen); 245 wreq->wi_len = (1 + ic->ic_des_esslen + 1) / 2; 246 break; 247 case WI_RID_CURRENT_BSSID: 248 if (ic->ic_state == IEEE80211_S_RUN) 249 IEEE80211_ADDR_COPY(wreq->wi_val, ic->ic_bss->ni_bssid); 250 else 251 memset(wreq->wi_val, 0, IEEE80211_ADDR_LEN); 252 wreq->wi_len = IEEE80211_ADDR_LEN / 2; 253 break; 254 case WI_RID_CHANNEL_LIST: 255 memset(wreq->wi_val, 0, sizeof(wreq->wi_val)); 256 /* 257 * Since channel 0 is not available for DS, channel 1 258 * is assigned to LSB on WaveLAN. 259 */ 260 if (ic->ic_phytype == IEEE80211_T_DS) 261 i = 1; 262 else 263 i = 0; 264 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) 265 if (isset(ic->ic_chan_active, i)) { 266 setbit((u_int8_t *)wreq->wi_val, j); 267 wreq->wi_len = j / 16 + 1; 268 } 269 break; 270 case WI_RID_OWN_CHNL: 271 wreq->wi_val[0] = htole16( 272 ieee80211_chan2ieee(ic, ic->ic_ibss_chan)); 273 wreq->wi_len = 1; 274 break; 275 case WI_RID_CURRENT_CHAN: 276 wreq->wi_val[0] = htole16( 277 ieee80211_chan2ieee(ic, ic->ic_curchan)); 278 wreq->wi_len = 1; 279 break; 280 case WI_RID_COMMS_QUALITY: 281 wreq->wi_val[0] = 0; /* quality */ 282 wreq->wi_val[1] = htole16(ic->ic_node_getrssi(ic->ic_bss)); 283 wreq->wi_val[2] = 0; /* noise */ 284 wreq->wi_len = 3; 285 break; 286 case WI_RID_PROMISC: 287 wreq->wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0); 288 wreq->wi_len = 1; 289 break; 290 case WI_RID_PORTTYPE: 291 wreq->wi_val[0] = htole16(ic->ic_opmode); 292 wreq->wi_len = 1; 293 break; 294 case WI_RID_MAC_NODE: 295 IEEE80211_ADDR_COPY(wreq->wi_val, ic->ic_myaddr); 296 wreq->wi_len = IEEE80211_ADDR_LEN / 2; 297 break; 298 case WI_RID_TX_RATE: 299 if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) 300 wreq->wi_val[0] = 0; /* auto */ 301 else 302 wreq->wi_val[0] = htole16( 303 (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] & 304 IEEE80211_RATE_VAL) / 2); 305 wreq->wi_len = 1; 306 break; 307 case WI_RID_CUR_TX_RATE: 308 wreq->wi_val[0] = htole16( 309 (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] & 310 IEEE80211_RATE_VAL) / 2); 311 wreq->wi_len = 1; 312 break; 313 case WI_RID_FRAG_THRESH: 314 wreq->wi_val[0] = htole16(ic->ic_fragthreshold); 315 wreq->wi_len = 1; 316 break; 317 case WI_RID_RTS_THRESH: 318 wreq->wi_val[0] = htole16(ic->ic_rtsthreshold); 319 wreq->wi_len = 1; 320 break; 321 case WI_RID_CREATE_IBSS: 322 wreq->wi_val[0] = 323 htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0); 324 wreq->wi_len = 1; 325 break; 326 case WI_RID_MICROWAVE_OVEN: 327 wreq->wi_val[0] = 0; /* no ... not supported */ 328 wreq->wi_len = 1; 329 break; 330 case WI_RID_ROAMING_MODE: 331 wreq->wi_val[0] = htole16(ic->ic_roaming); /* XXX map */ 332 wreq->wi_len = 1; 333 break; 334 case WI_RID_SYSTEM_SCALE: 335 wreq->wi_val[0] = htole16(1); /* low density ... not supp */ 336 wreq->wi_len = 1; 337 break; 338 case WI_RID_PM_ENABLED: 339 wreq->wi_val[0] = 340 htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0); 341 wreq->wi_len = 1; 342 break; 343 case WI_RID_MAX_SLEEP: 344 wreq->wi_val[0] = htole16(ic->ic_lintval); 345 wreq->wi_len = 1; 346 break; 347 case WI_RID_CUR_BEACON_INT: 348 wreq->wi_val[0] = htole16(ic->ic_bss->ni_intval); 349 wreq->wi_len = 1; 350 break; 351 case WI_RID_WEP_AVAIL: 352 wreq->wi_val[0] = htole16(1); /* always available */ 353 wreq->wi_len = 1; 354 break; 355 case WI_RID_CNFAUTHMODE: 356 wreq->wi_val[0] = htole16(1); /* TODO: open system only */ 357 wreq->wi_len = 1; 358 break; 359 case WI_RID_ENCRYPTION: 360 wreq->wi_val[0] = 361 htole16((ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0); 362 wreq->wi_len = 1; 363 break; 364 case WI_RID_TX_CRYPT_KEY: 365 wreq->wi_val[0] = htole16(ic->ic_def_txkey); 366 wreq->wi_len = 1; 367 break; 368 case WI_RID_DEFLT_CRYPT_KEYS: 369 keys = (struct wi_ltv_keys *)wreq; 370 /* do not show keys to non-root user */ 371 error = kauth_authorize_network(curlwp->l_cred, 372 KAUTH_NETWORK_INTERFACE, 373 KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp, 374 NULL, NULL); 375 if (error) { 376 memset(keys, 0, sizeof(*keys)); 377 error = 0; 378 break; 379 } 380 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 381 keys->wi_keys[i].wi_keylen = 382 htole16(ic->ic_nw_keys[i].wk_keylen); 383 memcpy(keys->wi_keys[i].wi_keydat, 384 ic->ic_nw_keys[i].wk_key, 385 ic->ic_nw_keys[i].wk_keylen); 386 } 387 wreq->wi_len = sizeof(*keys) / 2; 388 break; 389 case WI_RID_MAX_DATALEN: 390 wreq->wi_val[0] = htole16(ic->ic_fragthreshold); 391 wreq->wi_len = 1; 392 break; 393 case WI_RID_DBM_ADJUST: 394 /* not supported, we just pass rssi value from driver. */ 395 break; 396 case WI_RID_IFACE_STATS: 397 /* XXX: should be implemented in lower drivers */ 398 break; 399 case WI_RID_READ_APS: 400 /* 401 * Don't return results until active scan completes. 402 */ 403 if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) { 404 struct wi_read_ap_args args; 405 406 args.i = 0; 407 args.ap = (void *)((char *)wreq->wi_val + sizeof(i)); 408 args.max = (void *)(wreq + 1); 409 ieee80211_iterate_nodes(&ic->ic_scan, 410 wi_read_ap_result, &args); 411 memcpy(wreq->wi_val, &args.i, sizeof(args.i)); 412 wreq->wi_len = (sizeof(int) + 413 sizeof(struct wi_apinfo) * args.i) / 2; 414 } else 415 error = EINPROGRESS; 416 break; 417#if 0 418 case WI_RID_SCAN_RES: /* compatibility interface */ 419 if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) { 420 struct wi_read_prism2_args args; 421 struct wi_scan_p2_hdr *p2; 422 423 /* NB: use Prism2 format so we can include rate info */ 424 p2 = (struct wi_scan_p2_hdr *)wreq->wi_val; 425 args.i = 0; 426 args.res = (void *)&p2[1]; 427 args.max = (void *)(wreq + 1); 428 ieee80211_iterate_nodes(&ic->ic_scan, 429 wi_read_prism2_result, &args); 430 p2->wi_rsvd = 0; 431 p2->wi_reason = args.i; 432 wreq->wi_len = (sizeof(*p2) + 433 sizeof(struct wi_scan_res) * args.i) / 2; 434 } else 435 error = EINPROGRESS; 436 break; 437 case WI_RID_READ_CACHE: { 438 struct wi_read_sigcache_args args; 439 args.i = 0; 440 args.wsc = (struct wi_sigcache *) wreq->wi_val; 441 args.max = (void *)(wreq + 1); 442 ieee80211_iterate_nodes(&ic->ic_scan, wi_read_sigcache, &args); 443 wreq->wi_len = sizeof(struct wi_sigcache) * args.i / 2; 444 break; 445 } 446#endif 447 default: 448 error = EINVAL; 449 break; 450 } 451 if (error == 0) { 452 wreq->wi_len++; 453 error = copyout(wreq, ifr->ifr_data, sizeof(*wreq)); 454 } 455out: 456 free(wreq, M_TEMP); 457 return error; 458} 459 460static int 461findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate) 462{ 463#define IEEERATE(_ic,_m,_i) \ 464 ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL) 465 int i, nrates = ic->ic_sup_rates[mode].rs_nrates; 466 for (i = 0; i < nrates; i++) 467 if (IEEERATE(ic, mode, i) == rate) 468 return i; 469 return -1; 470#undef IEEERATE 471} 472 473/* 474 * Prepare to do a user-initiated scan for AP's. If no 475 * current/default channel is setup or the current channel 476 * is invalid then pick the first available channel from 477 * the active list as the place to start the scan. 478 */ 479static int 480ieee80211_setupscan(struct ieee80211com *ic, const u_int8_t chanlist[]) 481{ 482 483 /* 484 * XXX don't permit a scan to be started unless we 485 * know the device is ready. For the moment this means 486 * the device is marked up as this is the required to 487 * initialize the hardware. It would be better to permit 488 * scanning prior to being up but that'll require some 489 * changes to the infrastructure. 490 */ 491 if (!IS_UP(ic)) 492 return EINVAL; 493 memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active)); 494 /* 495 * We force the state to INIT before calling ieee80211_new_state 496 * to get ieee80211_begin_scan called. We really want to scan w/o 497 * altering the current state but that's not possible right now. 498 */ 499 /* XXX handle proberequest case */ 500 ic->ic_state = IEEE80211_S_INIT; /* XXX bypass state machine */ 501 return 0; 502} 503 504int 505ieee80211_cfgset(struct ieee80211com *ic, u_long cmd, void *data) 506{ 507 struct ifnet *ifp = ic->ic_ifp; 508 int i, j, len, error, rate; 509 struct ifreq *ifr = (struct ifreq *)data; 510 struct wi_ltv_keys *keys; 511 struct wi_req *wreq; 512 u_int8_t chanlist[IEEE80211_CHAN_BYTES]; 513 514 wreq = malloc(sizeof(*wreq), M_TEMP, M_WAITOK); 515 error = copyin(ifr->ifr_data, wreq, sizeof(*wreq)); 516 if (error) 517 goto out; 518 len = wreq->wi_len ? (wreq->wi_len - 1) * 2 : 0; 519 switch (wreq->wi_type) { 520 case WI_RID_SERIALNO: 521 case WI_RID_NODENAME: 522 case WI_RID_CURRENT_SSID: 523 error = EPERM; 524 goto out; 525 case WI_RID_OWN_SSID: 526 case WI_RID_DESIRED_SSID: 527 if (le16toh(wreq->wi_val[0]) * 2 > len || 528 le16toh(wreq->wi_val[0]) > IEEE80211_NWID_LEN) { 529 error = ENOSPC; 530 break; 531 } 532 memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid)); 533 ic->ic_des_esslen = le16toh(wreq->wi_val[0]) * 2; 534 memcpy(ic->ic_des_essid, &wreq->wi_val[1], ic->ic_des_esslen); 535 error = ENETRESET; 536 break; 537 case WI_RID_CURRENT_BSSID: 538 error = EPERM; 539 goto out; 540 case WI_RID_OWN_CHNL: 541 if (len != 2) 542 goto invalid; 543 i = le16toh(wreq->wi_val[0]); 544 if (i < 0 || 545 i > IEEE80211_CHAN_MAX || 546 isclr(ic->ic_chan_active, i)) 547 goto invalid; 548 ic->ic_ibss_chan = &ic->ic_channels[i]; 549 if (ic->ic_opmode == IEEE80211_M_MONITOR) 550 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 551 else 552 error = ENETRESET; 553 break; 554 case WI_RID_CURRENT_CHAN: 555 case WI_RID_COMMS_QUALITY: 556 error = EPERM; 557 goto out; 558 case WI_RID_PROMISC: 559 if (len != 2) 560 goto invalid; 561 if (ifp->if_flags & IFF_PROMISC) { 562 if (wreq->wi_val[0] == 0) { 563 ifp->if_flags &= ~IFF_PROMISC; 564 error = ENETRESET; 565 } 566 } else { 567 if (wreq->wi_val[0] != 0) { 568 ifp->if_flags |= IFF_PROMISC; 569 error = ENETRESET; 570 } 571 } 572 break; 573 case WI_RID_PORTTYPE: 574 if (len != 2) 575 goto invalid; 576 switch (le16toh(wreq->wi_val[0])) { 577 case IEEE80211_M_STA: 578 break; 579 case IEEE80211_M_IBSS: 580 if (!(ic->ic_caps & IEEE80211_C_IBSS)) 581 goto invalid; 582 break; 583 case IEEE80211_M_AHDEMO: 584 if (ic->ic_phytype != IEEE80211_T_DS || 585 !(ic->ic_caps & IEEE80211_C_AHDEMO)) 586 goto invalid; 587 break; 588 case IEEE80211_M_HOSTAP: 589 if (!(ic->ic_caps & IEEE80211_C_HOSTAP)) 590 goto invalid; 591 break; 592 default: 593 goto invalid; 594 } 595 if (le16toh(wreq->wi_val[0]) != ic->ic_opmode) { 596 ic->ic_opmode = le16toh(wreq->wi_val[0]); 597 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 598 } 599 break; 600#if 0 601 case WI_RID_MAC_NODE: 602 if (len != IEEE80211_ADDR_LEN) 603 goto invalid; 604 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq->wi_val); 605 /* if_init will copy lladdr into ic_myaddr */ 606 error = ENETRESET; 607 break; 608#endif 609 case WI_RID_TX_RATE: 610 if (len != 2) 611 goto invalid; 612 if (wreq->wi_val[0] == 0) { 613 /* auto */ 614 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 615 break; 616 } 617 rate = 2 * le16toh(wreq->wi_val[0]); 618 if (ic->ic_curmode == IEEE80211_MODE_AUTO) { 619 /* 620 * In autoselect mode search for the rate. We take 621 * the first instance which may not be right, but we 622 * are limited by the interface. Note that we also 623 * lock the mode to insure the rate is meaningful 624 * when it is used. 625 */ 626 for (j = IEEE80211_MODE_11A; 627 j < IEEE80211_MODE_MAX; j++) { 628 if ((ic->ic_modecaps & (1<<j)) == 0) 629 continue; 630 i = findrate(ic, j, rate); 631 if (i != -1) { 632 /* lock mode too */ 633 ic->ic_curmode = j; 634 goto setrate; 635 } 636 } 637 } else { 638 i = findrate(ic, ic->ic_curmode, rate); 639 if (i != -1) 640 goto setrate; 641 } 642 goto invalid; 643 setrate: 644 ic->ic_fixed_rate = i; 645 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 646 break; 647 case WI_RID_CUR_TX_RATE: 648 error = EPERM; 649 goto out; 650 case WI_RID_FRAG_THRESH: 651 if (len != 2) 652 goto invalid; 653 ic->ic_fragthreshold = le16toh(wreq->wi_val[0]); 654 error = ENETRESET; 655 break; 656 case WI_RID_RTS_THRESH: 657 if (len != 2) 658 goto invalid; 659 ic->ic_rtsthreshold = le16toh(wreq->wi_val[0]); 660 error = ENETRESET; 661 break; 662 case WI_RID_CREATE_IBSS: 663 if (len != 2) 664 goto invalid; 665 if (wreq->wi_val[0] != 0) { 666 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) 667 goto invalid; 668 if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) { 669 ic->ic_flags |= IEEE80211_F_IBSSON; 670 if (ic->ic_opmode == IEEE80211_M_IBSS && 671 ic->ic_state == IEEE80211_S_SCAN) 672 error = IS_UP_AUTO(ic) ? ENETRESET : 0; 673 } 674 } else { 675 if (ic->ic_flags & IEEE80211_F_IBSSON) { 676 ic->ic_flags &= ~IEEE80211_F_IBSSON; 677 if (ic->ic_flags & IEEE80211_F_SIBSS) { 678 ic->ic_flags &= ~IEEE80211_F_SIBSS; 679 error = IS_UP_AUTO(ic) ? ENETRESET : 0; 680 } 681 } 682 } 683 break; 684 case WI_RID_MICROWAVE_OVEN: 685 if (len != 2) 686 goto invalid; 687 if (wreq->wi_val[0] != 0) 688 goto invalid; /* not supported */ 689 break; 690 case WI_RID_ROAMING_MODE: 691 if (len != 2) 692 goto invalid; 693 i = le16toh(wreq->wi_val[0]); 694 if (i > IEEE80211_ROAMING_MANUAL) 695 goto invalid; /* not supported */ 696 ic->ic_roaming = i; 697 break; 698 case WI_RID_SYSTEM_SCALE: 699 if (len != 2) 700 goto invalid; 701 if (le16toh(wreq->wi_val[0]) != 1) 702 goto invalid; /* not supported */ 703 break; 704 case WI_RID_PM_ENABLED: 705 if (len != 2) 706 goto invalid; 707 if (wreq->wi_val[0] != 0) { 708 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) 709 goto invalid; 710 if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { 711 ic->ic_flags |= IEEE80211_F_PMGTON; 712 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 713 } 714 } else { 715 if (ic->ic_flags & IEEE80211_F_PMGTON) { 716 ic->ic_flags &= ~IEEE80211_F_PMGTON; 717 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 718 } 719 } 720 break; 721 case WI_RID_MAX_SLEEP: 722 if (len != 2) 723 goto invalid; 724 ic->ic_lintval = le16toh(wreq->wi_val[0]); 725 if (ic->ic_flags & IEEE80211_F_PMGTON) 726 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 727 break; 728 case WI_RID_CUR_BEACON_INT: 729 case WI_RID_WEP_AVAIL: 730 error = EPERM; 731 goto out; 732 case WI_RID_CNFAUTHMODE: 733 if (len != 2) 734 goto invalid; 735 i = le16toh(wreq->wi_val[0]); 736 if (i > IEEE80211_AUTH_WPA) 737 goto invalid; 738 ic->ic_bss->ni_authmode = i; /* XXX ENETRESET? */ 739 error = ENETRESET; 740 break; 741 case WI_RID_ENCRYPTION: 742 if (len != 2) 743 goto invalid; 744 if (wreq->wi_val[0] != 0) { 745 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) 746 goto invalid; 747 if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) { 748 ic->ic_flags |= IEEE80211_F_PRIVACY; 749 error = ENETRESET; 750 } 751 } else { 752 if (ic->ic_flags & IEEE80211_F_PRIVACY) { 753 ic->ic_flags &= ~IEEE80211_F_PRIVACY; 754 error = ENETRESET; 755 } 756 } 757 break; 758 case WI_RID_TX_CRYPT_KEY: 759 if (len != 2) 760 goto invalid; 761 i = le16toh(wreq->wi_val[0]); 762 if (i >= IEEE80211_WEP_NKID) 763 goto invalid; 764 ic->ic_def_txkey = i; 765 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 766 break; 767 case WI_RID_DEFLT_CRYPT_KEYS: 768 if (len != sizeof(struct wi_ltv_keys)) 769 goto invalid; 770 keys = (struct wi_ltv_keys *)wreq; 771 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 772 len = le16toh(keys->wi_keys[i].wi_keylen); 773 if (len != 0 && len < IEEE80211_WEP_KEYLEN) 774 goto invalid; 775 if (len > IEEE80211_KEYBUF_SIZE) 776 goto invalid; 777 } 778 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 779 struct ieee80211_key *k = &ic->ic_nw_keys[i]; 780 781 len = le16toh(keys->wi_keys[i].wi_keylen); 782 k->wk_keylen = len; 783 k->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV; 784 memset(k->wk_key, 0, sizeof(k->wk_key)); 785 memcpy(k->wk_key, keys->wi_keys[i].wi_keydat, len); 786#if 0 787 k->wk_type = IEEE80211_CIPHER_WEP; 788#endif 789 } 790 error = ENETRESET; 791 break; 792 case WI_RID_MAX_DATALEN: 793 if (len != 2) 794 goto invalid; 795 len = le16toh(wreq->wi_val[0]); 796 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN) 797 goto invalid; 798 ic->ic_fragthreshold = len; 799 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 800 break; 801 case WI_RID_IFACE_STATS: 802 error = EPERM; 803 break; 804 case WI_RID_SCAN_REQ: /* XXX wicontrol */ 805 if (ic->ic_opmode == IEEE80211_M_HOSTAP) 806 break; 807 error = ieee80211_setupscan(ic, ic->ic_chan_avail); 808 if (error == 0) 809 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 810 break; 811 case WI_RID_SCAN_APS: 812 if (ic->ic_opmode == IEEE80211_M_HOSTAP) 813 break; 814 len--; /* XXX: tx rate? */ 815 /* FALLTHRU */ 816 case WI_RID_CHANNEL_LIST: 817 memset(chanlist, 0, sizeof(chanlist)); 818 /* 819 * Since channel 0 is not available for DS, channel 1 820 * is assigned to LSB on WaveLAN. 821 */ 822 if (ic->ic_phytype == IEEE80211_T_DS) 823 i = 1; 824 else 825 i = 0; 826 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) { 827 if ((j / 8) >= len) 828 break; 829 if (isclr((u_int8_t *)wreq->wi_val, j)) 830 continue; 831 if (isclr(ic->ic_chan_active, i)) { 832 if (wreq->wi_type != WI_RID_CHANNEL_LIST) 833 continue; 834 if (isclr(ic->ic_chan_avail, i)) { 835 error = EPERM; 836 goto out; 837 } 838 } 839 setbit(chanlist, i); 840 } 841 error = ieee80211_setupscan(ic, chanlist); 842 if (wreq->wi_type == WI_RID_CHANNEL_LIST) { 843 /* NB: ignore error from ieee80211_setupscan */ 844 error = ENETRESET; 845 } else if (error == 0) 846 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 847 break; 848 default: 849 goto invalid; 850 } 851 if (error == ENETRESET && !IS_UP_AUTO(ic)) 852 error = 0; 853out: 854 free(wreq, M_TEMP); 855 return error; 856invalid: 857 free(wreq, M_TEMP); 858 return EINVAL; 859} 860 861static int 862cap2cipher(int flag) 863{ 864 switch (flag) { 865 case IEEE80211_C_WEP: return IEEE80211_CIPHER_WEP; 866 case IEEE80211_C_AES: return IEEE80211_CIPHER_AES_OCB; 867 case IEEE80211_C_AES_CCM: return IEEE80211_CIPHER_AES_CCM; 868 case IEEE80211_C_CKIP: return IEEE80211_CIPHER_CKIP; 869 case IEEE80211_C_TKIP: return IEEE80211_CIPHER_TKIP; 870 } 871 return -1; 872} 873 874static int 875ieee80211_ioctl_getkey(struct ieee80211com *ic, struct ieee80211req *ireq) 876{ 877 struct ieee80211_node *ni; 878 struct ieee80211req_key ik; 879 struct ieee80211_key *wk; 880 const struct ieee80211_cipher *cip; 881 u_int kid; 882 int error; 883 884 if (ireq->i_len != sizeof(ik)) 885 return EINVAL; 886 error = copyin(ireq->i_data, &ik, sizeof(ik)); 887 if (error) 888 return error; 889 kid = ik.ik_keyix; 890 if (kid == IEEE80211_KEYIX_NONE) { 891 ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr); 892 if (ni == NULL) 893 return EINVAL; /* XXX */ 894 wk = &ni->ni_ucastkey; 895 } else { 896 if (kid >= IEEE80211_WEP_NKID) 897 return EINVAL; 898 wk = &ic->ic_nw_keys[kid]; 899 IEEE80211_ADDR_COPY(&ik.ik_macaddr, ic->ic_bss->ni_macaddr); 900 ni = NULL; 901 } 902 cip = wk->wk_cipher; 903 ik.ik_type = cip->ic_cipher; 904 ik.ik_keylen = wk->wk_keylen; 905 ik.ik_flags = wk->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV); 906 if (wk->wk_keyix == ic->ic_def_txkey) 907 ik.ik_flags |= IEEE80211_KEY_DEFAULT; 908 if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_INTERFACE, 909 KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ic->ic_ifp, NULL, NULL) == 0) { 910 /* NB: only root can read key data */ 911 ik.ik_keyrsc = wk->wk_keyrsc; 912 ik.ik_keytsc = wk->wk_keytsc; 913 memcpy(ik.ik_keydata, wk->wk_key, wk->wk_keylen); 914 if (cip->ic_cipher == IEEE80211_CIPHER_TKIP) { 915 memcpy(ik.ik_keydata+wk->wk_keylen, 916 wk->wk_key + IEEE80211_KEYBUF_SIZE, 917 IEEE80211_MICBUF_SIZE); 918 ik.ik_keylen += IEEE80211_MICBUF_SIZE; 919 } 920 } else { 921 ik.ik_keyrsc = 0; 922 ik.ik_keytsc = 0; 923 memset(ik.ik_keydata, 0, sizeof(ik.ik_keydata)); 924 } 925 if (ni != NULL) 926 ieee80211_free_node(ni); 927 return copyout(&ik, ireq->i_data, sizeof(ik)); 928} 929 930static int 931ieee80211_ioctl_getchanlist(struct ieee80211com *ic, struct ieee80211req *ireq) 932{ 933 size_t len = ireq->i_len; 934 935 if (len > sizeof(ic->ic_chan_active)) 936 len = sizeof(ic->ic_chan_active); 937 return copyout(&ic->ic_chan_active, ireq->i_data, len); 938} 939 940static int 941ieee80211_ioctl_getchaninfo(struct ieee80211com *ic, struct ieee80211req *ireq) 942{ 943 struct ieee80211req_chaninfo *chans; 944 uint32_t i, space; 945 int error; 946 947 /* 948 * Since channel 0 is not available for DS, channel 1 949 * is assigned to LSB on WaveLAN. 950 */ 951 if (ic->ic_phytype == IEEE80211_T_DS) 952 i = 1; 953 else 954 i = 0; 955 956 chans = malloc(sizeof(*chans), M_TEMP, M_WAITOK|M_ZERO); 957 958 for (; i <= IEEE80211_CHAN_MAX; i++) 959 if (isset(ic->ic_chan_avail, i)) { 960 struct ieee80211_channel *c = &ic->ic_channels[i]; 961 chans->ic_chans[chans->ic_nchans].ic_freq = c->ic_freq; 962 chans->ic_chans[chans->ic_nchans].ic_flags = c->ic_flags; 963 chans->ic_nchans++; 964 } 965 space = offsetof(struct ieee80211req_chaninfo, 966 ic_chans[chans->ic_nchans]); 967 if (space > ireq->i_len) 968 space = ireq->i_len; 969 error = copyout(chans, ireq->i_data, space); 970 free(chans, M_TEMP); 971 return error; 972} 973 974static int 975ieee80211_ioctl_getwpaie(struct ieee80211com *ic, struct ieee80211req *ireq) 976{ 977 struct ieee80211_node *ni; 978 struct ieee80211req_wpaie wpaie; 979 int error; 980 981 if (ireq->i_len < IEEE80211_ADDR_LEN) 982 return EINVAL; 983 error = copyin(ireq->i_data, wpaie.wpa_macaddr, IEEE80211_ADDR_LEN); 984 if (error != 0) 985 return error; 986 ni = ieee80211_find_node(&ic->ic_sta, wpaie.wpa_macaddr); 987 if (ni == NULL) 988 return EINVAL; /* XXX */ 989 memset(wpaie.wpa_ie, 0, sizeof(wpaie.wpa_ie)); 990 if (ni->ni_wpa_ie != NULL) { 991 int ielen = ni->ni_wpa_ie[1] + 2; 992 if (ielen > sizeof(wpaie.wpa_ie)) 993 ielen = sizeof(wpaie.wpa_ie); 994 memcpy(wpaie.wpa_ie, ni->ni_wpa_ie, ielen); 995 } 996 ieee80211_free_node(ni); 997 if (ireq->i_len > sizeof(wpaie)) 998 ireq->i_len = sizeof(wpaie); 999 return copyout(&wpaie, ireq->i_data, ireq->i_len); 1000} 1001 1002static int 1003ieee80211_ioctl_getstastats(struct ieee80211com *ic, struct ieee80211req *ireq) 1004{ 1005 struct ieee80211_node *ni; 1006 u_int8_t macaddr[IEEE80211_ADDR_LEN]; 1007 const size_t off = offsetof(struct ieee80211req_sta_stats, is_stats); 1008 int error; 1009 1010 if (ireq->i_len < off) 1011 return EINVAL; 1012 error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN); 1013 if (error != 0) 1014 return error; 1015 ni = ieee80211_find_node(&ic->ic_sta, macaddr); 1016 if (ni == NULL) 1017 return EINVAL; /* XXX */ 1018 if (ireq->i_len > sizeof(struct ieee80211req_sta_stats)) 1019 ireq->i_len = sizeof(struct ieee80211req_sta_stats); 1020 /* NB: copy out only the statistics */ 1021 error = copyout(&ni->ni_stats, (u_int8_t *) ireq->i_data + off, 1022 ireq->i_len - off); 1023 ieee80211_free_node(ni); 1024 return error; 1025} 1026 1027static void 1028get_scan_result(struct ieee80211req_scan_result *sr, 1029 const struct ieee80211_node *ni) 1030{ 1031 struct ieee80211com *ic = ni->ni_ic; 1032 u_int ielen = 0; 1033 1034 memset(sr, 0, sizeof(*sr)); 1035 sr->isr_ssid_len = ni->ni_esslen; 1036 if (ni->ni_wpa_ie != NULL) 1037 ielen += 2+ni->ni_wpa_ie[1]; 1038 if (ni->ni_wme_ie != NULL) 1039 ielen += 2+ni->ni_wme_ie[1]; 1040 1041 /* 1042 * The value sr->isr_ie_len is defined as a uint8_t, so we 1043 * need to be careful to avoid an integer overflow. If the 1044 * value would overflow, we will set isr_ie_len to zero, and 1045 * ieee80211_ioctl_getscanresults (below) will avoid copying 1046 * the (overflowing) data. 1047 */ 1048 if (ielen > 255) 1049 ielen = 0; 1050 sr->isr_ie_len = ielen; 1051 sr->isr_len = sizeof(*sr) + sr->isr_ssid_len + sr->isr_ie_len; 1052 sr->isr_len = roundup(sr->isr_len, sizeof(u_int32_t)); 1053 if (ni->ni_chan != IEEE80211_CHAN_ANYC) { 1054 sr->isr_freq = ni->ni_chan->ic_freq; 1055 sr->isr_flags = ni->ni_chan->ic_flags; 1056 } 1057 sr->isr_rssi = ic->ic_node_getrssi(ni); 1058 sr->isr_intval = ni->ni_intval; 1059 sr->isr_capinfo = ni->ni_capinfo; 1060 sr->isr_erp = ni->ni_erp; 1061 IEEE80211_ADDR_COPY(sr->isr_bssid, ni->ni_bssid); 1062 sr->isr_nrates = ni->ni_rates.rs_nrates; 1063 if (sr->isr_nrates > 15) 1064 sr->isr_nrates = 15; 1065 memcpy(sr->isr_rates, ni->ni_rates.rs_rates, sr->isr_nrates); 1066} 1067 1068static int 1069ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq) 1070{ 1071 union { 1072 struct ieee80211req_scan_result res; 1073 char data[sizeof(struct ieee80211req_scan_result) + IEEE80211_NWID_LEN + 256 * 2]; 1074 } u; 1075 struct ieee80211req_scan_result *sr = &u.res; 1076 struct ieee80211_node_table *nt; 1077 struct ieee80211_node *ni; 1078 int error; 1079 uint32_t space; 1080 u_int8_t *p, *cp; 1081 1082 p = ireq->i_data; 1083 space = ireq->i_len; 1084 error = 0; 1085 /* XXX locking */ 1086 nt = &ic->ic_scan; 1087 TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 1088 /* NB: skip pre-scan node state */ 1089 if (ni->ni_chan == IEEE80211_CHAN_ANYC) 1090 continue; 1091 get_scan_result(sr, ni); 1092 if (sr->isr_len > sizeof(u)) 1093 continue; /* XXX */ 1094 if (space < sr->isr_len) 1095 break; 1096 cp = (u_int8_t *)(sr+1); 1097 memcpy(cp, ni->ni_essid, ni->ni_esslen); 1098 cp += ni->ni_esslen; 1099 if (sr->isr_ie_len > 0 && ni->ni_wpa_ie != NULL) { 1100 memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]); 1101 cp += 2+ni->ni_wpa_ie[1]; 1102 } 1103 if (sr->isr_ie_len > 0 && ni->ni_wme_ie != NULL) { 1104 memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]); 1105 cp += 2+ni->ni_wme_ie[1]; 1106 } 1107 error = copyout(sr, p, sr->isr_len); 1108 if (error) 1109 break; 1110 p += sr->isr_len; 1111 space -= sr->isr_len; 1112 } 1113 ireq->i_len -= space; 1114 return error; 1115} 1116 1117struct stainforeq { 1118 struct ieee80211com *ic; 1119 struct ieee80211req_sta_info *si; 1120 size_t space; 1121}; 1122 1123static size_t 1124sta_space(const struct ieee80211_node *ni, size_t *ielen) 1125{ 1126 *ielen = 0; 1127 if (ni->ni_wpa_ie != NULL) 1128 *ielen += 2+ni->ni_wpa_ie[1]; 1129 if (ni->ni_wme_ie != NULL) 1130 *ielen += 2+ni->ni_wme_ie[1]; 1131 return roundup(sizeof(struct ieee80211req_sta_info) + *ielen, 1132 sizeof(u_int32_t)); 1133} 1134 1135static void 1136get_sta_space(void *arg, struct ieee80211_node *ni) 1137{ 1138 struct stainforeq *req = arg; 1139 struct ieee80211com *ic = ni->ni_ic; 1140 size_t ielen; 1141 1142 if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1143 ni->ni_associd == 0) /* only associated stations */ 1144 return; 1145 req->space += sta_space(ni, &ielen); 1146} 1147 1148static void 1149get_sta_info(void *arg, struct ieee80211_node *ni) 1150{ 1151 struct stainforeq *req = arg; 1152 struct ieee80211com *ic = ni->ni_ic; 1153 struct ieee80211req_sta_info *si; 1154 size_t ielen, len; 1155 u_int8_t *cp; 1156 1157 if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1158 ni->ni_associd == 0) /* only associated stations */ 1159 return; 1160 if (ni->ni_chan == IEEE80211_CHAN_ANYC) /* XXX bogus entry */ 1161 return; 1162 len = sta_space(ni, &ielen); 1163 if (len > req->space) 1164 return; 1165 si = req->si; 1166 si->isi_len = len; 1167 si->isi_ie_len = ielen; 1168 si->isi_freq = ni->ni_chan->ic_freq; 1169 si->isi_flags = ni->ni_chan->ic_flags; 1170 si->isi_state = ni->ni_flags; 1171 si->isi_authmode = ni->ni_authmode; 1172 si->isi_rssi = ic->ic_node_getrssi(ni); 1173 si->isi_capinfo = ni->ni_capinfo; 1174 si->isi_erp = ni->ni_erp; 1175 IEEE80211_ADDR_COPY(si->isi_macaddr, ni->ni_macaddr); 1176 si->isi_nrates = ni->ni_rates.rs_nrates; 1177 if (si->isi_nrates > 15) 1178 si->isi_nrates = 15; 1179 memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates); 1180 si->isi_txrate = ni->ni_txrate; 1181 si->isi_associd = ni->ni_associd; 1182 si->isi_txpower = ni->ni_txpower; 1183 si->isi_vlan = ni->ni_vlan; 1184 if (ni->ni_flags & IEEE80211_NODE_QOS) { 1185 memcpy(si->isi_txseqs, ni->ni_txseqs, sizeof(ni->ni_txseqs)); 1186 memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs)); 1187 } else { 1188 si->isi_txseqs[0] = ni->ni_txseqs[0]; 1189 si->isi_rxseqs[0] = ni->ni_rxseqs[0]; 1190 } 1191 /* NB: leave all cases in case we relax ni_associd == 0 check */ 1192 if (ieee80211_node_is_authorized(ni)) 1193 si->isi_inact = ic->ic_inact_run; 1194 else if (ni->ni_associd != 0) 1195 si->isi_inact = ic->ic_inact_auth; 1196 else 1197 si->isi_inact = ic->ic_inact_init; 1198 si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT; 1199 1200 cp = (u_int8_t *)(si+1); 1201 if (ni->ni_wpa_ie != NULL) { 1202 memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]); 1203 cp += 2+ni->ni_wpa_ie[1]; 1204 } 1205 if (ni->ni_wme_ie != NULL) { 1206 memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]); 1207 cp += 2+ni->ni_wme_ie[1]; 1208 } 1209 1210 req->si = (struct ieee80211req_sta_info *)(((u_int8_t *)si) + len); 1211 req->space -= len; 1212} 1213 1214static int 1215ieee80211_ioctl_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq) 1216{ 1217 struct stainforeq req; 1218 int error; 1219 1220 if (ireq->i_len < sizeof(struct stainforeq)) 1221 return EFAULT; 1222 1223 error = 0; 1224 req.space = 0; 1225 ieee80211_iterate_nodes(&ic->ic_sta, get_sta_space, &req); 1226 if (req.space > ireq->i_len) 1227 req.space = ireq->i_len; 1228 if (req.space > 0) { 1229 size_t space; 1230 void *p; 1231 1232 space = req.space; 1233 /* XXX M_WAITOK after driver lock released */ 1234 p = malloc(space, M_TEMP, M_NOWAIT); 1235 if (p == NULL) 1236 return ENOMEM; 1237 req.si = p; 1238 ieee80211_iterate_nodes(&ic->ic_sta, get_sta_info, &req); 1239 ireq->i_len = space - req.space; 1240 error = copyout(p, ireq->i_data, ireq->i_len); 1241 free(p, M_TEMP); 1242 } else 1243 ireq->i_len = 0; 1244 1245 return error; 1246} 1247 1248static int 1249ieee80211_ioctl_getstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq) 1250{ 1251 struct ieee80211_node *ni; 1252 struct ieee80211req_sta_txpow txpow; 1253 int error; 1254 1255 if (ireq->i_len != sizeof(txpow)) 1256 return EINVAL; 1257 error = copyin(ireq->i_data, &txpow, sizeof(txpow)); 1258 if (error != 0) 1259 return error; 1260 ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr); 1261 if (ni == NULL) 1262 return EINVAL; /* XXX */ 1263 txpow.it_txpow = ni->ni_txpower; 1264 error = copyout(&txpow, ireq->i_data, sizeof(txpow)); 1265 ieee80211_free_node(ni); 1266 return error; 1267} 1268 1269static int 1270ieee80211_ioctl_getwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq) 1271{ 1272 struct ieee80211_wme_state *wme = &ic->ic_wme; 1273 struct wmeParams *wmep; 1274 int ac; 1275 1276 if ((ic->ic_caps & IEEE80211_C_WME) == 0) 1277 return EINVAL; 1278 1279 ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL); 1280 if (ac >= WME_NUM_AC) 1281 ac = WME_AC_BE; 1282 if (ireq->i_len & IEEE80211_WMEPARAM_BSS) 1283 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac]; 1284 else 1285 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac]; 1286 switch (ireq->i_type) { 1287 case IEEE80211_IOC_WME_CWMIN: /* WME: CWmin */ 1288 ireq->i_val = wmep->wmep_logcwmin; 1289 break; 1290 case IEEE80211_IOC_WME_CWMAX: /* WME: CWmax */ 1291 ireq->i_val = wmep->wmep_logcwmax; 1292 break; 1293 case IEEE80211_IOC_WME_AIFS: /* WME: AIFS */ 1294 ireq->i_val = wmep->wmep_aifsn; 1295 break; 1296 case IEEE80211_IOC_WME_TXOPLIMIT: /* WME: txops limit */ 1297 ireq->i_val = wmep->wmep_txopLimit; 1298 break; 1299 case IEEE80211_IOC_WME_ACM: /* WME: ACM (bss only) */ 1300 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac]; 1301 ireq->i_val = wmep->wmep_acm; 1302 break; 1303 case IEEE80211_IOC_WME_ACKPOLICY: /* WME: ACK policy (!bss only)*/ 1304 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac]; 1305 ireq->i_val = !wmep->wmep_noackPolicy; 1306 break; 1307 } 1308 return 0; 1309} 1310 1311static int 1312ieee80211_ioctl_getmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq) 1313{ 1314 const struct ieee80211_aclator *acl = ic->ic_acl; 1315 1316 return (acl == NULL ? EINVAL : acl->iac_getioctl(ic, ireq)); 1317} 1318 1319#if defined(COMPAT_FREEBSD_NET80211) 1320static int 1321ieee80211_ioctl_get80211_fbsd(struct ieee80211com *ic, u_long cmd, 1322 struct ieee80211req *ireq) 1323{ 1324 u_int kid, len; 1325 u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE]; 1326 char tmpssid[IEEE80211_NWID_LEN]; 1327 struct ifnet *ifp = ic->ic_ifp; 1328 1329 int error = 0; 1330 1331 switch (ireq->i_type) { 1332 case IEEE80211_IOC_SSID: 1333 switch (ic->ic_state) { 1334 case IEEE80211_S_INIT: 1335 case IEEE80211_S_SCAN: 1336 ireq->i_len = ic->ic_des_esslen; 1337 memcpy(tmpssid, ic->ic_des_essid, ireq->i_len); 1338 break; 1339 default: 1340 ireq->i_len = ic->ic_bss->ni_esslen; 1341 memcpy(tmpssid, ic->ic_bss->ni_essid, 1342 ireq->i_len); 1343 break; 1344 } 1345 error = copyout(tmpssid, ireq->i_data, ireq->i_len); 1346 break; 1347 case IEEE80211_IOC_NUMSSIDS: 1348 ireq->i_val = 1; 1349 break; 1350 case IEEE80211_IOC_WEP: 1351 if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) 1352 ireq->i_val = IEEE80211_WEP_OFF; 1353 else if (ic->ic_flags & IEEE80211_F_DROPUNENC) 1354 ireq->i_val = IEEE80211_WEP_ON; 1355 else 1356 ireq->i_val = IEEE80211_WEP_MIXED; 1357 break; 1358 case IEEE80211_IOC_WEPKEY: 1359 kid = (u_int) ireq->i_val; 1360 if (kid >= IEEE80211_WEP_NKID) 1361 return EINVAL; 1362 len = (u_int) ic->ic_nw_keys[kid].wk_keylen; 1363 /* NB: only root can read WEP keys */ 1364 if (kauth_authorize_network(curlwp->l_cred, 1365 KAUTH_NETWORK_INTERFACE, 1366 KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp, NULL, 1367 NULL) == 0) { 1368 memcpy(tmpkey, ic->ic_nw_keys[kid].wk_key, len); 1369 } else { 1370 memset(tmpkey, 0, len); 1371 } 1372 ireq->i_len = len; 1373 error = copyout(tmpkey, ireq->i_data, len); 1374 break; 1375 case IEEE80211_IOC_NUMWEPKEYS: 1376 ireq->i_val = IEEE80211_WEP_NKID; 1377 break; 1378 case IEEE80211_IOC_WEPTXKEY: 1379 ireq->i_val = ic->ic_def_txkey; 1380 break; 1381 case IEEE80211_IOC_CHANNEL: 1382 ireq->i_val = ieee80211_chan2ieee(ic, ic->ic_curchan); 1383 break; 1384 case IEEE80211_IOC_POWERSAVE: 1385 if (ic->ic_flags & IEEE80211_F_PMGTON) 1386 ireq->i_val = IEEE80211_POWERSAVE_ON; 1387 else 1388 ireq->i_val = IEEE80211_POWERSAVE_OFF; 1389 break; 1390 case IEEE80211_IOC_POWERSAVESLEEP: 1391 ireq->i_val = ic->ic_lintval; 1392 break; 1393 case IEEE80211_IOC_BSSID: 1394 if (ireq->i_len != IEEE80211_ADDR_LEN) 1395 return EINVAL; 1396 error = copyout(ic->ic_state == IEEE80211_S_RUN ? 1397 ic->ic_bss->ni_bssid : 1398 ic->ic_des_bssid, 1399 ireq->i_data, ireq->i_len); 1400 break; 1401 default: 1402 error = EINVAL; 1403 break; 1404 } 1405 return error; 1406} 1407#endif /* COMPAT_FREEBSD_NET80211 */ 1408 1409/* 1410 * When building the kernel with -O2 on the i386 architecture, gcc 1411 * seems to want to inline this function into ieee80211_ioctl() 1412 * (which is the only routine that calls it). When this happens, 1413 * ieee80211_ioctl() ends up consuming an additional 2K of stack 1414 * space. (Exactly why it needs so much is unclear.) The problem 1415 * is that it's possible for ieee80211_ioctl() to invoke other 1416 * routines (including driver init functions) which could then find 1417 * themselves perilously close to exhausting the stack. 1418 * 1419 * To avoid this, we deliberately prevent gcc from inlining this 1420 * routine. Another way to avoid this is to use less agressive 1421 * optimization when compiling this file (i.e. -O instead of -O2) 1422 * but special-casing the compilation of this one module in the 1423 * build system would be awkward. 1424 */ 1425#ifdef __GNUC__ 1426__attribute__ ((__noinline__)) 1427#endif 1428static int 1429ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, 1430 struct ieee80211req *ireq) 1431{ 1432 const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn; 1433 int error = 0; 1434 u_int m; 1435 1436 switch (ireq->i_type) { 1437 case IEEE80211_IOC_AUTHMODE: 1438 if (ic->ic_flags & IEEE80211_F_WPA) 1439 ireq->i_val = IEEE80211_AUTH_WPA; 1440 else 1441 ireq->i_val = ic->ic_bss->ni_authmode; 1442 break; 1443 case IEEE80211_IOC_RTSTHRESHOLD: 1444 ireq->i_val = ic->ic_rtsthreshold; 1445 break; 1446 case IEEE80211_IOC_PROTMODE: 1447 ireq->i_val = ic->ic_protmode; 1448 break; 1449 case IEEE80211_IOC_TXPOWER: 1450 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) 1451 return EINVAL; 1452 ireq->i_val = ic->ic_txpowlimit; 1453 break; 1454 case IEEE80211_IOC_MCASTCIPHER: 1455 ireq->i_val = rsn->rsn_mcastcipher; 1456 break; 1457 case IEEE80211_IOC_MCASTKEYLEN: 1458 ireq->i_val = rsn->rsn_mcastkeylen; 1459 break; 1460 case IEEE80211_IOC_UCASTCIPHERS: 1461 ireq->i_val = 0; 1462 for (m = 0x1; m != 0; m <<= 1) 1463 if (rsn->rsn_ucastcipherset & m) 1464 ireq->i_val |= 1<<cap2cipher(m); 1465 break; 1466 case IEEE80211_IOC_UCASTCIPHER: 1467 ireq->i_val = rsn->rsn_ucastcipher; 1468 break; 1469 case IEEE80211_IOC_UCASTKEYLEN: 1470 ireq->i_val = rsn->rsn_ucastkeylen; 1471 break; 1472 case IEEE80211_IOC_KEYMGTALGS: 1473 ireq->i_val = rsn->rsn_keymgmtset; 1474 break; 1475 case IEEE80211_IOC_RSNCAPS: 1476 ireq->i_val = rsn->rsn_caps; 1477 break; 1478 case IEEE80211_IOC_WPA: 1479 switch (ic->ic_flags & IEEE80211_F_WPA) { 1480 case IEEE80211_F_WPA1: 1481 ireq->i_val = 1; 1482 break; 1483 case IEEE80211_F_WPA2: 1484 ireq->i_val = 2; 1485 break; 1486 case IEEE80211_F_WPA1 | IEEE80211_F_WPA2: 1487 ireq->i_val = 3; 1488 break; 1489 default: 1490 ireq->i_val = 0; 1491 break; 1492 } 1493 break; 1494 case IEEE80211_IOC_CHANLIST: 1495 error = ieee80211_ioctl_getchanlist(ic, ireq); 1496 break; 1497 case IEEE80211_IOC_ROAMING: 1498 ireq->i_val = ic->ic_roaming; 1499 break; 1500 case IEEE80211_IOC_PRIVACY: 1501 ireq->i_val = (ic->ic_flags & IEEE80211_F_PRIVACY) != 0; 1502 break; 1503 case IEEE80211_IOC_DROPUNENCRYPTED: 1504 ireq->i_val = (ic->ic_flags & IEEE80211_F_DROPUNENC) != 0; 1505 break; 1506 case IEEE80211_IOC_COUNTERMEASURES: 1507 ireq->i_val = (ic->ic_flags & IEEE80211_F_COUNTERM) != 0; 1508 break; 1509 case IEEE80211_IOC_DRIVER_CAPS: 1510 ireq->i_val = ic->ic_caps>>16; 1511 ireq->i_len = ic->ic_caps&0xffff; 1512 break; 1513 case IEEE80211_IOC_WME: 1514 ireq->i_val = (ic->ic_flags & IEEE80211_F_WME) != 0; 1515 break; 1516 case IEEE80211_IOC_HIDESSID: 1517 ireq->i_val = (ic->ic_flags & IEEE80211_F_HIDESSID) != 0; 1518 break; 1519 case IEEE80211_IOC_APBRIDGE: 1520 ireq->i_val = (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0; 1521 break; 1522 case IEEE80211_IOC_OPTIE: 1523 if (ic->ic_opt_ie == NULL) 1524 return EINVAL; 1525 /* NB: truncate, caller can check length */ 1526 if (ireq->i_len > ic->ic_opt_ie_len) 1527 ireq->i_len = ic->ic_opt_ie_len; 1528 error = copyout(ic->ic_opt_ie, ireq->i_data, ireq->i_len); 1529 break; 1530 case IEEE80211_IOC_WPAKEY: 1531 error = ieee80211_ioctl_getkey(ic, ireq); 1532 break; 1533 case IEEE80211_IOC_CHANINFO: 1534 error = ieee80211_ioctl_getchaninfo(ic, ireq); 1535 break; 1536 case IEEE80211_IOC_WPAIE: 1537 error = ieee80211_ioctl_getwpaie(ic, ireq); 1538 break; 1539 case IEEE80211_IOC_SCAN_RESULTS: 1540 error = ieee80211_ioctl_getscanresults(ic, ireq); 1541 break; 1542 case IEEE80211_IOC_STA_STATS: 1543 error = ieee80211_ioctl_getstastats(ic, ireq); 1544 break; 1545 case IEEE80211_IOC_TXPOWMAX: 1546 ireq->i_val = ic->ic_bss->ni_txpower; 1547 break; 1548 case IEEE80211_IOC_STA_TXPOW: 1549 error = ieee80211_ioctl_getstatxpow(ic, ireq); 1550 break; 1551 case IEEE80211_IOC_STA_INFO: 1552 error = ieee80211_ioctl_getstainfo(ic, ireq); 1553 break; 1554 case IEEE80211_IOC_WME_CWMIN: /* WME: CWmin */ 1555 case IEEE80211_IOC_WME_CWMAX: /* WME: CWmax */ 1556 case IEEE80211_IOC_WME_AIFS: /* WME: AIFS */ 1557 case IEEE80211_IOC_WME_TXOPLIMIT: /* WME: txops limit */ 1558 case IEEE80211_IOC_WME_ACM: /* WME: ACM (bss only) */ 1559 case IEEE80211_IOC_WME_ACKPOLICY: /* WME: ACK policy (bss only) */ 1560 error = ieee80211_ioctl_getwmeparam(ic, ireq); 1561 break; 1562 case IEEE80211_IOC_DTIM_PERIOD: 1563 ireq->i_val = ic->ic_dtim_period; 1564 break; 1565 case IEEE80211_IOC_BEACON_INTERVAL: 1566 /* NB: get from ic_bss for station mode */ 1567 ireq->i_val = ic->ic_bss->ni_intval; 1568 break; 1569 case IEEE80211_IOC_PUREG: 1570 ireq->i_val = (ic->ic_flags & IEEE80211_F_PUREG) != 0; 1571 break; 1572 case IEEE80211_IOC_MCAST_RATE: 1573 ireq->i_val = ic->ic_mcast_rate; 1574 break; 1575 case IEEE80211_IOC_FRAGTHRESHOLD: 1576 ireq->i_val = ic->ic_fragthreshold; 1577 break; 1578 case IEEE80211_IOC_MACCMD: 1579 error = ieee80211_ioctl_getmaccmd(ic, ireq); 1580 break; 1581 default: 1582#if defined(COMPAT_FREEBSD_NET80211) 1583 error = ieee80211_ioctl_get80211_fbsd(ic, cmd, ireq); 1584#else 1585 error = EINVAL; 1586#endif /* COMPAT_FREEBSD_NET80211 */ 1587 break; 1588 } 1589 return error; 1590} 1591 1592static int 1593ieee80211_ioctl_setoptie(struct ieee80211com *ic, struct ieee80211req *ireq) 1594{ 1595 int error; 1596 void *ie; 1597 1598 /* 1599 * NB: Doing this for ap operation could be useful (e.g. for 1600 * WPA and/or WME) except that it typically is worthless 1601 * without being able to intervene when processing 1602 * association response frames--so disallow it for now. 1603 */ 1604 if (ic->ic_opmode != IEEE80211_M_STA) 1605 return EINVAL; 1606 if (ireq->i_len > IEEE80211_MAX_OPT_IE) 1607 return EINVAL; 1608 /* NB: data.length is validated by the wireless extensions code */ 1609 ie = malloc(ireq->i_len, M_DEVBUF, M_WAITOK); 1610 if (ie == NULL) 1611 return ENOMEM; 1612 error = copyin(ireq->i_data, ie, ireq->i_len); 1613 /* XXX sanity check data? */ 1614 if (ic->ic_opt_ie != NULL) 1615 free(ic->ic_opt_ie, M_DEVBUF); 1616 ic->ic_opt_ie = ie; 1617 ic->ic_opt_ie_len = ireq->i_len; 1618 return 0; 1619} 1620 1621static int 1622ieee80211_ioctl_setkey(struct ieee80211com *ic, struct ieee80211req *ireq) 1623{ 1624 struct ieee80211req_key ik; 1625 struct ieee80211_node *ni; 1626 struct ieee80211_key *wk; 1627 u_int16_t kid; 1628 int error; 1629 1630 if (ireq->i_len != sizeof(ik)) 1631 return EINVAL; 1632 error = copyin(ireq->i_data, &ik, sizeof(ik)); 1633 if (error) 1634 return error; 1635 /* NB: cipher support is verified by ieee80211_crypt_newkey */ 1636 /* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */ 1637 if (ik.ik_keylen > sizeof(ik.ik_keydata)) 1638 return E2BIG; 1639 kid = ik.ik_keyix; 1640 if (kid == IEEE80211_KEYIX_NONE) { 1641 /* XXX unicast keys currently must be tx/rx */ 1642 if (ik.ik_flags != (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV)) 1643 return EINVAL; 1644 if (ic->ic_opmode == IEEE80211_M_STA) { 1645 ni = ieee80211_ref_node(ic->ic_bss); 1646 if (!IEEE80211_ADDR_EQ(ik.ik_macaddr, ni->ni_bssid)) { 1647 ieee80211_free_node(ni); 1648 return EADDRNOTAVAIL; 1649 } 1650 } else { 1651 ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr); 1652 if (ni == NULL) 1653 return ENOENT; 1654 } 1655 wk = &ni->ni_ucastkey; 1656 } else { 1657 if (kid >= IEEE80211_WEP_NKID) 1658 return EINVAL; 1659 wk = &ic->ic_nw_keys[kid]; 1660 ni = NULL; 1661 } 1662 error = 0; 1663 ieee80211_key_update_begin(ic); 1664 if (ieee80211_crypto_newkey(ic, ik.ik_type, ik.ik_flags, wk)) { 1665 wk->wk_keylen = ik.ik_keylen; 1666 /* NB: MIC presence is implied by cipher type */ 1667 if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE) 1668 wk->wk_keylen = IEEE80211_KEYBUF_SIZE; 1669 wk->wk_keyrsc = ik.ik_keyrsc; 1670 wk->wk_keytsc = 0; /* new key, reset */ 1671 memset(wk->wk_key, 0, sizeof(wk->wk_key)); 1672 memcpy(wk->wk_key, ik.ik_keydata, ik.ik_keylen); 1673 if (!ieee80211_crypto_setkey(ic, wk, 1674 ni != NULL ? ni->ni_macaddr : ik.ik_macaddr)) 1675 error = EIO; 1676 else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT)) 1677 ic->ic_def_txkey = kid; 1678 } else 1679 error = ENXIO; 1680 ieee80211_key_update_end(ic); 1681 if (ni != NULL) 1682 ieee80211_free_node(ni); 1683 return error; 1684} 1685 1686static int 1687ieee80211_ioctl_delkey(struct ieee80211com *ic, struct ieee80211req *ireq) 1688{ 1689 struct ieee80211req_del_key dk; 1690 int kid, error; 1691 1692 if (ireq->i_len != sizeof(dk)) 1693 return EINVAL; 1694 error = copyin(ireq->i_data, &dk, sizeof(dk)); 1695 if (error) 1696 return error; 1697 kid = dk.idk_keyix; 1698 /* XXX u_int8_t -> u_int16_t */ 1699 if (dk.idk_keyix == (u_int8_t) IEEE80211_KEYIX_NONE) { 1700 struct ieee80211_node *ni; 1701 1702 if (ic->ic_opmode == IEEE80211_M_STA) { 1703 ni = ieee80211_ref_node(ic->ic_bss); 1704 if (!IEEE80211_ADDR_EQ(dk.idk_macaddr, ni->ni_bssid)) { 1705 ieee80211_free_node(ni); 1706 return EADDRNOTAVAIL; 1707 } 1708 } else { 1709 ni = ieee80211_find_node(&ic->ic_sta, dk.idk_macaddr); 1710 if (ni == NULL) 1711 return ENOENT; 1712 } 1713 /* XXX error return */ 1714 ieee80211_node_delucastkey(ni); 1715 ieee80211_free_node(ni); 1716 } else { 1717 if (kid >= IEEE80211_WEP_NKID) 1718 return EINVAL; 1719 /* XXX error return */ 1720 ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[kid]); 1721 } 1722 return 0; 1723} 1724 1725#ifndef IEEE80211_NO_HOSTAP 1726static void 1727domlme(void *arg, struct ieee80211_node *ni) 1728{ 1729 struct ieee80211com *ic = ni->ni_ic; 1730 struct ieee80211req_mlme *mlme = arg; 1731 1732 if (ni->ni_associd != 0) { 1733 IEEE80211_SEND_MGMT(ic, ni, 1734 mlme->im_op == IEEE80211_MLME_DEAUTH ? 1735 IEEE80211_FC0_SUBTYPE_DEAUTH : 1736 IEEE80211_FC0_SUBTYPE_DISASSOC, 1737 mlme->im_reason); 1738 } 1739 ieee80211_node_leave(ic, ni); 1740} 1741#endif /* !IEEE80211_NO_HOSTAP */ 1742 1743static int 1744ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq) 1745{ 1746 struct ieee80211req_mlme mlme; 1747 struct ieee80211_node *ni; 1748 int error; 1749 1750 if (ireq->i_len != sizeof(mlme)) 1751 return EINVAL; 1752 error = copyin(ireq->i_data, &mlme, sizeof(mlme)); 1753 if (error) 1754 return error; 1755 switch (mlme.im_op) { 1756 case IEEE80211_MLME_ASSOC: 1757 if (ic->ic_opmode != IEEE80211_M_STA) 1758 return EINVAL; 1759 /* XXX must be in S_SCAN state? */ 1760 1761 if (mlme.im_ssid_len != 0) { 1762 /* 1763 * Desired ssid specified; must match both bssid and 1764 * ssid to distinguish ap advertising multiple ssid's. 1765 */ 1766 ni = ieee80211_find_node_with_ssid(&ic->ic_scan, 1767 mlme.im_macaddr, 1768 mlme.im_ssid_len, mlme.im_ssid); 1769 } else { 1770 /* 1771 * Normal case; just match bssid. 1772 */ 1773 ni = ieee80211_find_node(&ic->ic_scan, mlme.im_macaddr); 1774 } 1775 if (ni == NULL) 1776 return EINVAL; 1777 if (!ieee80211_sta_join(ic, ni)) { 1778 ieee80211_free_node(ni); 1779 return EINVAL; 1780 } 1781 break; 1782 case IEEE80211_MLME_DISASSOC: 1783 case IEEE80211_MLME_DEAUTH: 1784 switch (ic->ic_opmode) { 1785 case IEEE80211_M_STA: 1786 /* XXX not quite right */ 1787 ieee80211_new_state(ic, IEEE80211_S_INIT, 1788 mlme.im_reason); 1789 break; 1790 case IEEE80211_M_HOSTAP: 1791#ifndef IEEE80211_NO_HOSTAP 1792 /* NB: the broadcast address means do 'em all */ 1793 if (!IEEE80211_ADDR_EQ(mlme.im_macaddr, ic->ic_ifp->if_broadcastaddr)) { 1794 if ((ni = ieee80211_find_node(&ic->ic_sta, 1795 mlme.im_macaddr)) == NULL) 1796 return EINVAL; 1797 domlme(&mlme, ni); 1798 ieee80211_free_node(ni); 1799 } else { 1800 ieee80211_iterate_nodes(&ic->ic_sta, 1801 domlme, &mlme); 1802 } 1803#endif /* !IEEE80211_NO_HOSTAP */ 1804 break; 1805 default: 1806 return EINVAL; 1807 } 1808 break; 1809 case IEEE80211_MLME_AUTHORIZE: 1810 case IEEE80211_MLME_UNAUTHORIZE: 1811 if (ic->ic_opmode != IEEE80211_M_HOSTAP) 1812 return EINVAL; 1813 ni = ieee80211_find_node(&ic->ic_sta, mlme.im_macaddr); 1814 if (ni == NULL) 1815 return EINVAL; 1816 if (mlme.im_op == IEEE80211_MLME_AUTHORIZE) 1817 ieee80211_node_authorize(ni); 1818 else 1819 ieee80211_node_unauthorize(ni); 1820 ieee80211_free_node(ni); 1821 break; 1822 default: 1823 return EINVAL; 1824 } 1825 return 0; 1826} 1827 1828static int 1829ieee80211_ioctl_macmac(struct ieee80211com *ic, struct ieee80211req *ireq) 1830{ 1831 u_int8_t mac[IEEE80211_ADDR_LEN]; 1832 const struct ieee80211_aclator *acl = ic->ic_acl; 1833 int error; 1834 1835 if (ireq->i_len != sizeof(mac)) 1836 return EINVAL; 1837 error = copyin(ireq->i_data, mac, ireq->i_len); 1838 if (error) 1839 return error; 1840 if (acl == NULL) { 1841 acl = ieee80211_aclator_get("mac"); 1842 if (acl == NULL || !acl->iac_attach(ic)) 1843 return EINVAL; 1844 ic->ic_acl = acl; 1845 } 1846 if (ireq->i_type == IEEE80211_IOC_ADDMAC) 1847 acl->iac_add(ic, mac); 1848 else 1849 acl->iac_remove(ic, mac); 1850 return 0; 1851} 1852 1853static int 1854ieee80211_ioctl_setmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq) 1855{ 1856 const struct ieee80211_aclator *acl = ic->ic_acl; 1857 1858 switch (ireq->i_val) { 1859 case IEEE80211_MACCMD_POLICY_OPEN: 1860 case IEEE80211_MACCMD_POLICY_ALLOW: 1861 case IEEE80211_MACCMD_POLICY_DENY: 1862 if (acl == NULL) { 1863 acl = ieee80211_aclator_get("mac"); 1864 if (acl == NULL || !acl->iac_attach(ic)) 1865 return EINVAL; 1866 ic->ic_acl = acl; 1867 } 1868 acl->iac_setpolicy(ic, ireq->i_val); 1869 break; 1870 case IEEE80211_MACCMD_FLUSH: 1871 if (acl != NULL) 1872 acl->iac_flush(ic); 1873 /* NB: silently ignore when not in use */ 1874 break; 1875 case IEEE80211_MACCMD_DETACH: 1876 if (acl != NULL) { 1877 ic->ic_acl = NULL; 1878 acl->iac_detach(ic); 1879 } 1880 break; 1881 default: 1882 if (acl == NULL) 1883 return EINVAL; 1884 else 1885 return acl->iac_setioctl(ic, ireq); 1886 } 1887 return 0; 1888} 1889 1890static int 1891ieee80211_ioctl_setchanlist(struct ieee80211com *ic, struct ieee80211req *ireq) 1892{ 1893 struct ieee80211req_chanlist list; 1894 u_int8_t chanlist[IEEE80211_CHAN_BYTES]; 1895 int i, j, error; 1896 1897 if (ireq->i_len != sizeof(list)) 1898 return EINVAL; 1899 error = copyin(ireq->i_data, &list, sizeof(list)); 1900 if (error) 1901 return error; 1902 memset(chanlist, 0, sizeof(chanlist)); 1903 /* 1904 * Since channel 0 is not available for DS, channel 1 1905 * is assigned to LSB on WaveLAN. 1906 */ 1907 if (ic->ic_phytype == IEEE80211_T_DS) 1908 i = 1; 1909 else 1910 i = 0; 1911 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) { 1912 /* 1913 * NB: silently discard unavailable channels so users 1914 * can specify 1-255 to get all available channels. 1915 */ 1916 if (isset(list.ic_channels, j) && isset(ic->ic_chan_avail, i)) 1917 setbit(chanlist, i); 1918 } 1919 if (ic->ic_ibss_chan == NULL || 1920 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { 1921 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) 1922 if (isset(chanlist, i)) { 1923 ic->ic_ibss_chan = &ic->ic_channels[i]; 1924 goto found; 1925 } 1926 return EINVAL; /* no active channels */ 1927found: 1928 ; 1929 } 1930 memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active)); 1931 return IS_UP_AUTO(ic) ? ENETRESET : 0; 1932} 1933 1934static int 1935ieee80211_ioctl_setstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq) 1936{ 1937 struct ieee80211_node *ni; 1938 struct ieee80211req_sta_txpow txpow; 1939 int error; 1940 1941 if (ireq->i_len != sizeof(txpow)) 1942 return EINVAL; 1943 error = copyin(ireq->i_data, &txpow, sizeof(txpow)); 1944 if (error != 0) 1945 return error; 1946 ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr); 1947 if (ni == NULL) 1948 return EINVAL; /* XXX */ 1949 ni->ni_txpower = txpow.it_txpow; 1950 ieee80211_free_node(ni); 1951 return error; 1952} 1953 1954static int 1955ieee80211_ioctl_setwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq) 1956{ 1957 struct ieee80211_wme_state *wme = &ic->ic_wme; 1958 struct wmeParams *wmep, *chanp; 1959 int isbss, ac; 1960 1961 if ((ic->ic_caps & IEEE80211_C_WME) == 0) 1962 return EINVAL; 1963 1964 isbss = (ireq->i_len & IEEE80211_WMEPARAM_BSS); 1965 ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL); 1966 if (ac >= WME_NUM_AC) 1967 ac = WME_AC_BE; 1968 if (isbss) { 1969 chanp = &wme->wme_bssChanParams.cap_wmeParams[ac]; 1970 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac]; 1971 } else { 1972 chanp = &wme->wme_chanParams.cap_wmeParams[ac]; 1973 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac]; 1974 } 1975 switch (ireq->i_type) { 1976 case IEEE80211_IOC_WME_CWMIN: /* WME: CWmin */ 1977 if (isbss) { 1978 wmep->wmep_logcwmin = ireq->i_val; 1979 if ((wme->wme_flags & WME_F_AGGRMODE) == 0) 1980 chanp->wmep_logcwmin = ireq->i_val; 1981 } else { 1982 wmep->wmep_logcwmin = chanp->wmep_logcwmin = 1983 ireq->i_val; 1984 } 1985 break; 1986 case IEEE80211_IOC_WME_CWMAX: /* WME: CWmax */ 1987 if (isbss) { 1988 wmep->wmep_logcwmax = ireq->i_val; 1989 if ((wme->wme_flags & WME_F_AGGRMODE) == 0) 1990 chanp->wmep_logcwmax = ireq->i_val; 1991 } else { 1992 wmep->wmep_logcwmax = chanp->wmep_logcwmax = 1993 ireq->i_val; 1994 } 1995 break; 1996 case IEEE80211_IOC_WME_AIFS: /* WME: AIFS */ 1997 if (isbss) { 1998 wmep->wmep_aifsn = ireq->i_val; 1999 if ((wme->wme_flags & WME_F_AGGRMODE) == 0) 2000 chanp->wmep_aifsn = ireq->i_val; 2001 } else { 2002 wmep->wmep_aifsn = chanp->wmep_aifsn = ireq->i_val; 2003 } 2004 break; 2005 case IEEE80211_IOC_WME_TXOPLIMIT: /* WME: txops limit */ 2006 if (isbss) { 2007 wmep->wmep_txopLimit = ireq->i_val; 2008 if ((wme->wme_flags & WME_F_AGGRMODE) == 0) 2009 chanp->wmep_txopLimit = ireq->i_val; 2010 } else { 2011 wmep->wmep_txopLimit = chanp->wmep_txopLimit = 2012 ireq->i_val; 2013 } 2014 break; 2015 case IEEE80211_IOC_WME_ACM: /* WME: ACM (bss only) */ 2016 wmep->wmep_acm = ireq->i_val; 2017 if ((wme->wme_flags & WME_F_AGGRMODE) == 0) 2018 chanp->wmep_acm = ireq->i_val; 2019 break; 2020 case IEEE80211_IOC_WME_ACKPOLICY: /* WME: ACK policy (!bss only)*/ 2021 wmep->wmep_noackPolicy = chanp->wmep_noackPolicy = 2022 (ireq->i_val) == 0; 2023 break; 2024 } 2025 ieee80211_wme_updateparams(ic); 2026 return 0; 2027} 2028 2029static int 2030cipher2cap(int cipher) 2031{ 2032 switch (cipher) { 2033 case IEEE80211_CIPHER_WEP: return IEEE80211_C_WEP; 2034 case IEEE80211_CIPHER_AES_OCB: return IEEE80211_C_AES; 2035 case IEEE80211_CIPHER_AES_CCM: return IEEE80211_C_AES_CCM; 2036 case IEEE80211_CIPHER_CKIP: return IEEE80211_C_CKIP; 2037 case IEEE80211_CIPHER_TKIP: return IEEE80211_C_TKIP; 2038 } 2039 return 0; 2040} 2041 2042static int 2043ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, 2044 struct ieee80211req *ireq) 2045{ 2046#if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211) 2047 static const u_int8_t zerobssid[IEEE80211_ADDR_LEN]; 2048 u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE]; 2049 char tmpssid[IEEE80211_NWID_LEN]; 2050 u_int8_t tmpbssid[IEEE80211_ADDR_LEN]; 2051 struct ieee80211_key *k; 2052 u_int kid; 2053#endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */ 2054 struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn; 2055 int error; 2056 const struct ieee80211_authenticator *auth; 2057 int j, caps; 2058 2059 error = 0; 2060 switch (ireq->i_type) { 2061#if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211) 2062 case IEEE80211_IOC_SSID: 2063 if (ireq->i_val != 0 || 2064 ireq->i_len > IEEE80211_NWID_LEN) 2065 return EINVAL; 2066 error = copyin(ireq->i_data, tmpssid, ireq->i_len); 2067 if (error) 2068 break; 2069 memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); 2070 ic->ic_des_esslen = ireq->i_len; 2071 memcpy(ic->ic_des_essid, tmpssid, ireq->i_len); 2072 error = ENETRESET; 2073 break; 2074#endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */ 2075 case IEEE80211_IOC_WEP: 2076 switch (ireq->i_val) { 2077 case IEEE80211_WEP_OFF: 2078 ic->ic_flags &= ~IEEE80211_F_PRIVACY; 2079 ic->ic_flags &= ~IEEE80211_F_DROPUNENC; 2080 break; 2081 case IEEE80211_WEP_ON: 2082 ic->ic_flags |= IEEE80211_F_PRIVACY; 2083 ic->ic_flags |= IEEE80211_F_DROPUNENC; 2084 break; 2085 case IEEE80211_WEP_MIXED: 2086 ic->ic_flags |= IEEE80211_F_PRIVACY; 2087 ic->ic_flags &= ~IEEE80211_F_DROPUNENC; 2088 break; 2089 } 2090 error = ENETRESET; 2091 break; 2092#if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211) 2093 case IEEE80211_IOC_WEPKEY: 2094 kid = (u_int) ireq->i_val; 2095 if (kid >= IEEE80211_WEP_NKID) 2096 return EINVAL; 2097 k = &ic->ic_nw_keys[kid]; 2098 if (ireq->i_len == 0) { 2099 /* zero-len =>'s delete any existing key */ 2100 (void) ieee80211_crypto_delkey(ic, k); 2101 break; 2102 } 2103 if (ireq->i_len > sizeof(tmpkey)) 2104 return EINVAL; 2105 memset(tmpkey, 0, sizeof(tmpkey)); 2106 error = copyin(ireq->i_data, tmpkey, ireq->i_len); 2107 if (error) 2108 break; 2109 ieee80211_key_update_begin(ic); 2110 k->wk_keyix = kid; /* NB: force fixed key id */ 2111 if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP, 2112 IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) { 2113 k->wk_keylen = ireq->i_len; 2114 memcpy(k->wk_key, tmpkey, sizeof(tmpkey)); 2115 if (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr)) 2116 error = EINVAL; 2117 } else 2118 error = EINVAL; 2119 ieee80211_key_update_end(ic); 2120 if (!error) /* NB: for compatibility */ 2121 error = ENETRESET; 2122 break; 2123 case IEEE80211_IOC_WEPTXKEY: 2124 kid = (u_int) ireq->i_val; 2125 if (kid >= IEEE80211_WEP_NKID && 2126 (u_int16_t) kid != IEEE80211_KEYIX_NONE) 2127 return EINVAL; 2128 ic->ic_def_txkey = kid; 2129 error = ENETRESET; /* push to hardware */ 2130 break; 2131#endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */ 2132 case IEEE80211_IOC_AUTHMODE: 2133 switch (ireq->i_val) { 2134 case IEEE80211_AUTH_WPA: 2135 case IEEE80211_AUTH_8021X: /* 802.1x */ 2136 case IEEE80211_AUTH_OPEN: /* open */ 2137 case IEEE80211_AUTH_SHARED: /* shared-key */ 2138 case IEEE80211_AUTH_AUTO: /* auto */ 2139 auth = ieee80211_authenticator_get(ireq->i_val); 2140 if (auth == NULL) 2141 return EINVAL; 2142 break; 2143 default: 2144 return EINVAL; 2145 } 2146 switch (ireq->i_val) { 2147 case IEEE80211_AUTH_WPA: /* WPA w/ 802.1x */ 2148 ic->ic_flags |= IEEE80211_F_PRIVACY; 2149 ireq->i_val = IEEE80211_AUTH_8021X; 2150 break; 2151 case IEEE80211_AUTH_OPEN: /* open */ 2152 ic->ic_flags &= ~(IEEE80211_F_WPA|IEEE80211_F_PRIVACY); 2153 break; 2154 case IEEE80211_AUTH_SHARED: /* shared-key */ 2155 case IEEE80211_AUTH_8021X: /* 802.1x */ 2156 ic->ic_flags &= ~IEEE80211_F_WPA; 2157 /* both require a key so mark the PRIVACY capability */ 2158 ic->ic_flags |= IEEE80211_F_PRIVACY; 2159 break; 2160 case IEEE80211_AUTH_AUTO: /* auto */ 2161 ic->ic_flags &= ~IEEE80211_F_WPA; 2162 /* XXX PRIVACY handling? */ 2163 /* XXX what's the right way to do this? */ 2164 break; 2165 } 2166 /* NB: authenticator attach/detach happens on state change */ 2167 ic->ic_bss->ni_authmode = ireq->i_val; 2168 /* XXX mixed/mode/usage? */ 2169 ic->ic_auth = auth; 2170 error = ENETRESET; 2171 break; 2172#if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211) 2173 case IEEE80211_IOC_CHANNEL: 2174 /* XXX 0xffff overflows 16-bit signed */ 2175 if (ireq->i_val == 0 || 2176 ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) 2177 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 2178 else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX || 2179 isclr(ic->ic_chan_active, ireq->i_val)) { 2180 return EINVAL; 2181 } else 2182 ic->ic_ibss_chan = ic->ic_des_chan = 2183 &ic->ic_channels[ireq->i_val]; 2184 switch (ic->ic_state) { 2185 case IEEE80211_S_INIT: 2186 case IEEE80211_S_SCAN: 2187 error = ENETRESET; 2188 break; 2189 default: 2190 /* 2191 * If the desired channel has changed (to something 2192 * other than any) and we're not already scanning, 2193 * then kick the state machine. 2194 */ 2195 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 2196 ic->ic_bss->ni_chan != ic->ic_des_chan && 2197 (ic->ic_flags & IEEE80211_F_SCAN) == 0) 2198 error = ENETRESET; 2199 break; 2200 } 2201 if (error == ENETRESET && 2202 ic->ic_opmode == IEEE80211_M_MONITOR) { 2203 if (IS_UP(ic)) { 2204 /* 2205 * Monitor mode can switch directly. 2206 */ 2207 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) 2208 ic->ic_curchan = ic->ic_des_chan; 2209 error = ic->ic_reset(ic->ic_ifp); 2210 } else 2211 error = 0; 2212 } 2213 break; 2214 case IEEE80211_IOC_POWERSAVE: 2215 switch (ireq->i_val) { 2216 case IEEE80211_POWERSAVE_OFF: 2217 if (ic->ic_flags & IEEE80211_F_PMGTON) { 2218 ic->ic_flags &= ~IEEE80211_F_PMGTON; 2219 error = ENETRESET; 2220 } 2221 break; 2222 case IEEE80211_POWERSAVE_ON: 2223 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) 2224 error = EINVAL; 2225 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { 2226 ic->ic_flags |= IEEE80211_F_PMGTON; 2227 error = ENETRESET; 2228 } 2229 break; 2230 default: 2231 error = EINVAL; 2232 break; 2233 } 2234 break; 2235 case IEEE80211_IOC_POWERSAVESLEEP: 2236 if (ireq->i_val < 0) 2237 return EINVAL; 2238 ic->ic_lintval = ireq->i_val; 2239 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 2240 break; 2241#endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */ 2242 case IEEE80211_IOC_RTSTHRESHOLD: 2243 if (!(IEEE80211_RTS_MIN <= ireq->i_val && 2244 ireq->i_val <= IEEE80211_RTS_MAX)) 2245 return EINVAL; 2246 ic->ic_rtsthreshold = ireq->i_val; 2247 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 2248 break; 2249 case IEEE80211_IOC_PROTMODE: 2250 if (ireq->i_val > IEEE80211_PROT_RTSCTS) 2251 return EINVAL; 2252 ic->ic_protmode = ireq->i_val; 2253 /* NB: if not operating in 11g this can wait */ 2254 if (ic->ic_curmode == IEEE80211_MODE_11G) 2255 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 2256 break; 2257 case IEEE80211_IOC_TXPOWER: 2258 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) 2259 return EINVAL; 2260 if (!(IEEE80211_TXPOWER_MIN < ireq->i_val && 2261 ireq->i_val < IEEE80211_TXPOWER_MAX)) 2262 return EINVAL; 2263 ic->ic_txpowlimit = ireq->i_val; 2264 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 2265 break; 2266 case IEEE80211_IOC_ROAMING: 2267 if (!(IEEE80211_ROAMING_DEVICE <= ireq->i_val && 2268 ireq->i_val <= IEEE80211_ROAMING_MANUAL)) 2269 return EINVAL; 2270 ic->ic_roaming = ireq->i_val; 2271 /* XXXX reset? */ 2272 break; 2273 case IEEE80211_IOC_PRIVACY: 2274 if (ireq->i_val) { 2275 /* XXX check for key state? */ 2276 ic->ic_flags |= IEEE80211_F_PRIVACY; 2277 } else 2278 ic->ic_flags &= ~IEEE80211_F_PRIVACY; 2279 break; 2280 case IEEE80211_IOC_DROPUNENCRYPTED: 2281 if (ireq->i_val) 2282 ic->ic_flags |= IEEE80211_F_DROPUNENC; 2283 else 2284 ic->ic_flags &= ~IEEE80211_F_DROPUNENC; 2285 break; 2286 case IEEE80211_IOC_WPAKEY: 2287 error = ieee80211_ioctl_setkey(ic, ireq); 2288 break; 2289 case IEEE80211_IOC_DELKEY: 2290 error = ieee80211_ioctl_delkey(ic, ireq); 2291 break; 2292 case IEEE80211_IOC_MLME: 2293 error = ieee80211_ioctl_setmlme(ic, ireq); 2294 break; 2295 case IEEE80211_IOC_OPTIE: 2296 error = ieee80211_ioctl_setoptie(ic, ireq); 2297 break; 2298 case IEEE80211_IOC_COUNTERMEASURES: 2299 if (ireq->i_val) { 2300 if ((ic->ic_flags & IEEE80211_F_WPA) == 0) 2301 return EINVAL; 2302 ic->ic_flags |= IEEE80211_F_COUNTERM; 2303 } else 2304 ic->ic_flags &= ~IEEE80211_F_COUNTERM; 2305 break; 2306 case IEEE80211_IOC_WPA: 2307 if (ireq->i_val > 3) 2308 return EINVAL; 2309 /* XXX verify ciphers available */ 2310 ic->ic_flags &= ~IEEE80211_F_WPA; 2311 switch (ireq->i_val) { 2312 case 1: 2313 ic->ic_flags |= IEEE80211_F_WPA1; 2314 break; 2315 case 2: 2316 ic->ic_flags |= IEEE80211_F_WPA2; 2317 break; 2318 case 3: 2319 ic->ic_flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2; 2320 break; 2321 } 2322 error = ENETRESET; /* XXX? */ 2323 break; 2324 case IEEE80211_IOC_WME: 2325 if (ireq->i_val) { 2326 if ((ic->ic_caps & IEEE80211_C_WME) == 0) 2327 return EINVAL; 2328 ic->ic_flags |= IEEE80211_F_WME; 2329 } else 2330 ic->ic_flags &= ~IEEE80211_F_WME; 2331 error = ENETRESET; /* XXX maybe not for station? */ 2332 break; 2333 case IEEE80211_IOC_HIDESSID: 2334 if (ireq->i_val) 2335 ic->ic_flags |= IEEE80211_F_HIDESSID; 2336 else 2337 ic->ic_flags &= ~IEEE80211_F_HIDESSID; 2338 error = ENETRESET; 2339 break; 2340 case IEEE80211_IOC_APBRIDGE: 2341 if (ireq->i_val == 0) 2342 ic->ic_flags |= IEEE80211_F_NOBRIDGE; 2343 else 2344 ic->ic_flags &= ~IEEE80211_F_NOBRIDGE; 2345 break; 2346 case IEEE80211_IOC_MCASTCIPHER: 2347 if ((ic->ic_caps & cipher2cap(ireq->i_val)) == 0 && 2348 !ieee80211_crypto_available(ireq->i_val)) 2349 return EINVAL; 2350 rsn->rsn_mcastcipher = ireq->i_val; 2351 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0; 2352 break; 2353 case IEEE80211_IOC_MCASTKEYLEN: 2354 if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE)) 2355 return EINVAL; 2356 /* XXX no way to verify driver capability */ 2357 rsn->rsn_mcastkeylen = ireq->i_val; 2358 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0; 2359 break; 2360 case IEEE80211_IOC_UCASTCIPHERS: 2361 /* 2362 * Convert user-specified cipher set to the set 2363 * we can support (via hardware or software). 2364 * NB: this logic intentionally ignores unknown and 2365 * unsupported ciphers so folks can specify 0xff or 2366 * similar and get all available ciphers. 2367 */ 2368 caps = 0; 2369 for (j = 1; j < 32; j++) /* NB: skip WEP */ 2370 if ((ireq->i_val & (1<<j)) && 2371 ((ic->ic_caps & cipher2cap(j)) || 2372 ieee80211_crypto_available(j))) 2373 caps |= 1<<j; 2374 if (caps == 0) /* nothing available */ 2375 return EINVAL; 2376 /* XXX verify ciphers ok for unicast use? */ 2377 /* XXX disallow if running as it'll have no effect */ 2378 rsn->rsn_ucastcipherset = caps; 2379 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0; 2380 break; 2381 case IEEE80211_IOC_UCASTCIPHER: 2382 if ((rsn->rsn_ucastcipherset & cipher2cap(ireq->i_val)) == 0) 2383 return EINVAL; 2384 rsn->rsn_ucastcipher = ireq->i_val; 2385 break; 2386 case IEEE80211_IOC_UCASTKEYLEN: 2387 if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE)) 2388 return EINVAL; 2389 /* XXX no way to verify driver capability */ 2390 rsn->rsn_ucastkeylen = ireq->i_val; 2391 break; 2392 case IEEE80211_IOC_DRIVER_CAPS: 2393 /* NB: for testing */ 2394 ic->ic_caps = (((u_int16_t) ireq->i_val) << 16) | 2395 ((u_int16_t) ireq->i_len); 2396 break; 2397 case IEEE80211_IOC_KEYMGTALGS: 2398 /* XXX check */ 2399 rsn->rsn_keymgmtset = ireq->i_val; 2400 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0; 2401 break; 2402 case IEEE80211_IOC_RSNCAPS: 2403 /* XXX check */ 2404 rsn->rsn_caps = ireq->i_val; 2405 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0; 2406 break; 2407#if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211) 2408 case IEEE80211_IOC_BSSID: 2409 /* NB: should only be set when in STA mode */ 2410 if (ic->ic_opmode != IEEE80211_M_STA) 2411 return EINVAL; 2412 if (ireq->i_len != sizeof(tmpbssid)) 2413 return EINVAL; 2414 error = copyin(ireq->i_data, tmpbssid, ireq->i_len); 2415 if (error) 2416 break; 2417 IEEE80211_ADDR_COPY(ic->ic_des_bssid, tmpbssid); 2418 if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid)) 2419 ic->ic_flags &= ~IEEE80211_F_DESBSSID; 2420 else 2421 ic->ic_flags |= IEEE80211_F_DESBSSID; 2422 error = ENETRESET; 2423 break; 2424#endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */ 2425 case IEEE80211_IOC_CHANLIST: 2426 error = ieee80211_ioctl_setchanlist(ic, ireq); 2427 break; 2428 case IEEE80211_IOC_SCAN_REQ: 2429 if (ic->ic_opmode == IEEE80211_M_HOSTAP) /* XXX ignore */ 2430 break; 2431 error = ieee80211_setupscan(ic, ic->ic_chan_avail); 2432 if (error == 0) /* XXX background scan */ 2433 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 2434 break; 2435 case IEEE80211_IOC_ADDMAC: 2436 case IEEE80211_IOC_DELMAC: 2437 error = ieee80211_ioctl_macmac(ic, ireq); 2438 break; 2439 case IEEE80211_IOC_MACCMD: 2440 error = ieee80211_ioctl_setmaccmd(ic, ireq); 2441 break; 2442 case IEEE80211_IOC_STA_TXPOW: 2443 error = ieee80211_ioctl_setstatxpow(ic, ireq); 2444 break; 2445 case IEEE80211_IOC_WME_CWMIN: /* WME: CWmin */ 2446 case IEEE80211_IOC_WME_CWMAX: /* WME: CWmax */ 2447 case IEEE80211_IOC_WME_AIFS: /* WME: AIFS */ 2448 case IEEE80211_IOC_WME_TXOPLIMIT: /* WME: txops limit */ 2449 case IEEE80211_IOC_WME_ACM: /* WME: ACM (bss only) */ 2450 case IEEE80211_IOC_WME_ACKPOLICY: /* WME: ACK policy (bss only) */ 2451 error = ieee80211_ioctl_setwmeparam(ic, ireq); 2452 break; 2453 case IEEE80211_IOC_DTIM_PERIOD: 2454 if (ic->ic_opmode != IEEE80211_M_HOSTAP && 2455 ic->ic_opmode != IEEE80211_M_IBSS) 2456 return EINVAL; 2457 if (IEEE80211_DTIM_MIN <= ireq->i_val && 2458 ireq->i_val <= IEEE80211_DTIM_MAX) { 2459 ic->ic_dtim_period = ireq->i_val; 2460 error = ENETRESET; /* requires restart */ 2461 } else 2462 error = EINVAL; 2463 break; 2464 case IEEE80211_IOC_BEACON_INTERVAL: 2465 if (ic->ic_opmode != IEEE80211_M_HOSTAP && 2466 ic->ic_opmode != IEEE80211_M_IBSS) 2467 return EINVAL; 2468 if (IEEE80211_BINTVAL_MIN <= ireq->i_val && 2469 ireq->i_val <= IEEE80211_BINTVAL_MAX) { 2470 ic->ic_bintval = ireq->i_val; 2471 error = ENETRESET; /* requires restart */ 2472 } else 2473 error = EINVAL; 2474 break; 2475 case IEEE80211_IOC_PUREG: 2476 if (ireq->i_val) 2477 ic->ic_flags |= IEEE80211_F_PUREG; 2478 else 2479 ic->ic_flags &= ~IEEE80211_F_PUREG; 2480 /* NB: reset only if we're operating on an 11g channel */ 2481 if (ic->ic_curmode == IEEE80211_MODE_11G) 2482 error = ENETRESET; 2483 break; 2484 case IEEE80211_IOC_MCAST_RATE: 2485 ic->ic_mcast_rate = ireq->i_val & IEEE80211_RATE_VAL; 2486 break; 2487 case IEEE80211_IOC_FRAGTHRESHOLD: 2488 if ((ic->ic_caps & IEEE80211_C_TXFRAG) == 0 && 2489 ireq->i_val != IEEE80211_FRAG_MAX) 2490 return EINVAL; 2491 if (!(IEEE80211_FRAG_MIN <= ireq->i_val && 2492 ireq->i_val <= IEEE80211_FRAG_MAX)) 2493 return EINVAL; 2494 ic->ic_fragthreshold = ireq->i_val; 2495 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0; 2496 break; 2497 default: 2498 error = EINVAL; 2499 break; 2500 } 2501 if (error == ENETRESET && !IS_UP_AUTO(ic)) 2502 error = 0; 2503 return error; 2504} 2505 2506#ifdef __FreeBSD__ 2507int 2508ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, void *data) 2509{ 2510 struct ifnet *ifp = ic->ic_ifp; 2511 int error = 0; 2512 struct ifreq *ifr; 2513 struct ifaddr *ifa; /* XXX */ 2514 2515 switch (cmd) { 2516 case SIOCSIFMEDIA: 2517 case SIOCGIFMEDIA: 2518 error = ifmedia_ioctl(ifp, (struct ifreq *) data, 2519 &ic->ic_media, cmd); 2520 break; 2521 case SIOCG80211: 2522 error = ieee80211_ioctl_get80211(ic, cmd, 2523 (struct ieee80211req *) data); 2524 break; 2525 case SIOCS80211: 2526 error = suser(curthread); 2527 if (error == 0) 2528 error = ieee80211_ioctl_set80211(ic, cmd, 2529 (struct ieee80211req *) data); 2530 break; 2531 case SIOCGIFGENERIC: 2532 error = ieee80211_cfgget(ic, cmd, data); 2533 break; 2534 case SIOCSIFGENERIC: 2535 error = suser(curthread); 2536 if (error) 2537 break; 2538 error = ieee80211_cfgset(ic, cmd, data); 2539 break; 2540 case SIOCG80211STATS: 2541 ifr = (struct ifreq *)data; 2542 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats)); 2543 break; 2544 case SIOCSIFMTU: 2545 ifr = (struct ifreq *)data; 2546 if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu && 2547 ifr->ifr_mtu <= IEEE80211_MTU_MAX)) 2548 error = EINVAL; 2549 else 2550 ifp->if_mtu = ifr->ifr_mtu; 2551 break; 2552 default: 2553 error = ether_ioctl(ifp, cmd, data); 2554 break; 2555 } 2556 return error; 2557} 2558#endif /* __FreeBSD__ */ 2559 2560#ifdef COMPAT_20 2561static void 2562ieee80211_get_ostats(struct ieee80211_ostats *ostats, 2563 struct ieee80211_stats *stats) 2564{ 2565#define COPYSTATS1(__ostats, __nstats, __dstmemb, __srcmemb, __lastmemb)\ 2566 (void)memcpy(&(__ostats)->__dstmemb, &(__nstats)->__srcmemb, \ 2567 offsetof(struct ieee80211_stats, __lastmemb) - \ 2568 offsetof(struct ieee80211_stats, __srcmemb)) 2569#define COPYSTATS(__ostats, __nstats, __dstmemb, __lastmemb) \ 2570 COPYSTATS1(__ostats, __nstats, __dstmemb, __dstmemb, __lastmemb) 2571 2572 COPYSTATS(ostats, stats, is_rx_badversion, is_rx_unencrypted); 2573 COPYSTATS(ostats, stats, is_rx_wepfail, is_rx_beacon); 2574 COPYSTATS(ostats, stats, is_rx_rstoobig, is_rx_auth_countermeasures); 2575 COPYSTATS(ostats, stats, is_rx_assoc_bss, is_rx_assoc_badwpaie); 2576 COPYSTATS(ostats, stats, is_rx_deauth, is_rx_unauth); 2577 COPYSTATS1(ostats, stats, is_tx_nombuf, is_tx_nobuf, is_tx_badcipher); 2578 COPYSTATS(ostats, stats, is_scan_active, is_crypto_tkip); 2579} 2580#endif /* COMPAT_20 */ 2581 2582#ifdef __NetBSD__ 2583int 2584ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, void *data) 2585{ 2586 struct ifnet *ifp = ic->ic_ifp; 2587 struct ifreq *ifr = (struct ifreq *)data; 2588 int i, error = 0, kid, klen, s; 2589 struct ieee80211_key *k; 2590 struct ieee80211_nwid nwid; 2591 struct ieee80211_nwkey *nwkey; 2592 struct ieee80211_power *power; 2593 struct ieee80211_bssid *bssid; 2594 struct ieee80211chanreq *chanreq; 2595 struct ieee80211_channel *chan; 2596 uint32_t oflags; 2597#ifdef COMPAT_20 2598 struct ieee80211_ostats ostats; 2599#endif /* COMPAT_20 */ 2600 static const u_int8_t zerobssid[IEEE80211_ADDR_LEN]; 2601 u_int8_t tmpkey[IEEE80211_WEP_NKID][IEEE80211_KEYBUF_SIZE]; 2602 2603 switch (cmd) { 2604#ifdef OSIOCSIFMEDIA 2605 case OSIOCSIFMEDIA: 2606#endif 2607 case SIOCSIFMEDIA: 2608 case SIOCGIFMEDIA: 2609 error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 2610 break; 2611 case SIOCG80211: 2612 error = ieee80211_ioctl_get80211(ic, cmd, 2613 (struct ieee80211req *) data); 2614 break; 2615 case SIOCS80211: 2616 if ((error = kauth_authorize_network(curlwp->l_cred, 2617 KAUTH_NETWORK_INTERFACE, 2618 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, 2619 NULL)) != 0) 2620 break; 2621 error = ieee80211_ioctl_set80211(ic, cmd, 2622 (struct ieee80211req *) data); 2623 break; 2624 case SIOCS80211NWID: 2625 if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0) 2626 break; 2627 if (nwid.i_len > IEEE80211_NWID_LEN) { 2628 error = EINVAL; 2629 break; 2630 } 2631 memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); 2632 ic->ic_des_esslen = nwid.i_len; 2633 memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len); 2634 error = ENETRESET; 2635 break; 2636 case SIOCG80211NWID: 2637 memset(&nwid, 0, sizeof(nwid)); 2638 switch (ic->ic_state) { 2639 case IEEE80211_S_INIT: 2640 case IEEE80211_S_SCAN: 2641 nwid.i_len = ic->ic_des_esslen; 2642 memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len); 2643 break; 2644 default: 2645 nwid.i_len = ic->ic_bss->ni_esslen; 2646 memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len); 2647 break; 2648 } 2649 error = copyout(&nwid, ifr->ifr_data, sizeof(nwid)); 2650 break; 2651 case SIOCS80211NWKEY: 2652 nwkey = (struct ieee80211_nwkey *)data; 2653 /* transmit key index out of range? */ 2654 kid = nwkey->i_defkid - 1; 2655 if (kid < 0 || kid >= IEEE80211_WEP_NKID) { 2656 error = EINVAL; 2657 break; 2658 } 2659 /* no such transmit key is set? */ 2660 if (nwkey->i_key[kid].i_keylen == 0 || 2661 (nwkey->i_key[kid].i_keylen == -1 && 2662 ic->ic_nw_keys[kid].wk_keylen == 0)) { 2663 if (nwkey->i_wepon != IEEE80211_NWKEY_OPEN) { 2664 error = EINVAL; 2665 break; 2666 } 2667 } 2668 /* check key lengths */ 2669 for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) { 2670 klen = nwkey->i_key[kid].i_keylen; 2671 if ((klen > 0 && 2672 klen < IEEE80211_WEP_KEYLEN) || 2673 klen > sizeof(ic->ic_nw_keys[kid].wk_key)) { 2674 error = EINVAL; 2675 break; 2676 } 2677 } 2678 2679 if (error) 2680 break; 2681 2682 /* copy in keys */ 2683 (void)memset(tmpkey, 0, sizeof(tmpkey)); 2684 for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) { 2685 klen = nwkey->i_key[kid].i_keylen; 2686 if (klen <= 0) 2687 continue; 2688 if ((error = copyin(nwkey->i_key[kid].i_keydat, 2689 tmpkey[kid], klen)) != 0) 2690 break; 2691 } 2692 2693 if (error) 2694 break; 2695 2696 /* set keys */ 2697 ieee80211_key_update_begin(ic); 2698 for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) { 2699 klen = nwkey->i_key[kid].i_keylen; 2700 if (klen <= 0) 2701 continue; 2702 k = &ic->ic_nw_keys[kid]; 2703 k->wk_keyix = kid; 2704 if (!ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP, 2705 IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) { 2706 error = EINVAL; 2707 continue; 2708 } 2709 k->wk_keylen = nwkey->i_key[kid].i_keylen; 2710 (void)memcpy(k->wk_key, tmpkey[kid], 2711 sizeof(tmpkey[kid])); 2712 if (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr)) 2713 error = EINVAL; 2714 } 2715 ieee80211_key_update_end(ic); 2716 2717 if (error) 2718 break; 2719 2720 /* delete keys */ 2721 for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) { 2722 klen = nwkey->i_key[kid].i_keylen; 2723 k = &ic->ic_nw_keys[kid]; 2724 if (klen <= 0) 2725 (void)ieee80211_crypto_delkey(ic, k); 2726 } 2727 2728 /* set transmit key */ 2729 kid = nwkey->i_defkid - 1; 2730 if (ic->ic_def_txkey != kid) { 2731 ic->ic_def_txkey = kid; 2732 error = ENETRESET; 2733 } 2734 oflags = ic->ic_flags; 2735 if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) { 2736 ic->ic_flags &= ~IEEE80211_F_PRIVACY; 2737 ic->ic_flags &= ~IEEE80211_F_DROPUNENC; 2738 } else { 2739 ic->ic_flags |= IEEE80211_F_PRIVACY; 2740 ic->ic_flags |= IEEE80211_F_DROPUNENC; 2741 } 2742 if (oflags != ic->ic_flags) 2743 error = ENETRESET; 2744 break; 2745 case SIOCG80211NWKEY: 2746 nwkey = (struct ieee80211_nwkey *)data; 2747 if (ic->ic_flags & IEEE80211_F_PRIVACY) 2748 nwkey->i_wepon = IEEE80211_NWKEY_WEP; 2749 else 2750 nwkey->i_wepon = IEEE80211_NWKEY_OPEN; 2751 nwkey->i_defkid = ic->ic_def_txkey + 1; 2752 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 2753 if (nwkey->i_key[i].i_keydat == NULL) 2754 continue; 2755 /* do not show any keys to non-root user */ 2756 if ((error = kauth_authorize_network(curlwp->l_cred, 2757 KAUTH_NETWORK_INTERFACE, 2758 KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp, 2759 (void *)cmd, NULL)) != 0) 2760 break; 2761 nwkey->i_key[i].i_keylen = ic->ic_nw_keys[i].wk_keylen; 2762 if ((error = copyout(ic->ic_nw_keys[i].wk_key, 2763 nwkey->i_key[i].i_keydat, 2764 ic->ic_nw_keys[i].wk_keylen)) != 0) 2765 break; 2766 } 2767 break; 2768 case SIOCS80211POWER: 2769 power = (struct ieee80211_power *)data; 2770 ic->ic_lintval = power->i_maxsleep; 2771 if (power->i_enabled != 0) { 2772 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) 2773 error = EINVAL; 2774 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { 2775 ic->ic_flags |= IEEE80211_F_PMGTON; 2776 error = ENETRESET; 2777 } 2778 } else { 2779 if (ic->ic_flags & IEEE80211_F_PMGTON) { 2780 ic->ic_flags &= ~IEEE80211_F_PMGTON; 2781 error = ENETRESET; 2782 } 2783 } 2784 break; 2785 case SIOCG80211POWER: 2786 power = (struct ieee80211_power *)data; 2787 power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0; 2788 power->i_maxsleep = ic->ic_lintval; 2789 break; 2790 case SIOCS80211BSSID: 2791 bssid = (struct ieee80211_bssid *)data; 2792 IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid); 2793 if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid)) 2794 ic->ic_flags &= ~IEEE80211_F_DESBSSID; 2795 else 2796 ic->ic_flags |= IEEE80211_F_DESBSSID; 2797 error = ENETRESET; 2798 break; 2799 case SIOCG80211BSSID: 2800 bssid = (struct ieee80211_bssid *)data; 2801 switch (ic->ic_state) { 2802 case IEEE80211_S_INIT: 2803 case IEEE80211_S_SCAN: 2804 if (ic->ic_opmode == IEEE80211_M_HOSTAP) 2805 IEEE80211_ADDR_COPY(bssid->i_bssid, 2806 ic->ic_myaddr); 2807 else if (ic->ic_flags & IEEE80211_F_DESBSSID) 2808 IEEE80211_ADDR_COPY(bssid->i_bssid, 2809 ic->ic_des_bssid); 2810 else 2811 memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN); 2812 break; 2813 default: 2814 IEEE80211_ADDR_COPY(bssid->i_bssid, 2815 ic->ic_bss->ni_bssid); 2816 break; 2817 } 2818 break; 2819 case SIOCS80211CHANNEL: 2820 chanreq = (struct ieee80211chanreq *)data; 2821 if (chanreq->i_channel == IEEE80211_CHAN_ANY) 2822 ic->ic_des_chan = IEEE80211_CHAN_ANYC; 2823 else if (chanreq->i_channel > IEEE80211_CHAN_MAX || 2824 isclr(ic->ic_chan_active, chanreq->i_channel)) { 2825 error = EINVAL; 2826 break; 2827 } else 2828 ic->ic_ibss_chan = ic->ic_des_chan = 2829 &ic->ic_channels[chanreq->i_channel]; 2830 switch (ic->ic_state) { 2831 case IEEE80211_S_INIT: 2832 case IEEE80211_S_SCAN: 2833 error = ENETRESET; 2834 break; 2835 default: 2836 if (ic->ic_opmode == IEEE80211_M_STA) { 2837 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && 2838 ic->ic_bss->ni_chan != ic->ic_des_chan) 2839 error = ENETRESET; 2840 } else { 2841 if (ic->ic_bss->ni_chan != ic->ic_ibss_chan) 2842 error = ENETRESET; 2843 } 2844 break; 2845 } 2846 break; 2847 case SIOCG80211CHANNEL: 2848 chanreq = (struct ieee80211chanreq *)data; 2849 switch (ic->ic_state) { 2850 case IEEE80211_S_INIT: 2851 case IEEE80211_S_SCAN: 2852 if (ic->ic_opmode == IEEE80211_M_STA) 2853 chan = ic->ic_des_chan; 2854 else 2855 chan = ic->ic_ibss_chan; 2856 break; 2857 default: 2858 chan = ic->ic_curchan; 2859 break; 2860 } 2861 chanreq->i_channel = ieee80211_chan2ieee(ic, chan); 2862 break; 2863 case SIOCGIFGENERIC: 2864 error = ieee80211_cfgget(ic, cmd, data); 2865 break; 2866 case SIOCSIFGENERIC: 2867 error = kauth_authorize_network(curlwp->l_cred, 2868 KAUTH_NETWORK_INTERFACE, 2869 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, 2870 NULL); 2871 if (error) 2872 break; 2873 error = ieee80211_cfgset(ic, cmd, data); 2874 break; 2875#ifdef COMPAT_20 2876 case OSIOCG80211STATS: 2877 case OSIOCG80211ZSTATS: 2878 ifr = (struct ifreq *)data; 2879 s = splnet(); 2880 ieee80211_get_ostats(&ostats, &ic->ic_stats); 2881 error = copyout(&ostats, ifr->ifr_data, sizeof(ostats)); 2882 if (error == 0 && cmd == OSIOCG80211ZSTATS) 2883 (void)memset(&ic->ic_stats, 0, sizeof(ic->ic_stats)); 2884 splx(s); 2885 break; 2886#endif /* COMPAT_20 */ 2887 case SIOCG80211ZSTATS: 2888 case SIOCG80211STATS: 2889 ifr = (struct ifreq *)data; 2890 s = splnet(); 2891 error = copyout(&ic->ic_stats, ifr->ifr_buf, 2892 MIN(sizeof(ic->ic_stats), ifr->ifr_buflen)); 2893 if (error == 0 && cmd == SIOCG80211ZSTATS) 2894 (void)memset(&ic->ic_stats, 0, sizeof(ic->ic_stats)); 2895 splx(s); 2896 break; 2897 case SIOCSIFMTU: 2898 ifr = (struct ifreq *)data; 2899 if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu && 2900 ifr->ifr_mtu <= IEEE80211_MTU_MAX)) 2901 error = EINVAL; 2902 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 2903 error = 0; 2904 break; 2905 default: 2906 error = ether_ioctl(ifp, cmd, data); 2907 break; 2908 } 2909 return error; 2910} 2911#endif /* __NetBSD__ */ 2912