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