ieee80211_ioctl.c revision 1.48.4.1 1 /* $NetBSD: ieee80211_ioctl.c,v 1.48.4.1 2008/02/22 16:50:25 skrll Exp $ */
2 /*-
3 * Copyright (c) 2001 Atsushi Onoe
4 * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 #ifdef __FreeBSD__
30 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_ioctl.c,v 1.58 2007/11/02 05:22:24 sam Exp $");
31 #endif
32 #ifdef __NetBSD__
33 __KERNEL_RCSID(0, "$NetBSD: ieee80211_ioctl.c,v 1.48.4.1 2008/02/22 16:50:25 skrll Exp $");
34 #endif
35
36 /*
37 * IEEE 802.11 ioctl support (FreeBSD-specific)
38 */
39
40 #include "opt_inet.h"
41 #include "opt_compat_netbsd.h"
42
43 #include <sys/endian.h>
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/systm.h>
49 #include <sys/proc.h>
50 #include <sys/kauth.h>
51
52 #include <net/if.h>
53 #include <net/if_dl.h>
54 #include <net/if_media.h>
55 #include <net/if_ether.h>
56
57 #ifdef INET
58 #include <netinet/in.h>
59 #include <netinet/if_inarp.h>
60 #endif
61
62 #include <net80211/ieee80211_var.h>
63 #include <net80211/ieee80211_ioctl.h>
64
65 #include <dev/ic/wi_ieee.h>
66
67 #if defined(COMPAT_09) || defined(COMPAT_10) || defined(COMPAT_11) || \
68 defined(COMPAT_12) || defined(COMPAT_13) || defined(COMPAT_14) || \
69 defined(COMPAT_15) || defined(COMPAT_16) || defined(COMPAT_20) || \
70 defined(COMPAT_30) || defined(COMPAT_40)
71 #include <compat/sys/sockio.h>
72 #endif
73
74 #ifdef __FreeBSD__
75 #define IS_UP(_ic) \
76 (((_ic)->ic_ifp->if_flags & IFF_UP) && \
77 ((_ic)->ic_ifp->if_drv_flags & IFF_DRV_RUNNING))
78 #endif
79 #ifdef __NetBSD__
80 #define IS_UP(_ic) \
81 (((_ic)->ic_ifp->if_flags & IFF_UP) && \
82 ((_ic)->ic_ifp->if_flags & IFF_RUNNING))
83 #endif
84 #define IS_UP_AUTO(_ic) \
85 (IS_UP(_ic) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO)
86 #define RESCAN 1
87
88 /*
89 * XXX
90 * Wireless LAN specific configuration interface, which is compatible
91 * with wicontrol(8).
92 */
93
94 struct wi_read_ap_args {
95 int i; /* result count */
96 struct wi_apinfo *ap; /* current entry in result buffer */
97 void * max; /* result buffer bound */
98 };
99
100 static void
101 wi_read_ap_result(void *arg, struct ieee80211_node *ni)
102 {
103 struct ieee80211com *ic = ni->ni_ic;
104 struct wi_read_ap_args *sa = arg;
105 struct wi_apinfo *ap = sa->ap;
106 struct ieee80211_rateset *rs;
107 int j;
108
109 if ((void *)(ap + 1) > sa->max)
110 return;
111 memset(ap, 0, sizeof(struct wi_apinfo));
112 if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
113 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
114 ap->namelen = ic->ic_des_ssid[0].len;
115 if (ic->ic_des_ssid[0].len)
116 memcpy(ap->name, ic->ic_des_ssid[0].ssid,
117 ic->ic_des_ssid[0].len);
118 } else {
119 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
120 ap->namelen = ni->ni_esslen;
121 if (ni->ni_esslen)
122 memcpy(ap->name, ni->ni_essid,
123 ni->ni_esslen);
124 }
125 ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
126 ap->signal = ic->ic_node_getrssi(ni);
127 ap->capinfo = ni->ni_capinfo;
128 ap->interval = ni->ni_intval;
129 rs = &ni->ni_rates;
130 for (j = 0; j < rs->rs_nrates; j++) {
131 if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
132 ap->rate = (rs->rs_rates[j] &
133 IEEE80211_RATE_VAL) * 5; /* XXX */
134 }
135 }
136 sa->i++;
137 sa->ap++;
138 }
139
140 struct wi_read_prism2_args {
141 int i; /* result count */
142 struct wi_scan_res *res;/* current entry in result buffer */
143 void * max; /* result buffer bound */
144 };
145
146 #if 0
147 static void
148 wi_read_prism2_result(void *arg, struct ieee80211_node *ni)
149 {
150 struct ieee80211com *ic = ni->ni_ic;
151 struct wi_read_prism2_args *sa = arg;
152 struct wi_scan_res *res = sa->res;
153
154 if ((void *)(res + 1) > sa->max)
155 return;
156 res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
157 res->wi_noise = 0;
158 res->wi_signal = ic->ic_node_getrssi(ni);
159 IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
160 res->wi_interval = ni->ni_intval;
161 res->wi_capinfo = ni->ni_capinfo;
162 res->wi_ssid_len = ni->ni_esslen;
163 memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
164 /* NB: assumes wi_srates holds <= ni->ni_rates */
165 memcpy(res->wi_srates, ni->ni_rates.rs_rates,
166 sizeof(res->wi_srates));
167 if (ni->ni_rates.rs_nrates < 10)
168 res->wi_srates[ni->ni_rates.rs_nrates] = 0;
169 res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
170 res->wi_rsvd = 0;
171
172 sa->i++;
173 sa->res++;
174 }
175
176 struct wi_read_sigcache_args {
177 int i; /* result count */
178 struct wi_sigcache *wsc;/* current entry in result buffer */
179 void * max; /* result buffer bound */
180 };
181
182 static void
183 wi_read_sigcache(void *arg, struct ieee80211_node *ni)
184 {
185 struct ieee80211com *ic = ni->ni_ic;
186 struct wi_read_sigcache_args *sa = arg;
187 struct wi_sigcache *wsc = sa->wsc;
188
189 if ((void *)(wsc + 1) > sa->max)
190 return;
191 memset(wsc, 0, sizeof(struct wi_sigcache));
192 IEEE80211_ADDR_COPY(wsc->macsrc, ni->ni_macaddr);
193 wsc->signal = ic->ic_node_getrssi(ni);
194
195 sa->wsc++;
196 sa->i++;
197 }
198 #endif
199
200 int
201 ieee80211_cfgget(struct ieee80211com *ic, u_long cmd, void *data)
202 {
203 struct ifnet *ifp = ic->ic_ifp;
204 int i, j, error;
205 struct ifreq *ifr = (struct ifreq *)data;
206 struct wi_req *wreq;
207 struct wi_ltv_keys *keys;
208
209 wreq = malloc(sizeof(*wreq), M_TEMP, M_WAITOK);
210 error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
211 if (error)
212 goto out;
213 wreq->wi_len = 0;
214 switch (wreq->wi_type) {
215 case WI_RID_SERIALNO:
216 case WI_RID_STA_IDENTITY:
217 /* nothing appropriate */
218 break;
219 case WI_RID_NODENAME:
220 strlcpy((char *)&wreq->wi_val[1], hostname,
221 sizeof(wreq->wi_val) - sizeof(wreq->wi_val[0]));
222 wreq->wi_val[0] = htole16(strlen(hostname));
223 wreq->wi_len = (1 + strlen(hostname) + 1) / 2;
224 break;
225 case WI_RID_CURRENT_SSID:
226 if (ic->ic_state != IEEE80211_S_RUN) {
227 wreq->wi_val[0] = 0;
228 wreq->wi_len = 1;
229 break;
230 }
231 wreq->wi_val[0] = htole16(ic->ic_bss->ni_esslen);
232 memcpy(&wreq->wi_val[1], ic->ic_bss->ni_essid,
233 ic->ic_bss->ni_esslen);
234 wreq->wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
235 break;
236 case WI_RID_OWN_SSID:
237 case WI_RID_DESIRED_SSID:
238 wreq->wi_val[0] = htole16(ic->ic_des_ssid[0].len);
239 memcpy(&wreq->wi_val[1], ic->ic_des_ssid[0].ssid, ic->ic_des_ssid[0].len);
240 wreq->wi_len = (1 + ic->ic_des_ssid[0].len + 1) / 2;
241 break;
242 case WI_RID_CURRENT_BSSID:
243 if (ic->ic_state == IEEE80211_S_RUN)
244 IEEE80211_ADDR_COPY(wreq->wi_val, ic->ic_bss->ni_bssid);
245 else
246 memset(wreq->wi_val, 0, IEEE80211_ADDR_LEN);
247 wreq->wi_len = IEEE80211_ADDR_LEN / 2;
248 break;
249 case WI_RID_CHANNEL_LIST:
250 memset(wreq->wi_val, 0, sizeof(wreq->wi_val));
251 /*
252 * Since channel 0 is not available for DS, channel 1
253 * is assigned to LSB on WaveLAN.
254 */
255 if (ic->ic_phytype == IEEE80211_T_DS)
256 i = 1;
257 else
258 i = 0;
259 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
260 if (isset(ic->ic_chan_active, i)) {
261 setbit((u_int8_t *)wreq->wi_val, j);
262 wreq->wi_len = j / 16 + 1;
263 }
264 break;
265 case WI_RID_OWN_CHNL:
266 wreq->wi_val[0] = htole16(
267 ieee80211_chan2ieee(ic, ic->ic_bsschan));
268 wreq->wi_len = 1;
269 break;
270 case WI_RID_CURRENT_CHAN:
271 wreq->wi_val[0] = htole16(
272 ieee80211_chan2ieee(ic, ic->ic_curchan));
273 wreq->wi_len = 1;
274 break;
275 case WI_RID_COMMS_QUALITY:
276 wreq->wi_val[0] = 0; /* quality */
277 wreq->wi_val[1] = htole16(ic->ic_node_getrssi(ic->ic_bss));
278 wreq->wi_val[2] = 0; /* noise */
279 wreq->wi_len = 3;
280 break;
281 case WI_RID_PROMISC:
282 wreq->wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
283 wreq->wi_len = 1;
284 break;
285 case WI_RID_PORTTYPE:
286 wreq->wi_val[0] = htole16(ic->ic_opmode);
287 wreq->wi_len = 1;
288 break;
289 case WI_RID_MAC_NODE:
290 IEEE80211_ADDR_COPY(wreq->wi_val, ic->ic_myaddr);
291 wreq->wi_len = IEEE80211_ADDR_LEN / 2;
292 break;
293 case WI_RID_TX_RATE:
294 if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
295 wreq->wi_val[0] = 0; /* auto */
296 else
297 wreq->wi_val[0] = htole16(
298 (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
299 IEEE80211_RATE_VAL) / 2);
300 wreq->wi_len = 1;
301 break;
302 case WI_RID_CUR_TX_RATE:
303 wreq->wi_val[0] = htole16(
304 (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
305 IEEE80211_RATE_VAL) / 2);
306 wreq->wi_len = 1;
307 break;
308 case WI_RID_FRAG_THRESH:
309 wreq->wi_val[0] = htole16(ic->ic_fragthreshold);
310 wreq->wi_len = 1;
311 break;
312 case WI_RID_RTS_THRESH:
313 wreq->wi_val[0] = htole16(ic->ic_rtsthreshold);
314 wreq->wi_len = 1;
315 break;
316 case WI_RID_CREATE_IBSS:
317 wreq->wi_val[0] =
318 htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
319 wreq->wi_len = 1;
320 break;
321 case WI_RID_MICROWAVE_OVEN:
322 wreq->wi_val[0] = 0; /* no ... not supported */
323 wreq->wi_len = 1;
324 break;
325 case WI_RID_ROAMING_MODE:
326 wreq->wi_val[0] = htole16(ic->ic_roaming); /* XXX map */
327 wreq->wi_len = 1;
328 break;
329 case WI_RID_SYSTEM_SCALE:
330 wreq->wi_val[0] = htole16(1); /* low density ... not supp */
331 wreq->wi_len = 1;
332 break;
333 case WI_RID_PM_ENABLED:
334 wreq->wi_val[0] =
335 htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
336 wreq->wi_len = 1;
337 break;
338 case WI_RID_MAX_SLEEP:
339 wreq->wi_val[0] = htole16(ic->ic_lintval);
340 wreq->wi_len = 1;
341 break;
342 case WI_RID_CUR_BEACON_INT:
343 wreq->wi_val[0] = htole16(ic->ic_bss->ni_intval);
344 wreq->wi_len = 1;
345 break;
346 case WI_RID_WEP_AVAIL:
347 wreq->wi_val[0] = htole16(1); /* always available */
348 wreq->wi_len = 1;
349 break;
350 case WI_RID_CNFAUTHMODE:
351 wreq->wi_val[0] = htole16(1); /* TODO: open system only */
352 wreq->wi_len = 1;
353 break;
354 case WI_RID_ENCRYPTION:
355 wreq->wi_val[0] =
356 htole16((ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0);
357 wreq->wi_len = 1;
358 break;
359 case WI_RID_TX_CRYPT_KEY:
360 wreq->wi_val[0] = htole16(ic->ic_def_txkey);
361 wreq->wi_len = 1;
362 break;
363 case WI_RID_DEFLT_CRYPT_KEYS:
364 keys = (struct wi_ltv_keys *)wreq;
365 /* do not show keys to non-root user */
366 error = kauth_authorize_network(curlwp->l_cred,
367 KAUTH_NETWORK_INTERFACE,
368 KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp,
369 NULL, NULL);
370 if (error) {
371 memset(keys, 0, sizeof(*keys));
372 error = 0;
373 break;
374 }
375 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
376 keys->wi_keys[i].wi_keylen =
377 htole16(ic->ic_nw_keys[i].wk_keylen);
378 memcpy(keys->wi_keys[i].wi_keydat,
379 ic->ic_nw_keys[i].wk_key,
380 ic->ic_nw_keys[i].wk_keylen);
381 }
382 wreq->wi_len = sizeof(*keys) / 2;
383 break;
384 case WI_RID_MAX_DATALEN:
385 wreq->wi_val[0] = htole16(ic->ic_fragthreshold);
386 wreq->wi_len = 1;
387 break;
388 case WI_RID_DBM_ADJUST:
389 /* not supported, we just pass rssi value from driver. */
390 break;
391 case WI_RID_IFACE_STATS:
392 /* XXX: should be implemented in lower drivers */
393 break;
394 case WI_RID_READ_APS:
395 /*
396 * Don't return results until active scan completes.
397 */
398 if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) {
399 struct wi_read_ap_args args;
400
401 args.i = 0;
402 args.ap = (void *)((char *)wreq->wi_val + sizeof(i));
403 args.max = (void *)(wreq + 1);
404 ieee80211_iterate_nodes(&ic->ic_sta,
405 wi_read_ap_result, &args);
406 memcpy(wreq->wi_val, &args.i, sizeof(args.i));
407 wreq->wi_len = (sizeof(int) +
408 sizeof(struct wi_apinfo) * args.i) / 2;
409 } else
410 error = EINPROGRESS;
411 break;
412 #if 0
413 case WI_RID_SCAN_RES: /* compatibility interface */
414 if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) {
415 struct wi_read_prism2_args args;
416 struct wi_scan_p2_hdr *p2;
417
418 /* NB: use Prism2 format so we can include rate info */
419 p2 = (struct wi_scan_p2_hdr *)wreq->wi_val;
420 args.i = 0;
421 args.res = (void *)&p2[1];
422 args.max = (void *)(wreq + 1);
423 ieee80211_iterate_nodes(&ic->ic_scan,
424 wi_read_prism2_result, &args);
425 p2->wi_rsvd = 0;
426 p2->wi_reason = args.i;
427 wreq->wi_len = (sizeof(*p2) +
428 sizeof(struct wi_scan_res) * args.i) / 2;
429 } else
430 error = EINPROGRESS;
431 break;
432 case WI_RID_READ_CACHE: {
433 struct wi_read_sigcache_args args;
434 args.i = 0;
435 args.wsc = (struct wi_sigcache *) wreq->wi_val;
436 args.max = (void *)(wreq + 1);
437 ieee80211_iterate_nodes(&ic->ic_scan, wi_read_sigcache, &args);
438 wreq->wi_len = sizeof(struct wi_sigcache) * args.i / 2;
439 break;
440 }
441 #endif
442 default:
443 error = EINVAL;
444 break;
445 }
446 if (error == 0) {
447 wreq->wi_len++;
448 error = copyout(wreq, ifr->ifr_data, sizeof(*wreq));
449 }
450 out:
451 free(wreq, M_TEMP);
452 return error;
453 }
454
455 static int
456 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
457 {
458 #define IEEERATE(_ic,_m,_i) \
459 ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
460 int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
461 for (i = 0; i < nrates; i++)
462 if (IEEERATE(ic, mode, i) == rate)
463 return i;
464 return -1;
465 #undef IEEERATE
466 }
467
468 /*
469 * Prepare to do a user-initiated scan for AP's. If no
470 * current/default channel is setup or the current channel
471 * is invalid then pick the first available channel from
472 * the active list as the place to start the scan.
473 */
474 static int
475 ieee80211_setupscan(struct ieee80211com *ic, const u_int8_t chanlist[])
476 {
477
478 /*
479 * XXX don't permit a scan to be started unless we
480 * know the device is ready. For the moment this means
481 * the device is marked up as this is the required to
482 * initialize the hardware. It would be better to permit
483 * scanning prior to being up but that'll require some
484 * changes to the infrastructure.
485 */
486 if (!IS_UP(ic))
487 return EINVAL;
488 memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
489 /*
490 * We force the state to INIT before calling ieee80211_new_state
491 * to get ieee80211_begin_scan called. We really want to scan w/o
492 * altering the current state but that's not possible right now.
493 */
494 /* XXX handle proberequest case */
495 ic->ic_state = IEEE80211_S_INIT; /* XXX bypass state machine */
496 return 0;
497 }
498
499 int
500 ieee80211_cfgset(struct ieee80211com *ic, u_long cmd, void *data)
501 {
502 struct ifnet *ifp = ic->ic_ifp;
503 int i, j, len, error, rate;
504 struct ifreq *ifr = (struct ifreq *)data;
505 struct wi_ltv_keys *keys;
506 struct wi_req *wreq;
507 u_int8_t chanlist[IEEE80211_CHAN_BYTES];
508
509 wreq = malloc(sizeof(*wreq), M_TEMP, M_WAITOK);
510 error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
511 if (error)
512 goto out;
513 len = wreq->wi_len ? (wreq->wi_len - 1) * 2 : 0;
514 switch (wreq->wi_type) {
515 case WI_RID_SERIALNO:
516 case WI_RID_NODENAME:
517 case WI_RID_CURRENT_SSID:
518 error = EPERM;
519 goto out;
520 case WI_RID_OWN_SSID:
521 case WI_RID_DESIRED_SSID:
522 if (le16toh(wreq->wi_val[0]) * 2 > len ||
523 le16toh(wreq->wi_val[0]) > IEEE80211_NWID_LEN) {
524 error = ENOSPC;
525 break;
526 }
527 memset(ic->ic_des_ssid[0].ssid, 0, sizeof(ic->ic_des_ssid[0].len));
528 ic->ic_des_ssid[0].len = le16toh(wreq->wi_val[0]) * 2;
529 memcpy(ic->ic_des_ssid[0].ssid, &wreq->wi_val[1], ic->ic_des_ssid[0].len);
530 error = ENETRESET;
531 break;
532 case WI_RID_CURRENT_BSSID:
533 error = EPERM;
534 goto out;
535 case WI_RID_OWN_CHNL:
536 if (len != 2)
537 goto invalid;
538 i = le16toh(wreq->wi_val[0]);
539 if (i < 0 ||
540 i > IEEE80211_CHAN_MAX ||
541 isclr(ic->ic_chan_active, i))
542 goto invalid;
543 ic->ic_bsschan = &ic->ic_channels[i];
544 if (ic->ic_opmode == IEEE80211_M_MONITOR)
545 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
546 else
547 error = ENETRESET;
548 break;
549 case WI_RID_CURRENT_CHAN:
550 case WI_RID_COMMS_QUALITY:
551 error = EPERM;
552 goto out;
553 case WI_RID_PROMISC:
554 if (len != 2)
555 goto invalid;
556 if (ifp->if_flags & IFF_PROMISC) {
557 if (wreq->wi_val[0] == 0) {
558 ifp->if_flags &= ~IFF_PROMISC;
559 error = ENETRESET;
560 }
561 } else {
562 if (wreq->wi_val[0] != 0) {
563 ifp->if_flags |= IFF_PROMISC;
564 error = ENETRESET;
565 }
566 }
567 break;
568 case WI_RID_PORTTYPE:
569 if (len != 2)
570 goto invalid;
571 switch (le16toh(wreq->wi_val[0])) {
572 case IEEE80211_M_STA:
573 break;
574 case IEEE80211_M_IBSS:
575 if (!(ic->ic_caps & IEEE80211_C_IBSS))
576 goto invalid;
577 break;
578 case IEEE80211_M_AHDEMO:
579 if (ic->ic_phytype != IEEE80211_T_DS ||
580 !(ic->ic_caps & IEEE80211_C_AHDEMO))
581 goto invalid;
582 break;
583 case IEEE80211_M_HOSTAP:
584 if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
585 goto invalid;
586 break;
587 default:
588 goto invalid;
589 }
590 if (le16toh(wreq->wi_val[0]) != ic->ic_opmode) {
591 ic->ic_opmode = le16toh(wreq->wi_val[0]);
592 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
593 }
594 break;
595 #if 0
596 case WI_RID_MAC_NODE:
597 if (len != IEEE80211_ADDR_LEN)
598 goto invalid;
599 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq->wi_val);
600 /* if_init will copy lladdr into ic_myaddr */
601 error = ENETRESET;
602 break;
603 #endif
604 case WI_RID_TX_RATE:
605 if (len != 2)
606 goto invalid;
607 if (wreq->wi_val[0] == 0) {
608 /* auto */
609 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
610 break;
611 }
612 rate = 2 * le16toh(wreq->wi_val[0]);
613 if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
614 /*
615 * In autoselect mode search for the rate. We take
616 * the first instance which may not be right, but we
617 * are limited by the interface. Note that we also
618 * lock the mode to insure the rate is meaningful
619 * when it is used.
620 */
621 for (j = IEEE80211_MODE_11A;
622 j < IEEE80211_MODE_MAX; j++) {
623 if (isset(ic->ic_modecaps, j))
624 continue;
625 i = findrate(ic, j, rate);
626 if (i != -1) {
627 /* lock mode too */
628 ic->ic_curmode = j;
629 goto setrate;
630 }
631 }
632 } else {
633 i = findrate(ic, ic->ic_curmode, rate);
634 if (i != -1)
635 goto setrate;
636 }
637 goto invalid;
638 setrate:
639 ic->ic_fixed_rate = i;
640 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
641 break;
642 case WI_RID_CUR_TX_RATE:
643 error = EPERM;
644 goto out;
645 case WI_RID_FRAG_THRESH:
646 if (len != 2)
647 goto invalid;
648 ic->ic_fragthreshold = le16toh(wreq->wi_val[0]);
649 error = ENETRESET;
650 break;
651 case WI_RID_RTS_THRESH:
652 if (len != 2)
653 goto invalid;
654 ic->ic_rtsthreshold = le16toh(wreq->wi_val[0]);
655 error = ENETRESET;
656 break;
657 case WI_RID_CREATE_IBSS:
658 if (len != 2)
659 goto invalid;
660 if (wreq->wi_val[0] != 0) {
661 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
662 goto invalid;
663 if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
664 ic->ic_flags |= IEEE80211_F_IBSSON;
665 if (ic->ic_opmode == IEEE80211_M_IBSS &&
666 ic->ic_state == IEEE80211_S_SCAN)
667 error = IS_UP_AUTO(ic) ? ENETRESET : 0;
668 }
669 } else {
670 if (ic->ic_flags & IEEE80211_F_IBSSON) {
671 ic->ic_flags &= ~IEEE80211_F_IBSSON;
672 if (ic->ic_flags & IEEE80211_F_SIBSS) {
673 ic->ic_flags &= ~IEEE80211_F_SIBSS;
674 error = IS_UP_AUTO(ic) ? ENETRESET : 0;
675 }
676 }
677 }
678 break;
679 case WI_RID_MICROWAVE_OVEN:
680 if (len != 2)
681 goto invalid;
682 if (wreq->wi_val[0] != 0)
683 goto invalid; /* not supported */
684 break;
685 case WI_RID_ROAMING_MODE:
686 if (len != 2)
687 goto invalid;
688 i = le16toh(wreq->wi_val[0]);
689 if (i > IEEE80211_ROAMING_MANUAL)
690 goto invalid; /* not supported */
691 ic->ic_roaming = i;
692 break;
693 case WI_RID_SYSTEM_SCALE:
694 if (len != 2)
695 goto invalid;
696 if (le16toh(wreq->wi_val[0]) != 1)
697 goto invalid; /* not supported */
698 break;
699 case WI_RID_PM_ENABLED:
700 if (len != 2)
701 goto invalid;
702 if (wreq->wi_val[0] != 0) {
703 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
704 goto invalid;
705 if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
706 ic->ic_flags |= IEEE80211_F_PMGTON;
707 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
708 }
709 } else {
710 if (ic->ic_flags & IEEE80211_F_PMGTON) {
711 ic->ic_flags &= ~IEEE80211_F_PMGTON;
712 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
713 }
714 }
715 break;
716 case WI_RID_MAX_SLEEP:
717 if (len != 2)
718 goto invalid;
719 ic->ic_lintval = le16toh(wreq->wi_val[0]);
720 if (ic->ic_flags & IEEE80211_F_PMGTON)
721 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
722 break;
723 case WI_RID_CUR_BEACON_INT:
724 case WI_RID_WEP_AVAIL:
725 error = EPERM;
726 goto out;
727 case WI_RID_CNFAUTHMODE:
728 if (len != 2)
729 goto invalid;
730 i = le16toh(wreq->wi_val[0]);
731 if (i > IEEE80211_AUTH_WPA)
732 goto invalid;
733 ic->ic_bss->ni_authmode = i; /* XXX ENETRESET? */
734 error = ENETRESET;
735 break;
736 case WI_RID_ENCRYPTION:
737 if (len != 2)
738 goto invalid;
739 if (wreq->wi_val[0] != 0) {
740 if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
741 goto invalid;
742 if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
743 ic->ic_flags |= IEEE80211_F_PRIVACY;
744 error = ENETRESET;
745 }
746 } else {
747 if (ic->ic_flags & IEEE80211_F_PRIVACY) {
748 ic->ic_flags &= ~IEEE80211_F_PRIVACY;
749 error = ENETRESET;
750 }
751 }
752 break;
753 case WI_RID_TX_CRYPT_KEY:
754 if (len != 2)
755 goto invalid;
756 i = le16toh(wreq->wi_val[0]);
757 if (i >= IEEE80211_WEP_NKID)
758 goto invalid;
759 ic->ic_def_txkey = i;
760 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
761 break;
762 case WI_RID_DEFLT_CRYPT_KEYS:
763 if (len != sizeof(struct wi_ltv_keys))
764 goto invalid;
765 keys = (struct wi_ltv_keys *)wreq;
766 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
767 len = le16toh(keys->wi_keys[i].wi_keylen);
768 if (len != 0 && len < IEEE80211_WEP_KEYLEN)
769 goto invalid;
770 if (len > IEEE80211_KEYBUF_SIZE)
771 goto invalid;
772 }
773 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
774 struct ieee80211_key *k = &ic->ic_nw_keys[i];
775
776 len = le16toh(keys->wi_keys[i].wi_keylen);
777 k->wk_keylen = len;
778 k->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
779 memset(k->wk_key, 0, sizeof(k->wk_key));
780 memcpy(k->wk_key, keys->wi_keys[i].wi_keydat, len);
781 #if 0
782 k->wk_type = IEEE80211_CIPHER_WEP;
783 #endif
784 }
785 error = ENETRESET;
786 break;
787 case WI_RID_MAX_DATALEN:
788 if (len != 2)
789 goto invalid;
790 len = le16toh(wreq->wi_val[0]);
791 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
792 goto invalid;
793 ic->ic_fragthreshold = len;
794 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
795 break;
796 case WI_RID_IFACE_STATS:
797 error = EPERM;
798 break;
799 case WI_RID_SCAN_REQ: /* XXX wicontrol */
800 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
801 break;
802 error = ieee80211_setupscan(ic, ic->ic_chan_avail);
803 if (error == 0)
804 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
805 break;
806 case WI_RID_SCAN_APS:
807 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
808 break;
809 len--; /* XXX: tx rate? */
810 /* FALLTHRU */
811 case WI_RID_CHANNEL_LIST:
812 memset(chanlist, 0, sizeof(chanlist));
813 /*
814 * Since channel 0 is not available for DS, channel 1
815 * is assigned to LSB on WaveLAN.
816 */
817 if (ic->ic_phytype == IEEE80211_T_DS)
818 i = 1;
819 else
820 i = 0;
821 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
822 if ((j / 8) >= len)
823 break;
824 if (isclr((u_int8_t *)wreq->wi_val, j))
825 continue;
826 if (isclr(ic->ic_chan_active, i)) {
827 if (wreq->wi_type != WI_RID_CHANNEL_LIST)
828 continue;
829 if (isclr(ic->ic_chan_avail, i)) {
830 error = EPERM;
831 goto out;
832 }
833 }
834 setbit(chanlist, i);
835 }
836 error = ieee80211_setupscan(ic, chanlist);
837 if (wreq->wi_type == WI_RID_CHANNEL_LIST) {
838 /* NB: ignore error from ieee80211_setupscan */
839 error = ENETRESET;
840 } else if (error == 0)
841 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
842 break;
843 default:
844 goto invalid;
845 }
846 if (error == ENETRESET && !IS_UP_AUTO(ic))
847 error = 0;
848 out:
849 free(wreq, M_TEMP);
850 return error;
851 invalid:
852 free(wreq, M_TEMP);
853 return EINVAL;
854 }
855
856 static int
857 cap2cipher(int flag)
858 {
859 switch (flag) {
860 case IEEE80211_C_WEP: return IEEE80211_CIPHER_WEP;
861 case IEEE80211_C_AES: return IEEE80211_CIPHER_AES_OCB;
862 case IEEE80211_C_AES_CCM: return IEEE80211_CIPHER_AES_CCM;
863 case IEEE80211_C_CKIP: return IEEE80211_CIPHER_CKIP;
864 case IEEE80211_C_TKIP: return IEEE80211_CIPHER_TKIP;
865 }
866 return -1;
867 }
868
869 static int
870 ieee80211_ioctl_getkey(struct ieee80211com *ic, struct ieee80211req *ireq)
871 {
872 struct ieee80211_node *ni;
873 struct ieee80211req_key ik;
874 struct ieee80211_key *wk;
875 const struct ieee80211_cipher *cip;
876 u_int kid;
877 int error;
878
879 if (ireq->i_len != sizeof(ik))
880 return EINVAL;
881 error = copyin(ireq->i_data, &ik, sizeof(ik));
882 if (error)
883 return error;
884 kid = ik.ik_keyix;
885 if (kid == IEEE80211_KEYIX_NONE) {
886 ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
887 if (ni == NULL)
888 return EINVAL; /* XXX */
889 wk = &ni->ni_ucastkey;
890 } else {
891 if (kid >= IEEE80211_WEP_NKID)
892 return EINVAL;
893 wk = &ic->ic_nw_keys[kid];
894 IEEE80211_ADDR_COPY(&ik.ik_macaddr, ic->ic_bss->ni_macaddr);
895 ni = NULL;
896 }
897 cip = wk->wk_cipher;
898 ik.ik_type = cip->ic_cipher;
899 ik.ik_keylen = wk->wk_keylen;
900 ik.ik_flags = wk->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
901 if (wk->wk_keyix == ic->ic_def_txkey)
902 ik.ik_flags |= IEEE80211_KEY_DEFAULT;
903 if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_INTERFACE,
904 KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ic->ic_ifp, NULL, NULL) == 0) {
905 /* NB: only root can read key data */
906 ik.ik_keyrsc = wk->wk_keyrsc;
907 ik.ik_keytsc = wk->wk_keytsc;
908 memcpy(ik.ik_keydata, wk->wk_key, wk->wk_keylen);
909 if (cip->ic_cipher == IEEE80211_CIPHER_TKIP) {
910 memcpy(ik.ik_keydata+wk->wk_keylen,
911 wk->wk_key + IEEE80211_KEYBUF_SIZE,
912 IEEE80211_MICBUF_SIZE);
913 ik.ik_keylen += IEEE80211_MICBUF_SIZE;
914 }
915 } else {
916 ik.ik_keyrsc = 0;
917 ik.ik_keytsc = 0;
918 memset(ik.ik_keydata, 0, sizeof(ik.ik_keydata));
919 }
920 if (ni != NULL)
921 ieee80211_free_node(ni);
922 return copyout(&ik, ireq->i_data, sizeof(ik));
923 }
924
925 static int
926 ieee80211_ioctl_getchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
927 {
928 size_t len = ireq->i_len;
929
930 if (sizeof(ic->ic_chan_active) < len) {
931 len = sizeof(ic->ic_chan_active);
932 }
933 return copyout(&ic->ic_chan_active, ireq->i_data, len);
934 }
935
936 static int
937 ieee80211_ioctl_getchaninfo(struct ieee80211com *ic, struct ieee80211req *ireq)
938 {
939 int space;
940
941 space = __offsetof(struct ieee80211req_chaninfo,
942 ic_chans[ic->ic_nchans]);
943 if (space > ireq->i_len)
944 space = ireq->i_len;
945 /* XXX assumes compatible layout */
946 return copyout(&ic->ic_nchans, ireq->i_data, space);
947 }
948
949 static int
950 ieee80211_ioctl_getwpaie(struct ieee80211com *ic, struct ieee80211req *ireq, int req)
951 {
952 struct ieee80211_node *ni;
953 struct ieee80211req_wpaie2 wpaie;
954 int error;
955
956 if (ireq->i_len < IEEE80211_ADDR_LEN)
957 return EINVAL;
958 error = copyin(ireq->i_data, wpaie.wpa_macaddr, IEEE80211_ADDR_LEN);
959 if (error != 0)
960 return error;
961 ni = ieee80211_find_node(&ic->ic_sta, wpaie.wpa_macaddr);
962 if (ni == NULL)
963 return ENOENT; /* XXX */
964 memset(wpaie.wpa_ie, 0, sizeof(wpaie.wpa_ie));
965 if (ni->ni_wpa_ie != NULL) {
966 int ielen = ni->ni_wpa_ie[1] + 2;
967 if (ielen > sizeof(wpaie.wpa_ie))
968 ielen = sizeof(wpaie.wpa_ie);
969 memcpy(wpaie.wpa_ie, ni->ni_wpa_ie, ielen);
970 }
971 if (req == IEEE80211_IOC_WPAIE2) {
972 memset(wpaie.rsn_ie, 0, sizeof(wpaie.rsn_ie));
973 if (ni->ni_rsn_ie != NULL) {
974 int ielen = ni->ni_rsn_ie[1] + 2;
975 if (ielen > sizeof(wpaie.rsn_ie))
976 ielen = sizeof(wpaie.rsn_ie);
977 memcpy(wpaie.rsn_ie, ni->ni_rsn_ie, ielen);
978 }
979 if (ireq->i_len > sizeof(struct ieee80211req_wpaie2))
980 ireq->i_len = sizeof(struct ieee80211req_wpaie2);
981 } else {
982 /* compatibility op, may overwrite wpa ie */
983 /* XXX check ic_flags? */
984 if (ni->ni_rsn_ie != NULL) {
985 int ielen = ni->ni_rsn_ie[1] + 2;
986 if (ielen > sizeof(wpaie.wpa_ie))
987 ielen = sizeof(wpaie.wpa_ie);
988 memcpy(wpaie.wpa_ie, ni->ni_rsn_ie, ielen);
989 }
990 if (ireq->i_len > sizeof(struct ieee80211req_wpaie))
991 ireq->i_len = sizeof(struct ieee80211req_wpaie);
992 }
993 ieee80211_free_node(ni);
994 return copyout(&wpaie, ireq->i_data, ireq->i_len);
995 }
996
997 static int
998 ieee80211_ioctl_getstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
999 {
1000 struct ieee80211_node *ni;
1001 uint8_t macaddr[IEEE80211_ADDR_LEN];
1002 const int off = __offsetof(struct ieee80211req_sta_stats, is_stats);
1003 int error;
1004
1005 if (ireq->i_len < off)
1006 return EINVAL;
1007 error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
1008 if (error != 0)
1009 return error;
1010 ni = ieee80211_find_node(&ic->ic_sta, macaddr);
1011 if (ni == NULL)
1012 return EINVAL;
1013 if (ireq->i_len > sizeof(struct ieee80211req_sta_stats))
1014 ireq->i_len = sizeof(struct ieee80211req_sta_stats);
1015 /* NB: copy out only the statistics */
1016 error = copyout(&ni->ni_stats, (uint8_t *) ireq->i_data + off,
1017 ireq->i_len - off);
1018 ieee80211_free_node(ni);
1019 return error;
1020 }
1021
1022 static __inline uint8_t *
1023 copyie(uint8_t *cp, const uint8_t *ie)
1024 {
1025 if (ie != NULL) {
1026 memcpy(cp, ie, 2+ie[1]);
1027 cp += 2+ie[1];
1028 }
1029 return cp;
1030 }
1031
1032 #ifdef COMPAT_FREEBSD6
1033 #define IEEE80211_IOC_SCAN_RESULTS_OLD 24
1034
1035 struct scan_result_old {
1036 uint16_t isr_len; /* length (mult of 4) */
1037 uint16_t isr_freq; /* MHz */
1038 uint16_t isr_flags; /* channel flags */
1039 uint8_t isr_noise;
1040 uint8_t isr_rssi;
1041 uint8_t isr_intval; /* beacon interval */
1042 uint8_t isr_capinfo; /* capabilities */
1043 uint8_t isr_erp; /* ERP element */
1044 uint8_t isr_bssid[IEEE80211_ADDR_LEN];
1045 uint8_t isr_nrates;
1046 uint8_t isr_rates[IEEE80211_RATE_MAXSIZE];
1047 uint8_t isr_ssid_len; /* SSID length */
1048 uint8_t isr_ie_len; /* IE length */
1049 uint8_t isr_pad[5];
1050 /* variable length SSID followed by IE data */
1051 };
1052
1053 struct oscanreq {
1054 struct scan_result_old *sr;
1055 size_t space;
1056 };
1057
1058 static size_t
1059 old_scan_space(const struct ieee80211_scan_entry *se, int *ielen)
1060 {
1061 size_t len;
1062
1063 *ielen = 0;
1064 if (se->se_wpa_ie != NULL)
1065 *ielen += 2+se->se_wpa_ie[1];
1066 if (se->se_wme_ie != NULL)
1067 *ielen += 2+se->se_wme_ie[1];
1068 /*
1069 * NB: ie's can be no more than 255 bytes and the max 802.11
1070 * packet is <3Kbytes so we are sure this doesn't overflow
1071 * 16-bits; if this is a concern we can drop the ie's.
1072 */
1073 len = sizeof(struct scan_result_old) + se->se_ssid[1] + *ielen;
1074 return roundup(len, sizeof(uint32_t));
1075 }
1076
1077 static void
1078 old_get_scan_space(void *arg, const struct ieee80211_scan_entry *se)
1079 {
1080 struct oscanreq *req = arg;
1081 int ielen = 0;
1082
1083 req->space += old_scan_space(se, &ielen);
1084 }
1085
1086 static void
1087 old_get_scan_result(void *arg, const struct ieee80211_scan_entry *se)
1088 {
1089 struct oscanreq *req = arg;
1090 struct scan_result_old *sr;
1091 int ielen, len, nr, nxr;
1092 uint8_t *cp;
1093
1094 len = old_scan_space(se, &ielen);
1095 if (len > req->space)
1096 return;
1097
1098 sr = req->sr;
1099 memset(sr, 0, sizeof(*sr));
1100 sr->isr_ssid_len = se->se_ssid[1];
1101 /*
1102 * The value sr->isr_ie_len is defined as a uint8_t, so we
1103 * need to be careful to avoid an integer overflow. If the
1104 * value would overflow, we will set isr_ie_len to zero, and
1105 * ieee80211_ioctl_getscanresults (below) will avoid copying
1106 * the (overflowing) data.
1107 */
1108 if (ielen > 255)
1109 ielen = 0;
1110 sr->isr_ie_len = ielen;
1111 sr->isr_len = len;
1112 sr->isr_freq = se->se_chan->ic_freq;
1113 sr->isr_flags = se->se_chan->ic_flags;
1114 sr->isr_rssi = se->se_rssi;
1115 sr->isr_noise = se->se_noise;
1116 sr->isr_intval = se->se_intval;
1117 sr->isr_capinfo = se->se_capinfo;
1118 sr->isr_erp = se->se_erp;
1119 IEEE80211_ADDR_COPY(sr->isr_bssid, se->se_bssid);
1120 nr = min(se->se_rates[1], IEEE80211_RATE_MAXSIZE);
1121 memcpy(sr->isr_rates, se->se_rates+2, nr);
1122 nxr = min(se->se_xrates[1], IEEE80211_RATE_MAXSIZE - nr);
1123 memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
1124 sr->isr_nrates = nr + nxr;
1125
1126 cp = (uint8_t *)(sr+1);
1127 memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
1128 cp += sr->isr_ssid_len;
1129 if (sr->isr_ie_len) {
1130 cp = copyie(cp, se->se_wpa_ie);
1131 cp = copyie(cp, se->se_wme_ie);
1132 }
1133
1134 req->space -= len;
1135 req->sr = (struct scan_result_old *)(((uint8_t *)sr) + len);
1136 }
1137
1138 static int
1139 old_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq)
1140 {
1141 struct oscanreq req;
1142 int error;
1143
1144 if (ireq->i_len < sizeof(struct scan_result_old))
1145 return EFAULT;
1146
1147 error = 0;
1148 req.space = 0;
1149 ieee80211_scan_iterate(ic, old_get_scan_space, &req);
1150 if (req.space > ireq->i_len)
1151 req.space = ireq->i_len;
1152 if (req.space > 0) {
1153 size_t space;
1154 void *p;
1155
1156 space = req.space;
1157 /* XXX M_WAITOK after driver lock released */
1158 p = malloc(space, M_TEMP, M_NOWAIT | M_ZERO);
1159 if (p == NULL)
1160 return ENOMEM;
1161 req.sr = p;
1162 ieee80211_scan_iterate(ic, old_get_scan_result, &req);
1163 ireq->i_len = space - req.space;
1164 error = copyout(p, ireq->i_data, ireq->i_len);
1165 FREE(p, M_TEMP);
1166 } else
1167 ireq->i_len = 0;
1168
1169 return error;
1170 }
1171 #endif /* COMPAT_FREEBSD6 */
1172
1173 struct scanreq {
1174 struct ieee80211req_scan_result *sr;
1175 size_t space;
1176 };
1177
1178 static size_t
1179 scan_space(const struct ieee80211_scan_entry *se, int *ielen)
1180 {
1181 size_t len;
1182
1183 *ielen = 0;
1184 if (se->se_wpa_ie != NULL)
1185 *ielen += 2+se->se_wpa_ie[1];
1186 if (se->se_rsn_ie != NULL)
1187 *ielen += 2+se->se_rsn_ie[1];
1188 if (se->se_wme_ie != NULL)
1189 *ielen += 2+se->se_wme_ie[1];
1190 if (se->se_ath_ie != NULL)
1191 *ielen += 2+se->se_ath_ie[1];
1192 /*
1193 * NB: ie's can be no more than 255 bytes and the max 802.11
1194 * packet is <3Kbytes so we are sure this doesn't overflow
1195 * 16-bits; if this is a concern we can drop the ie's.
1196 */
1197 len = sizeof(struct ieee80211req_scan_result) + se->se_ssid[1] + *ielen;
1198 return roundup(len, sizeof(uint32_t));
1199 }
1200
1201 static void
1202 get_scan_space(void *arg, const struct ieee80211_scan_entry *se)
1203 {
1204 struct scanreq *req = arg;
1205 int ielen;
1206
1207 req->space += scan_space(se, &ielen);
1208 }
1209
1210 static void
1211 get_scan_result(void *arg, const struct ieee80211_scan_entry *se)
1212 {
1213 struct scanreq *req = arg;
1214 struct ieee80211req_scan_result *sr;
1215 int ielen, len, nr, nxr;
1216 uint8_t *cp;
1217
1218 len = scan_space(se, &ielen);
1219 if (len > req->space)
1220 return;
1221
1222 sr = req->sr;
1223 IASSERT(len <= 65535 && ielen <= 65535,
1224 ("len %u ssid %u ie %u", len, se->se_ssid[1], ielen));
1225 sr->isr_ie_off = sizeof(struct ieee80211req_scan_result);
1226 sr->isr_ie_len = ielen;
1227 sr->isr_len = len;
1228 sr->isr_freq = se->se_chan->ic_freq;
1229 sr->isr_flags = se->se_chan->ic_flags;
1230 sr->isr_rssi = se->se_rssi;
1231 sr->isr_noise = se->se_noise;
1232 sr->isr_intval = se->se_intval;
1233 sr->isr_capinfo = se->se_capinfo;
1234 sr->isr_erp = se->se_erp;
1235 IEEE80211_ADDR_COPY(sr->isr_bssid, se->se_bssid);
1236 nr = min(se->se_rates[1], IEEE80211_RATE_MAXSIZE);
1237 memcpy(sr->isr_rates, se->se_rates+2, nr);
1238 nxr = min(se->se_xrates[1], IEEE80211_RATE_MAXSIZE - nr);
1239 memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
1240 sr->isr_nrates = nr + nxr;
1241
1242 sr->isr_ssid_len = se->se_ssid[1];
1243 cp = ((uint8_t *)sr) + sr->isr_ie_off;
1244 memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
1245
1246 if (ielen) {
1247 cp += sr->isr_ssid_len;
1248 cp = copyie(cp, se->se_wpa_ie);
1249 cp = copyie(cp, se->se_rsn_ie);
1250 cp = copyie(cp, se->se_wme_ie);
1251 cp = copyie(cp, se->se_ath_ie);
1252 cp = copyie(cp, se->se_htcap_ie);
1253 }
1254
1255 req->space -= len;
1256 req->sr = (struct ieee80211req_scan_result *)(((uint8_t *)sr) + len);
1257 }
1258
1259 static int
1260 ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq)
1261 {
1262 struct scanreq req;
1263 int error;
1264
1265 if (ireq->i_len < sizeof(struct ieee80211req_scan_result))
1266 return EFAULT;
1267
1268 error = 0;
1269 req.space = 0;
1270 ieee80211_scan_iterate(ic, get_scan_space, &req);
1271 if (req.space > ireq->i_len)
1272 req.space = ireq->i_len;
1273 if (req.space > 0) {
1274 size_t space;
1275 void *p;
1276
1277 space = req.space;
1278 /* XXX M_WAITOK after driver lock released */
1279 p = malloc(space, M_TEMP, M_NOWAIT | M_ZERO);
1280 if (p == NULL)
1281 return ENOMEM;
1282 req.sr = p;
1283 ieee80211_scan_iterate(ic, get_scan_result, &req);
1284 ireq->i_len = space - req.space;
1285 error = copyout(p, ireq->i_data, ireq->i_len);
1286 FREE(p, M_TEMP);
1287 } else
1288 ireq->i_len = 0;
1289
1290 return error;
1291 }
1292
1293 struct stainforeq {
1294 struct ieee80211com *ic;
1295 struct ieee80211req_sta_info *si;
1296 size_t space;
1297 };
1298
1299 static size_t
1300 sta_space(const struct ieee80211_node *ni, size_t *ielen)
1301 {
1302 *ielen = 0;
1303 if (ni->ni_wpa_ie != NULL)
1304 *ielen += 2+ni->ni_wpa_ie[1];
1305 if (ni->ni_rsn_ie != NULL)
1306 *ielen += 2+ni->ni_rsn_ie[1];
1307 if (ni->ni_wme_ie != NULL)
1308 *ielen += 2+ni->ni_wme_ie[1];
1309 if (ni->ni_ath_ie != NULL)
1310 *ielen += 2+ni->ni_ath_ie[1];
1311 return roundup(sizeof(struct ieee80211req_sta_info) + *ielen,
1312 sizeof(uint32_t));
1313 }
1314
1315 static void
1316 get_sta_space(void *arg, struct ieee80211_node *ni)
1317 {
1318 struct stainforeq *req = arg;
1319 struct ieee80211com *ic = ni->ni_ic;
1320 size_t ielen;
1321
1322 if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1323 ni->ni_associd == 0) /* only associated stations */
1324 return;
1325 req->space += sta_space(ni, &ielen);
1326 }
1327
1328 static void
1329 get_sta_info(void *arg, struct ieee80211_node *ni)
1330 {
1331 struct stainforeq *req = arg;
1332 struct ieee80211com *ic = ni->ni_ic;
1333 struct ieee80211req_sta_info *si;
1334 size_t ielen, len;
1335 uint8_t *cp;
1336
1337 if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1338 ni->ni_associd == 0) /* only associated stations */
1339 return;
1340 if (ni->ni_chan == IEEE80211_CHAN_ANYC) /* XXX bogus entry */
1341 return;
1342 len = sta_space(ni, &ielen);
1343 if (len > req->space)
1344 return;
1345 si = req->si;
1346 si->isi_len = len;
1347 si->isi_ie_off = sizeof(struct ieee80211req_sta_info);
1348 si->isi_ie_len = ielen;
1349 si->isi_freq = ni->ni_chan->ic_freq;
1350 si->isi_flags = ni->ni_chan->ic_flags;
1351 si->isi_state = ni->ni_flags;
1352 si->isi_authmode = ni->ni_authmode;
1353 ic->ic_node_getsignal(ni, &si->isi_rssi, &si->isi_noise);
1354 si->isi_noise = 0; /* XXX */
1355 si->isi_capinfo = ni->ni_capinfo;
1356 si->isi_erp = ni->ni_erp;
1357 IEEE80211_ADDR_COPY(si->isi_macaddr, ni->ni_macaddr);
1358 si->isi_nrates = ni->ni_rates.rs_nrates;
1359 if (si->isi_nrates > 15)
1360 si->isi_nrates = 15;
1361 memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates);
1362 si->isi_txrate = ni->ni_txrate;
1363 si->isi_ie_len = ielen;
1364 si->isi_associd = ni->ni_associd;
1365 si->isi_txpower = ni->ni_txpower;
1366 si->isi_vlan = ni->ni_vlan;
1367 if (ni->ni_flags & IEEE80211_NODE_QOS) {
1368 memcpy(si->isi_txseqs, ni->ni_txseqs, sizeof(ni->ni_txseqs));
1369 memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs));
1370 } else {
1371 si->isi_txseqs[0] = ni->ni_txseqs[IEEE80211_NONQOS_TID];
1372 si->isi_rxseqs[0] = ni->ni_rxseqs[IEEE80211_NONQOS_TID];
1373 }
1374 /* NB: leave all cases in case we relax ni_associd == 0 check */
1375 if (ieee80211_node_is_authorized(ni))
1376 si->isi_inact = ic->ic_inact_run;
1377 else if (ni->ni_associd != 0)
1378 si->isi_inact = ic->ic_inact_auth;
1379 else
1380 si->isi_inact = ic->ic_inact_init;
1381 si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
1382
1383 if (ielen) {
1384 cp = ((uint8_t *)si) + si->isi_ie_off;
1385 cp = copyie(cp, ni->ni_wpa_ie);
1386 cp = copyie(cp, ni->ni_rsn_ie);
1387 cp = copyie(cp, ni->ni_wme_ie);
1388 cp = copyie(cp, ni->ni_ath_ie);
1389 }
1390
1391 req->si = (struct ieee80211req_sta_info *)(((uint8_t *)si) + len);
1392 req->space -= len;
1393 }
1394
1395 static int
1396 getstainfo_common(struct ieee80211com *ic, struct ieee80211req *ireq,
1397 struct ieee80211_node *ni, int off)
1398 {
1399 struct stainforeq req;
1400 size_t space;
1401 void *p;
1402 int error;
1403
1404 error = 0;
1405 req.space = 0;
1406 if (ni == NULL)
1407 ieee80211_iterate_nodes(&ic->ic_sta, get_sta_space, &req);
1408 else
1409 get_sta_space(&req, ni);
1410 if (req.space > ireq->i_len)
1411 req.space = ireq->i_len;
1412 if (req.space > 0) {
1413 space = req.space;
1414 /* XXX M_WAITOK after driver lock released */
1415 p = malloc(space, M_TEMP, M_NOWAIT);
1416 if (p == NULL) {
1417 error = ENOMEM;
1418 goto bad;
1419 }
1420 req.si = p;
1421 if (ni == NULL)
1422 ieee80211_iterate_nodes(&ic->ic_sta, get_sta_info, &req);
1423 else
1424 get_sta_info(&req, ni);
1425 ireq->i_len = space - req.space;
1426 error = copyout(p, (uint8_t *) ireq->i_data+off, ireq->i_len);
1427 FREE(p, M_TEMP);
1428 } else
1429 ireq->i_len = 0;
1430 bad:
1431 if (ni != NULL)
1432 ieee80211_free_node(ni);
1433 return error;
1434 }
1435
1436 static int
1437 ieee80211_ioctl_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
1438 {
1439 uint8_t macaddr[IEEE80211_ADDR_LEN];
1440 const int off = __offsetof(struct ieee80211req_sta_req, info);
1441 struct ieee80211_node *ni;
1442 int error;
1443
1444 if (ireq->i_len < sizeof(struct ieee80211req_sta_req))
1445 return EFAULT;
1446 error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
1447 if (error != 0)
1448 return error;
1449 if (IEEE80211_ADDR_EQ(macaddr, ic->ic_ifp->if_broadcastaddr)) {
1450 ni = NULL;
1451 } else {
1452 ni = ieee80211_find_node(&ic->ic_sta, macaddr);
1453 if (ni == NULL)
1454 return EINVAL;
1455 }
1456 return getstainfo_common(ic, ireq, ni, off);
1457 }
1458
1459 #ifdef COMPAT_FREEBSD6
1460 #define IEEE80211_IOC_STA_INFO_OLD 45
1461
1462 static int
1463 old_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
1464 {
1465 if (ireq->i_len < sizeof(struct ieee80211req_sta_info))
1466 return EFAULT;
1467 return getstainfo_common(ic, ireq, NULL, 0);
1468 }
1469 #endif /* COMPAT_FREEBSD6 */
1470
1471 static int
1472 ieee80211_ioctl_getstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
1473 {
1474 struct ieee80211_node *ni;
1475 struct ieee80211req_sta_txpow txpow;
1476 int error;
1477
1478 if (ireq->i_len != sizeof(txpow))
1479 return EINVAL;
1480 error = copyin(ireq->i_data, &txpow, sizeof(txpow));
1481 if (error != 0)
1482 return error;
1483 ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
1484 if (ni == NULL)
1485 return EINVAL; /* XXX */
1486 txpow.it_txpow = ni->ni_txpower;
1487 error = copyout(&txpow, ireq->i_data, sizeof(txpow));
1488 ieee80211_free_node(ni);
1489 return error;
1490 }
1491
1492 static int
1493 ieee80211_ioctl_getwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
1494 {
1495 struct ieee80211_wme_state *wme = &ic->ic_wme;
1496 struct wmeParams *wmep;
1497 int ac;
1498
1499 if ((ic->ic_caps & IEEE80211_C_WME) == 0)
1500 return EINVAL;
1501
1502 ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
1503 if (ac >= WME_NUM_AC)
1504 ac = WME_AC_BE;
1505 if (ireq->i_len & IEEE80211_WMEPARAM_BSS)
1506 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1507 else
1508 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1509 switch (ireq->i_type) {
1510 case IEEE80211_IOC_WME_CWMIN: /* WME: CWmin */
1511 ireq->i_val = wmep->wmep_logcwmin;
1512 break;
1513 case IEEE80211_IOC_WME_CWMAX: /* WME: CWmax */
1514 ireq->i_val = wmep->wmep_logcwmax;
1515 break;
1516 case IEEE80211_IOC_WME_AIFS: /* WME: AIFS */
1517 ireq->i_val = wmep->wmep_aifsn;
1518 break;
1519 case IEEE80211_IOC_WME_TXOPLIMIT: /* WME: txops limit */
1520 ireq->i_val = wmep->wmep_txopLimit;
1521 break;
1522 case IEEE80211_IOC_WME_ACM: /* WME: ACM (bss only) */
1523 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1524 ireq->i_val = wmep->wmep_acm;
1525 break;
1526 case IEEE80211_IOC_WME_ACKPOLICY: /* WME: ACK policy (!bss only)*/
1527 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1528 ireq->i_val = !wmep->wmep_noackPolicy;
1529 break;
1530 }
1531 return 0;
1532 }
1533
1534 static int
1535 ieee80211_ioctl_getmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
1536 {
1537 const struct ieee80211_aclator *acl = ic->ic_acl;
1538
1539 return (acl == NULL ? EINVAL : acl->iac_getioctl(ic, ireq));
1540 }
1541
1542 /*
1543 * Return the current ``state'' of an Atheros capbility.
1544 * If associated in station mode report the negotiated
1545 * setting. Otherwise report the current setting.
1546 */
1547 static int
1548 getathcap(struct ieee80211com *ic, int cap)
1549 {
1550 if (ic->ic_opmode == IEEE80211_M_STA && ic->ic_state == IEEE80211_S_RUN)
1551 return IEEE80211_ATH_CAP(ic, ic->ic_bss, cap) != 0;
1552 else
1553 return (ic->ic_flags & cap) != 0;
1554 }
1555
1556 static int
1557 ieee80211_ioctl_getcurchan(struct ieee80211com *ic, struct ieee80211req *ireq)
1558 {
1559 if (ireq->i_len != sizeof(struct ieee80211_channel))
1560 return EINVAL;
1561 return copyout(ic->ic_curchan, ireq->i_data, sizeof(*ic->ic_curchan));
1562 }
1563
1564 #if defined(COMPAT_FREEBSD_NET80211)
1565 static int
1566 ieee80211_ioctl_get80211_fbsd(struct ieee80211com *ic, u_long cmd,
1567 struct ieee80211req *ireq)
1568 {
1569 const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
1570 int error = 0;
1571 u_int kid, len, m;
1572 uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
1573 char tmpssid[IEEE80211_NWID_LEN];
1574 struct ifnet *ifp = ic->ic_ifp;
1575
1576 int error = 0;
1577
1578 switch (ireq->i_type) {
1579 case IEEE80211_IOC_SSID:
1580 switch (ic->ic_state) {
1581 case IEEE80211_S_INIT:
1582 case IEEE80211_S_SCAN:
1583 ireq->i_len = ic->ic_des_ssid[0].len;
1584 memcpy(tmpssid, ic->ic_des_ssid[0].ssid, ireq->i_len);
1585 break;
1586 default:
1587 ireq->i_len = ic->ic_bss->ni_esslen;
1588 memcpy(tmpssid, ic->ic_bss->ni_essid,
1589 ireq->i_len);
1590 break;
1591 }
1592 error = copyout(tmpssid, ireq->i_data, ireq->i_len);
1593 break;
1594 case IEEE80211_IOC_NUMSSIDS:
1595 ireq->i_val = 1;
1596 break;
1597 case IEEE80211_IOC_WEP:
1598 if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0)
1599 ireq->i_val = IEEE80211_WEP_OFF;
1600 else if (ic->ic_flags & IEEE80211_F_DROPUNENC)
1601 ireq->i_val = IEEE80211_WEP_ON;
1602 else
1603 ireq->i_val = IEEE80211_WEP_MIXED;
1604 break;
1605 case IEEE80211_IOC_WEPKEY:
1606 kid = (u_int) ireq->i_val;
1607 if (kid >= IEEE80211_WEP_NKID)
1608 return EINVAL;
1609 len = (u_int) ic->ic_nw_keys[kid].wk_keylen;
1610 /* NB: only root can read WEP keys */
1611 if (kauth_authorize_network(curlwp->l_cred,
1612 KAUTH_NETWORK_INTERFACE,
1613 KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp, NULL,
1614 NULL) == 0) {
1615 bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
1616 } else {
1617 bzero(tmpkey, len);
1618 }
1619 ireq->i_len = len;
1620 error = copyout(tmpkey, ireq->i_data, len);
1621 break;
1622 case IEEE80211_IOC_NUMWEPKEYS:
1623 ireq->i_val = IEEE80211_WEP_NKID;
1624 break;
1625 case IEEE80211_IOC_WEPTXKEY:
1626 ireq->i_val = ic->ic_def_txkey;
1627 break;
1628 case IEEE80211_IOC_CHANNEL:
1629 ireq->i_val = ieee80211_chan2ieee(ic, ic->ic_curchan);
1630 break;
1631 case IEEE80211_IOC_POWERSAVE:
1632 if (ic->ic_flags & IEEE80211_F_PMGTON)
1633 ireq->i_val = IEEE80211_POWERSAVE_ON;
1634 else
1635 ireq->i_val = IEEE80211_POWERSAVE_OFF;
1636 break;
1637 case IEEE80211_IOC_POWERSAVESLEEP:
1638 ireq->i_val = ic->ic_lintval;
1639 break;
1640 case IEEE80211_IOC_BSSID:
1641 if (ireq->i_len != IEEE80211_ADDR_LEN)
1642 return EINVAL;
1643 error = copyout(ic->ic_state == IEEE80211_S_RUN ?
1644 ic->ic_bss->ni_bssid :
1645 ic->ic_des_bssid,
1646 ireq->i_data, ireq->i_len);
1647 break;
1648 default:
1649 error = EINVAL;
1650 break;
1651 }
1652 return error;
1653 }
1654 #endif /* COMPAT_FREEBSD_NET80211 */
1655
1656 /*
1657 * When building the kernel with -O2 on the i386 architecture, gcc
1658 * seems to want to inline this function into ieee80211_ioctl()
1659 * (which is the only routine that calls it). When this happens,
1660 * ieee80211_ioctl() ends up consuming an additional 2K of stack
1661 * space. (Exactly why it needs so much is unclear.) The problem
1662 * is that it's possible for ieee80211_ioctl() to invoke other
1663 * routines (including driver init functions) which could then find
1664 * themselves perilously close to exhausting the stack.
1665 *
1666 * To avoid this, we deliberately prevent gcc from inlining this
1667 * routine. Another way to avoid this is to use less agressive
1668 * optimization when compiling this file (i.e. -O instead of -O2)
1669 * but special-casing the compilation of this one module in the
1670 * build system would be awkward.
1671 */
1672 #ifdef __GNUC__
1673 __attribute__ ((__noinline__))
1674 #endif
1675 static int
1676 ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd,
1677 struct ieee80211req *ireq)
1678 {
1679 const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
1680 int error = 0;
1681 u_int m;
1682
1683 switch (ireq->i_type) {
1684 case IEEE80211_IOC_AUTHMODE:
1685 if (ic->ic_flags & IEEE80211_F_WPA)
1686 ireq->i_val = IEEE80211_AUTH_WPA;
1687 else
1688 ireq->i_val = ic->ic_bss->ni_authmode;
1689 break;
1690 case IEEE80211_IOC_RTSTHRESHOLD:
1691 ireq->i_val = ic->ic_rtsthreshold;
1692 break;
1693 case IEEE80211_IOC_PROTMODE:
1694 ireq->i_val = ic->ic_protmode;
1695 break;
1696 case IEEE80211_IOC_TXPOWER:
1697 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
1698 return EINVAL;
1699 ireq->i_val = ic->ic_txpowlimit;
1700 break;
1701 case IEEE80211_IOC_MCASTCIPHER:
1702 ireq->i_val = rsn->rsn_mcastcipher;
1703 break;
1704 case IEEE80211_IOC_MCASTKEYLEN:
1705 ireq->i_val = rsn->rsn_mcastkeylen;
1706 break;
1707 case IEEE80211_IOC_UCASTCIPHERS:
1708 ireq->i_val = 0;
1709 for (m = 0x1; m != 0; m <<= 1)
1710 if (rsn->rsn_ucastcipherset & m)
1711 ireq->i_val |= 1<<cap2cipher(m);
1712 break;
1713 case IEEE80211_IOC_UCASTCIPHER:
1714 ireq->i_val = rsn->rsn_ucastcipher;
1715 break;
1716 case IEEE80211_IOC_UCASTKEYLEN:
1717 ireq->i_val = rsn->rsn_ucastkeylen;
1718 break;
1719 case IEEE80211_IOC_KEYMGTALGS:
1720 ireq->i_val = rsn->rsn_keymgmtset;
1721 break;
1722 case IEEE80211_IOC_RSNCAPS:
1723 ireq->i_val = rsn->rsn_caps;
1724 break;
1725 case IEEE80211_IOC_WPA:
1726 switch (ic->ic_flags & IEEE80211_F_WPA) {
1727 case IEEE80211_F_WPA1:
1728 ireq->i_val = 1;
1729 break;
1730 case IEEE80211_F_WPA2:
1731 ireq->i_val = 2;
1732 break;
1733 case IEEE80211_F_WPA1 | IEEE80211_F_WPA2:
1734 ireq->i_val = 3;
1735 break;
1736 default:
1737 ireq->i_val = 0;
1738 break;
1739 }
1740 break;
1741 case IEEE80211_IOC_CHANLIST:
1742 error = ieee80211_ioctl_getchanlist(ic, ireq);
1743 break;
1744 case IEEE80211_IOC_ROAMING:
1745 ireq->i_val = ic->ic_roaming;
1746 break;
1747 case IEEE80211_IOC_PRIVACY:
1748 ireq->i_val = (ic->ic_flags & IEEE80211_F_PRIVACY) != 0;
1749 break;
1750 case IEEE80211_IOC_DROPUNENCRYPTED:
1751 ireq->i_val = (ic->ic_flags & IEEE80211_F_DROPUNENC) != 0;
1752 break;
1753 case IEEE80211_IOC_COUNTERMEASURES:
1754 ireq->i_val = (ic->ic_flags & IEEE80211_F_COUNTERM) != 0;
1755 break;
1756 case IEEE80211_IOC_DRIVER_CAPS:
1757 ireq->i_val = ic->ic_caps>>16;
1758 ireq->i_len = ic->ic_caps&0xffff;
1759 break;
1760 case IEEE80211_IOC_WME:
1761 ireq->i_val = (ic->ic_flags & IEEE80211_F_WME) != 0;
1762 break;
1763 case IEEE80211_IOC_HIDESSID:
1764 ireq->i_val = (ic->ic_flags & IEEE80211_F_HIDESSID) != 0;
1765 break;
1766 case IEEE80211_IOC_APBRIDGE:
1767 ireq->i_val = (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0;
1768 break;
1769 case IEEE80211_IOC_OPTIE:
1770 if (ic->ic_opt_ie == NULL)
1771 return EINVAL;
1772 /* NB: truncate, caller can check length */
1773 if (ireq->i_len > ic->ic_opt_ie_len)
1774 ireq->i_len = ic->ic_opt_ie_len;
1775 error = copyout(ic->ic_opt_ie, ireq->i_data, ireq->i_len);
1776 break;
1777 case IEEE80211_IOC_WPAKEY:
1778 error = ieee80211_ioctl_getkey(ic, ireq);
1779 break;
1780 case IEEE80211_IOC_CHANINFO:
1781 error = ieee80211_ioctl_getchaninfo(ic, ireq);
1782 break;
1783 case IEEE80211_IOC_WPAIE:
1784 error = ieee80211_ioctl_getwpaie(ic, ireq, ireq->i_type);
1785 break;
1786 case IEEE80211_IOC_WPAIE2:
1787 error = ieee80211_ioctl_getwpaie(ic, ireq, ireq->i_type);
1788 break;
1789 #ifdef COMPAT_FREEBSD6
1790 case IEEE80211_IOC_SCAN_RESULTS_OLD:
1791 error = old_getscanresults(ic, ireq);
1792 break;
1793 #endif
1794 case IEEE80211_IOC_SCAN_RESULTS:
1795 error = ieee80211_ioctl_getscanresults(ic, ireq);
1796 break;
1797 case IEEE80211_IOC_STA_STATS:
1798 error = ieee80211_ioctl_getstastats(ic, ireq);
1799 break;
1800 case IEEE80211_IOC_TXPOWMAX:
1801 ireq->i_val = ic->ic_bss->ni_txpower;
1802 break;
1803 case IEEE80211_IOC_STA_TXPOW:
1804 error = ieee80211_ioctl_getstatxpow(ic, ireq);
1805 break;
1806 #ifdef COMPAT_FREEBSD6
1807 case IEEE80211_IOC_STA_INFO_OLD:
1808 error = old_getstainfo(ic, ireq);
1809 break;
1810 #endif
1811 case IEEE80211_IOC_STA_INFO:
1812 error = ieee80211_ioctl_getstainfo(ic, ireq);
1813 break;
1814 case IEEE80211_IOC_WME_CWMIN: /* WME: CWmin */
1815 case IEEE80211_IOC_WME_CWMAX: /* WME: CWmax */
1816 case IEEE80211_IOC_WME_AIFS: /* WME: AIFS */
1817 case IEEE80211_IOC_WME_TXOPLIMIT: /* WME: txops limit */
1818 case IEEE80211_IOC_WME_ACM: /* WME: ACM (bss only) */
1819 case IEEE80211_IOC_WME_ACKPOLICY: /* WME: ACK policy (bss only) */
1820 error = ieee80211_ioctl_getwmeparam(ic, ireq);
1821 break;
1822 case IEEE80211_IOC_DTIM_PERIOD:
1823 ireq->i_val = ic->ic_dtim_period;
1824 break;
1825 case IEEE80211_IOC_BEACON_INTERVAL:
1826 /* NB: get from ic_bss for station mode */
1827 ireq->i_val = ic->ic_bss->ni_intval;
1828 break;
1829 case IEEE80211_IOC_PUREG:
1830 ireq->i_val = (ic->ic_flags & IEEE80211_F_PUREG) != 0;
1831 break;
1832 case IEEE80211_IOC_FF:
1833 ireq->i_val = getathcap(ic, IEEE80211_F_FF);
1834 break;
1835 case IEEE80211_IOC_TURBOP:
1836 ireq->i_val = getathcap(ic, IEEE80211_F_TURBOP);
1837 break;
1838 case IEEE80211_IOC_BGSCAN:
1839 ireq->i_val = (ic->ic_flags & IEEE80211_F_BGSCAN) != 0;
1840 break;
1841 case IEEE80211_IOC_BGSCAN_IDLE:
1842 ireq->i_val = ic->ic_bgscanidle*hz/1000; /* ms */
1843 break;
1844 case IEEE80211_IOC_BGSCAN_INTERVAL:
1845 ireq->i_val = ic->ic_bgscanintvl/hz; /* seconds */
1846 break;
1847 case IEEE80211_IOC_SCANVALID:
1848 ireq->i_val = ic->ic_scanvalid/hz; /* seconds */
1849 break;
1850 case IEEE80211_IOC_ROAM_RSSI_11A:
1851 ireq->i_val = ic->ic_roam.rssi11a;
1852 break;
1853 case IEEE80211_IOC_ROAM_RSSI_11B:
1854 ireq->i_val = ic->ic_roam.rssi11bOnly;
1855 break;
1856 case IEEE80211_IOC_ROAM_RSSI_11G:
1857 ireq->i_val = ic->ic_roam.rssi11b;
1858 break;
1859 case IEEE80211_IOC_ROAM_RATE_11A:
1860 ireq->i_val = ic->ic_roam.rate11a;
1861 break;
1862 case IEEE80211_IOC_ROAM_RATE_11B:
1863 ireq->i_val = ic->ic_roam.rate11bOnly;
1864 break;
1865 case IEEE80211_IOC_ROAM_RATE_11G:
1866 ireq->i_val = ic->ic_roam.rate11b;
1867 break;
1868 case IEEE80211_IOC_MCAST_RATE:
1869 ireq->i_val = ic->ic_mcast_rate;
1870 break;
1871 case IEEE80211_IOC_FRAGTHRESHOLD:
1872 ireq->i_val = ic->ic_fragthreshold;
1873 break;
1874 case IEEE80211_IOC_MACCMD:
1875 error = ieee80211_ioctl_getmaccmd(ic, ireq);
1876 break;
1877 case IEEE80211_IOC_BURST:
1878 ireq->i_val = (ic->ic_flags & IEEE80211_F_BURST) != 0;
1879 break;
1880 case IEEE80211_IOC_BMISSTHRESHOLD:
1881 ireq->i_val = ic->ic_bmissthreshold;
1882 break;
1883 case IEEE80211_IOC_CURCHAN:
1884 error = ieee80211_ioctl_getcurchan(ic, ireq);
1885 break;
1886 case IEEE80211_IOC_SHORTGI:
1887 ireq->i_val = 0;
1888 if (ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI20)
1889 ireq->i_val |= IEEE80211_HTCAP_SHORTGI20;
1890 if (ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI40)
1891 ireq->i_val |= IEEE80211_HTCAP_SHORTGI40;
1892 break;
1893 case IEEE80211_IOC_AMPDU:
1894 ireq->i_val = 0;
1895 if (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_TX)
1896 ireq->i_val |= 1;
1897 if (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_RX)
1898 ireq->i_val |= 2;
1899 break;
1900 case IEEE80211_IOC_AMPDU_LIMIT:
1901 ireq->i_val = ic->ic_ampdu_limit; /* XXX truncation? */
1902 break;
1903 case IEEE80211_IOC_AMPDU_DENSITY:
1904 ireq->i_val = ic->ic_ampdu_density;
1905 break;
1906 case IEEE80211_IOC_AMSDU:
1907 ireq->i_val = 0;
1908 if (ic->ic_flags_ext & IEEE80211_FEXT_AMSDU_TX)
1909 ireq->i_val |= 1;
1910 if (ic->ic_flags_ext & IEEE80211_FEXT_AMSDU_RX)
1911 ireq->i_val |= 2;
1912 break;
1913 case IEEE80211_IOC_AMSDU_LIMIT:
1914 ireq->i_val = ic->ic_amsdu_limit; /* XXX truncation? */
1915 break;
1916 case IEEE80211_IOC_PUREN:
1917 ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_PUREN) != 0;
1918 break;
1919 case IEEE80211_IOC_DOTH:
1920 ireq->i_val = (ic->ic_flags & IEEE80211_F_DOTH) != 0;
1921 break;
1922 case IEEE80211_IOC_HTCOMPAT:
1923 ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) != 0;
1924 break;
1925 case IEEE80211_IOC_INACTIVITY:
1926 ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_INACT) != 0;
1927 break;
1928 case IEEE80211_IOC_HTPROTMODE:
1929 ireq->i_val = ic->ic_htprotmode;
1930 break;
1931 case IEEE80211_IOC_HTCONF:
1932 if (ic->ic_flags_ext & IEEE80211_FEXT_HT) {
1933 ireq->i_val = 1;
1934 if (ic->ic_flags_ext & IEEE80211_FEXT_USEHT40)
1935 ireq->i_val |= 2;
1936 } else
1937 ireq->i_val = 0;
1938 break;
1939 default:
1940 #if defined(COMPAT_FREEBSD_NET80211)
1941 error = ieee80211_ioctl_get80211_fbsd(ic, cmd, ireq);
1942 #else
1943 error = EINVAL;
1944 #endif /* COMPAT_FREEBSD_NET80211 */
1945 break;
1946 }
1947 return error;
1948 }
1949
1950 static int
1951 ieee80211_ioctl_setoptie(struct ieee80211com *ic, struct ieee80211req *ireq)
1952 {
1953 int error;
1954 void *ie, *oie;
1955
1956 /*
1957 * NB: Doing this for ap operation could be useful (e.g. for
1958 * WPA and/or WME) except that it typically is worthless
1959 * without being able to intervene when processing
1960 * association response frames--so disallow it for now.
1961 */
1962 if (ic->ic_opmode != IEEE80211_M_STA)
1963 return EINVAL;
1964 if (ireq->i_len > IEEE80211_MAX_OPT_IE)
1965 return EINVAL;
1966 /* NB: data.length is validated by the wireless extensions code */
1967 /* XXX M_WAITOK after driver lock released */
1968 if (ireq->i_len > 0) {
1969 ie = malloc(ireq->i_len, M_DEVBUF, M_WAITOK);
1970 if (ie == NULL)
1971 return ENOMEM;
1972 error = copyin(ireq->i_data, ie, ireq->i_len);
1973 if (error) {
1974 free(ie, M_DEVBUF);
1975 return error;
1976 }
1977 } else {
1978 ie = NULL;
1979 ireq->i_len = 0;
1980 }
1981 /* XXX sanity check data? */
1982 oie = ic->ic_opt_ie;
1983 ic->ic_opt_ie = ie;
1984 ic->ic_opt_ie_len = ireq->i_len;
1985 if (oie != NULL)
1986 FREE(oie, M_DEVBUF);
1987 return 0;
1988 }
1989
1990 static int
1991 ieee80211_ioctl_setkey(struct ieee80211com *ic, struct ieee80211req *ireq)
1992 {
1993 struct ieee80211req_key ik;
1994 struct ieee80211_node *ni;
1995 struct ieee80211_key *wk;
1996 uint16_t kid;
1997 int error;
1998
1999 if (ireq->i_len != sizeof(ik))
2000 return EINVAL;
2001 error = copyin(ireq->i_data, &ik, sizeof(ik));
2002 if (error)
2003 return error;
2004 /* NB: cipher support is verified by ieee80211_crypt_newkey */
2005 /* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */
2006 if (ik.ik_keylen > sizeof(ik.ik_keydata))
2007 return E2BIG;
2008 kid = ik.ik_keyix;
2009 if (kid == IEEE80211_KEYIX_NONE) {
2010 /* XXX unicast keys currently must be tx/rx */
2011 if (ik.ik_flags != (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))
2012 return EINVAL;
2013 if (ic->ic_opmode == IEEE80211_M_STA) {
2014 ni = ieee80211_ref_node(ic->ic_bss);
2015 if (!IEEE80211_ADDR_EQ(ik.ik_macaddr, ni->ni_bssid)) {
2016 ieee80211_free_node(ni);
2017 return EADDRNOTAVAIL;
2018 }
2019 } else {
2020 ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
2021 if (ni == NULL)
2022 return ENOENT;
2023 }
2024 wk = &ni->ni_ucastkey;
2025 } else {
2026 if (kid >= IEEE80211_WEP_NKID)
2027 return EINVAL;
2028 wk = &ic->ic_nw_keys[kid];
2029 /*
2030 * Global slots start off w/o any assigned key index.
2031 * Force one here for consistency with IEEE80211_IOC_WEPKEY.
2032 */
2033 if (wk->wk_keyix == IEEE80211_KEYIX_NONE)
2034 wk->wk_keyix = kid;
2035 ni = NULL;
2036 }
2037 error = 0;
2038 ieee80211_key_update_begin(ic);
2039 if (ieee80211_crypto_newkey(ic, ik.ik_type, ik.ik_flags, wk)) {
2040 wk->wk_keylen = ik.ik_keylen;
2041 /* NB: MIC presence is implied by cipher type */
2042 if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
2043 wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
2044 wk->wk_keyrsc = ik.ik_keyrsc;
2045 wk->wk_keytsc = 0; /* new key, reset */
2046 memset(wk->wk_key, 0, sizeof(wk->wk_key));
2047 memcpy(wk->wk_key, ik.ik_keydata, ik.ik_keylen);
2048 if (!ieee80211_crypto_setkey(ic, wk,
2049 ni != NULL ? ni->ni_macaddr : ik.ik_macaddr))
2050 error = EIO;
2051 else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT))
2052 ic->ic_def_txkey = kid;
2053 } else
2054 error = ENXIO;
2055 ieee80211_key_update_end(ic);
2056 if (ni != NULL)
2057 ieee80211_free_node(ni);
2058 return error;
2059 }
2060
2061 static int
2062 ieee80211_ioctl_delkey(struct ieee80211com *ic, struct ieee80211req *ireq)
2063 {
2064 struct ieee80211req_del_key dk;
2065 int kid, error;
2066
2067 if (ireq->i_len != sizeof(dk))
2068 return EINVAL;
2069 error = copyin(ireq->i_data, &dk, sizeof(dk));
2070 if (error)
2071 return error;
2072 kid = dk.idk_keyix;
2073 /* XXX uint8_t -> uint16_t */
2074 if (dk.idk_keyix == (uint8_t) IEEE80211_KEYIX_NONE) {
2075 struct ieee80211_node *ni;
2076
2077 if (ic->ic_opmode == IEEE80211_M_STA) {
2078 ni = ieee80211_ref_node(ic->ic_bss);
2079 if (!IEEE80211_ADDR_EQ(dk.idk_macaddr, ni->ni_bssid)) {
2080 ieee80211_free_node(ni);
2081 return EADDRNOTAVAIL;
2082 }
2083 } else {
2084 ni = ieee80211_find_node(&ic->ic_sta, dk.idk_macaddr);
2085 if (ni == NULL)
2086 return ENOENT;
2087 }
2088 /* XXX error return */
2089 ieee80211_node_delucastkey(ni);
2090 ieee80211_free_node(ni);
2091 } else {
2092 if (kid >= IEEE80211_WEP_NKID)
2093 return EINVAL;
2094 /* XXX error return */
2095 ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[kid]);
2096 }
2097 return 0;
2098 }
2099
2100 #ifndef IEEE80211_NO_HOSTAP
2101 static void
2102 domlme(void *arg, struct ieee80211_node *ni)
2103 {
2104 struct ieee80211com *ic = ni->ni_ic;
2105 struct ieee80211req_mlme *mlme = arg;
2106
2107 if (ni->ni_associd != 0) {
2108 IEEE80211_SEND_MGMT(ic, ni,
2109 mlme->im_op == IEEE80211_MLME_DEAUTH ?
2110 IEEE80211_FC0_SUBTYPE_DEAUTH :
2111 IEEE80211_FC0_SUBTYPE_DISASSOC,
2112 mlme->im_reason);
2113 }
2114 ieee80211_node_leave(ic, ni);
2115 }
2116 #endif /* !IEEE80211_NO_HOSTAP */
2117
2118 struct scanlookup {
2119 const uint8_t *mac;
2120 int esslen;
2121 const uint8_t *essid;
2122 const struct ieee80211_scan_entry *se;
2123 };
2124
2125 /*
2126 * Match mac address and any ssid.
2127 */
2128 static void
2129 mlmelookup(void *arg, const struct ieee80211_scan_entry *se)
2130 {
2131 struct scanlookup *look = arg;
2132
2133 if (!IEEE80211_ADDR_EQ(look->mac, se->se_macaddr))
2134 return;
2135 if (look->esslen != 0) {
2136 if (se->se_ssid[1] != look->esslen)
2137 return;
2138 if (memcmp(look->essid, se->se_ssid+2, look->esslen))
2139 return;
2140 }
2141 look->se = se;
2142 }
2143
2144 static int
2145 ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq)
2146 {
2147 struct ieee80211req_mlme mlme;
2148 struct ieee80211_node *ni;
2149 int error;
2150
2151 if (ireq->i_len != sizeof(mlme))
2152 return EINVAL;
2153 error = copyin(ireq->i_data, &mlme, sizeof(mlme));
2154 if (error)
2155 return error;
2156 switch (mlme.im_op) {
2157 case IEEE80211_MLME_ASSOC:
2158 /* XXX ibss/ahdemo */
2159 if (ic->ic_opmode == IEEE80211_M_STA) {
2160 struct scanlookup lookup;
2161
2162 lookup.se = NULL;
2163 lookup.mac = mlme.im_macaddr;
2164 /* XXX use revised api w/ explicit ssid */
2165 lookup.esslen = ic->ic_des_ssid[0].len;
2166 lookup.essid = ic->ic_des_ssid[0].ssid;
2167 ieee80211_scan_iterate(ic, mlmelookup, &lookup);
2168 if (lookup.se != NULL &&
2169 ieee80211_sta_join(ic, lookup.se))
2170 return 0;
2171 }
2172 return EINVAL;
2173 case IEEE80211_MLME_DISASSOC:
2174 case IEEE80211_MLME_DEAUTH:
2175 switch (ic->ic_opmode) {
2176 case IEEE80211_M_STA:
2177 /* XXX not quite right */
2178 ieee80211_new_state(ic, IEEE80211_S_INIT,
2179 mlme.im_reason);
2180 break;
2181 case IEEE80211_M_HOSTAP:
2182 #ifndef IEEE80211_NO_HOSTAP
2183 /* NB: the broadcast address means do 'em all */
2184 if (!IEEE80211_ADDR_EQ(mlme.im_macaddr, ic->ic_ifp->if_broadcastaddr)) {
2185 if ((ni = ieee80211_find_node(&ic->ic_sta,
2186 mlme.im_macaddr)) == NULL)
2187 return EINVAL;
2188 domlme(&mlme, ni);
2189 ieee80211_free_node(ni);
2190 } else {
2191 ieee80211_iterate_nodes(&ic->ic_sta,
2192 domlme, &mlme);
2193 }
2194 #endif /* !IEEE80211_NO_HOSTAP */
2195 break;
2196 default:
2197 return EINVAL;
2198 }
2199 break;
2200 case IEEE80211_MLME_AUTHORIZE:
2201 case IEEE80211_MLME_UNAUTHORIZE:
2202 if (ic->ic_opmode != IEEE80211_M_HOSTAP)
2203 return EINVAL;
2204 ni = ieee80211_find_node(&ic->ic_sta, mlme.im_macaddr);
2205 if (ni == NULL)
2206 return EINVAL;
2207 if (mlme.im_op == IEEE80211_MLME_AUTHORIZE)
2208 ieee80211_node_authorize(ni);
2209 else
2210 ieee80211_node_unauthorize(ni);
2211 ieee80211_free_node(ni);
2212 break;
2213 default:
2214 return EINVAL;
2215 }
2216 return 0;
2217 }
2218
2219 static int
2220 ieee80211_ioctl_macmac(struct ieee80211com *ic, struct ieee80211req *ireq)
2221 {
2222 uint8_t mac[IEEE80211_ADDR_LEN];
2223 const struct ieee80211_aclator *acl = ic->ic_acl;
2224 int error;
2225
2226 if (ireq->i_len != sizeof(mac))
2227 return EINVAL;
2228 error = copyin(ireq->i_data, mac, ireq->i_len);
2229 if (error)
2230 return error;
2231 if (acl == NULL) {
2232 acl = ieee80211_aclator_get("mac");
2233 if (acl == NULL || !acl->iac_attach(ic))
2234 return EINVAL;
2235 ic->ic_acl = acl;
2236 }
2237 if (ireq->i_type == IEEE80211_IOC_ADDMAC)
2238 acl->iac_add(ic, mac);
2239 else
2240 acl->iac_remove(ic, mac);
2241 return 0;
2242 }
2243
2244 static int
2245 ieee80211_ioctl_setmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
2246 {
2247 const struct ieee80211_aclator *acl = ic->ic_acl;
2248
2249 switch (ireq->i_val) {
2250 case IEEE80211_MACCMD_POLICY_OPEN:
2251 case IEEE80211_MACCMD_POLICY_ALLOW:
2252 case IEEE80211_MACCMD_POLICY_DENY:
2253 if (acl == NULL) {
2254 acl = ieee80211_aclator_get("mac");
2255 if (acl == NULL || !acl->iac_attach(ic))
2256 return EINVAL;
2257 ic->ic_acl = acl;
2258 }
2259 acl->iac_setpolicy(ic, ireq->i_val);
2260 break;
2261 case IEEE80211_MACCMD_FLUSH:
2262 if (acl != NULL)
2263 acl->iac_flush(ic);
2264 /* NB: silently ignore when not in use */
2265 break;
2266 case IEEE80211_MACCMD_DETACH:
2267 if (acl != NULL) {
2268 ic->ic_acl = NULL;
2269 acl->iac_detach(ic);
2270 }
2271 break;
2272 default:
2273 if (acl == NULL)
2274 return EINVAL;
2275 else
2276 return acl->iac_setioctl(ic, ireq);
2277 }
2278 return 0;
2279 }
2280
2281 static int
2282 ieee80211_ioctl_setchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
2283 {
2284 struct ieee80211req_chanlist list;
2285 u_int8_t chanlist[IEEE80211_CHAN_BYTES];
2286 int i, j, nchan, error;
2287
2288 if (ireq->i_len != sizeof(list))
2289 return EINVAL;
2290 error = copyin(ireq->i_data, &list, sizeof(list));
2291 if (error)
2292 return error;
2293 memset(chanlist, 0, sizeof(chanlist));
2294 /*
2295 * Since channel 0 is not available for DS, channel 1
2296 * is assigned to LSB on WaveLAN.
2297 */
2298 if (ic->ic_phytype == IEEE80211_T_DS)
2299 i = 1;
2300 else
2301 i = 0;
2302 nchan = 0;
2303 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
2304 /*
2305 * NB: silently discard unavailable channels so users
2306 * can specify 1-255 to get all available channels.
2307 */
2308 if (isset(list.ic_channels, j) && isset(ic->ic_chan_avail, i)) {
2309 setbit(chanlist, i);
2310 nchan++;
2311 }
2312 }
2313 if (nchan == 0)
2314 return EINVAL;
2315 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && /* XXX */
2316 isclr(chanlist, ic->ic_bsschan->ic_ieee))
2317 ic->ic_bsschan = IEEE80211_CHAN_ANYC;
2318 memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
2319 return IS_UP_AUTO(ic) ? ieee80211_init(ic, RESCAN) : 0;
2320 }
2321
2322 static int
2323 ieee80211_ioctl_setstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
2324 {
2325 struct ieee80211_node *ni;
2326 uint8_t macaddr[IEEE80211_ADDR_LEN];
2327 int error;
2328
2329 /*
2330 * NB: we could copyin ieee80211req_sta_stats so apps
2331 * could make selective changes but that's overkill;
2332 * just clear all stats for now.
2333 */
2334 if (ireq->i_len < IEEE80211_ADDR_LEN)
2335 return EINVAL;
2336 error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
2337 if (error != 0)
2338 return error;
2339 ni = ieee80211_find_node(&ic->ic_sta, macaddr);
2340 if (ni == NULL)
2341 return EINVAL; /* XXX */
2342 memset(&ni->ni_stats, 0, sizeof(ni->ni_stats));
2343 ieee80211_free_node(ni);
2344 return 0;
2345 }
2346
2347 static int
2348 ieee80211_ioctl_setstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
2349 {
2350 struct ieee80211_node *ni;
2351 struct ieee80211req_sta_txpow txpow;
2352 int error;
2353
2354 if (ireq->i_len != sizeof(txpow))
2355 return EINVAL;
2356 error = copyin(ireq->i_data, &txpow, sizeof(txpow));
2357 if (error != 0)
2358 return error;
2359 ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
2360 if (ni == NULL)
2361 return EINVAL; /* XXX */
2362 ni->ni_txpower = txpow.it_txpow;
2363 ieee80211_free_node(ni);
2364 return error;
2365 }
2366
2367 static int
2368 ieee80211_ioctl_setwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
2369 {
2370 struct ieee80211_wme_state *wme = &ic->ic_wme;
2371 struct wmeParams *wmep, *chanp;
2372 int isbss, ac;
2373
2374 if ((ic->ic_caps & IEEE80211_C_WME) == 0)
2375 return EINVAL;
2376
2377 isbss = (ireq->i_len & IEEE80211_WMEPARAM_BSS);
2378 ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
2379 if (ac >= WME_NUM_AC)
2380 ac = WME_AC_BE;
2381 if (isbss) {
2382 chanp = &wme->wme_bssChanParams.cap_wmeParams[ac];
2383 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
2384 } else {
2385 chanp = &wme->wme_chanParams.cap_wmeParams[ac];
2386 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
2387 }
2388 switch (ireq->i_type) {
2389 case IEEE80211_IOC_WME_CWMIN: /* WME: CWmin */
2390 if (isbss) {
2391 wmep->wmep_logcwmin = ireq->i_val;
2392 if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
2393 chanp->wmep_logcwmin = ireq->i_val;
2394 } else {
2395 wmep->wmep_logcwmin = chanp->wmep_logcwmin =
2396 ireq->i_val;
2397 }
2398 break;
2399 case IEEE80211_IOC_WME_CWMAX: /* WME: CWmax */
2400 if (isbss) {
2401 wmep->wmep_logcwmax = ireq->i_val;
2402 if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
2403 chanp->wmep_logcwmax = ireq->i_val;
2404 } else {
2405 wmep->wmep_logcwmax = chanp->wmep_logcwmax =
2406 ireq->i_val;
2407 }
2408 break;
2409 case IEEE80211_IOC_WME_AIFS: /* WME: AIFS */
2410 if (isbss) {
2411 wmep->wmep_aifsn = ireq->i_val;
2412 if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
2413 chanp->wmep_aifsn = ireq->i_val;
2414 } else {
2415 wmep->wmep_aifsn = chanp->wmep_aifsn = ireq->i_val;
2416 }
2417 break;
2418 case IEEE80211_IOC_WME_TXOPLIMIT: /* WME: txops limit */
2419 if (isbss) {
2420 wmep->wmep_txopLimit = ireq->i_val;
2421 if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
2422 chanp->wmep_txopLimit = ireq->i_val;
2423 } else {
2424 wmep->wmep_txopLimit = chanp->wmep_txopLimit =
2425 ireq->i_val;
2426 }
2427 break;
2428 case IEEE80211_IOC_WME_ACM: /* WME: ACM (bss only) */
2429 wmep->wmep_acm = ireq->i_val;
2430 if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
2431 chanp->wmep_acm = ireq->i_val;
2432 break;
2433 case IEEE80211_IOC_WME_ACKPOLICY: /* WME: ACK policy (!bss only)*/
2434 wmep->wmep_noackPolicy = chanp->wmep_noackPolicy =
2435 (ireq->i_val) == 0;
2436 break;
2437 }
2438 ieee80211_wme_updateparams(ic);
2439 return 0;
2440 }
2441
2442 static int
2443 cipher2cap(int cipher)
2444 {
2445 switch (cipher) {
2446 case IEEE80211_CIPHER_WEP: return IEEE80211_C_WEP;
2447 case IEEE80211_CIPHER_AES_OCB: return IEEE80211_C_AES;
2448 case IEEE80211_CIPHER_AES_CCM: return IEEE80211_C_AES_CCM;
2449 case IEEE80211_CIPHER_CKIP: return IEEE80211_C_CKIP;
2450 case IEEE80211_CIPHER_TKIP: return IEEE80211_C_TKIP;
2451 }
2452 return 0;
2453 }
2454
2455 #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
2456 static int
2457 find11gchannel(struct ieee80211com *ic, int start, int freq)
2458 {
2459 const struct ieee80211_channel *c;
2460 int i;
2461
2462 for (i = start+1; i < ic->ic_nchans; i++) {
2463 c = &ic->ic_channels[i];
2464 if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
2465 return 1;
2466 }
2467 /* NB: should not be needed but in case things are mis-sorted */
2468 for (i = 0; i < start; i++) {
2469 c = &ic->ic_channels[i];
2470 if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
2471 return 1;
2472 }
2473 return 0;
2474 }
2475
2476 static struct ieee80211_channel *
2477 findchannel(struct ieee80211com *ic, int ieee, int mode)
2478 {
2479 static const u_int chanflags[IEEE80211_MODE_MAX] = {
2480 0, /* IEEE80211_MODE_AUTO */
2481 IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */
2482 IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */
2483 IEEE80211_CHAN_G, /* IEEE80211_MODE_11G */
2484 IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */
2485 IEEE80211_CHAN_108A, /* IEEE80211_MODE_TURBO_A */
2486 IEEE80211_CHAN_108G, /* IEEE80211_MODE_TURBO_G */
2487 IEEE80211_CHAN_STURBO, /* IEEE80211_MODE_STURBO_A */
2488 /* NB: handled specially below */
2489 IEEE80211_CHAN_A, /* IEEE80211_MODE_11NA */
2490 IEEE80211_CHAN_G, /* IEEE80211_MODE_11NG */
2491 };
2492 u_int modeflags;
2493 int i;
2494
2495 IASSERT(mode < IEEE80211_MODE_MAX, ("bad mode %u", mode));
2496 modeflags = chanflags[mode];
2497 IASSERT(modeflags != 0 || mode == IEEE80211_MODE_AUTO,
2498 ("no chanflags for mode %u", mode));
2499 for (i = 0; i < ic->ic_nchans; i++) {
2500 struct ieee80211_channel *c = &ic->ic_channels[i];
2501
2502 if (c->ic_ieee != ieee)
2503 continue;
2504 if (mode == IEEE80211_MODE_AUTO) {
2505 /* ignore turbo channels for autoselect */
2506 if (IEEE80211_IS_CHAN_TURBO(c))
2507 continue;
2508 /*
2509 * XXX special-case 11b/g channels so we
2510 * always select the g channel if both
2511 * are present.
2512 * XXX prefer HT to non-HT?
2513 */
2514 if (!IEEE80211_IS_CHAN_B(c) ||
2515 !find11gchannel(ic, i, c->ic_freq))
2516 return c;
2517 } else {
2518 /* must check HT specially */
2519 if ((mode == IEEE80211_MODE_11NA ||
2520 mode == IEEE80211_MODE_11NG) &&
2521 !IEEE80211_IS_CHAN_HT(c))
2522 continue;
2523 if ((c->ic_flags & modeflags) == modeflags)
2524 return c;
2525 }
2526 }
2527 return NULL;
2528 }
2529 #endif /*__FreeBSD__ || COMPAT_FREEBSD_NET80211 */
2530
2531 /*
2532 * Check the specified against any desired mode (aka netband).
2533 * This is only used (presently) when operating in hostap mode
2534 * to enforce consistency.
2535 */
2536 static int
2537 check_mode_consistency(const struct ieee80211_channel *c, int mode)
2538 {
2539 IASSERT(c != IEEE80211_CHAN_ANYC, ("oops, no channel"));
2540
2541 switch (mode) {
2542 case IEEE80211_MODE_11B:
2543 return (IEEE80211_IS_CHAN_B(c));
2544 case IEEE80211_MODE_11G:
2545 return (IEEE80211_IS_CHAN_ANYG(c) && !IEEE80211_IS_CHAN_HT(c));
2546 case IEEE80211_MODE_11A:
2547 return (IEEE80211_IS_CHAN_A(c) && !IEEE80211_IS_CHAN_HT(c));
2548 case IEEE80211_MODE_STURBO_A:
2549 return (IEEE80211_IS_CHAN_STURBO(c));
2550 case IEEE80211_MODE_11NA:
2551 return (IEEE80211_IS_CHAN_HTA(c));
2552 case IEEE80211_MODE_11NG:
2553 return (IEEE80211_IS_CHAN_HTG(c));
2554 }
2555 return 1;
2556
2557 }
2558
2559 /*
2560 * Common code to set the current channel. If the device
2561 * is up and running this may result in an immediate channel
2562 * change or a kick of the state machine.
2563 */
2564 static int
2565 setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c)
2566 {
2567 int error;
2568
2569 if (c != IEEE80211_CHAN_ANYC) {
2570 if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
2571 !check_mode_consistency(c, ic->ic_des_mode))
2572 return EINVAL;
2573 if (ic->ic_state == IEEE80211_S_RUN && c == ic->ic_curchan)
2574 return 0; /* NB: nothing to do */
2575 }
2576 ic->ic_des_chan = c;
2577
2578 error = 0;
2579 if ((ic->ic_opmode == IEEE80211_M_MONITOR ||
2580 ic->ic_opmode == IEEE80211_M_WDS) &&
2581 ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
2582 /*
2583 * Monitor and wds modes can switch directly.
2584 */
2585 ic->ic_curchan = ic->ic_des_chan;
2586 if (ic->ic_state == IEEE80211_S_RUN)
2587 ic->ic_set_channel(ic);
2588 } else {
2589 /*
2590 * Need to go through the state machine in case we
2591 * need to reassociate or the like. The state machine
2592 * will pickup the desired channel and avoid scanning.
2593 */
2594 if (IS_UP_AUTO(ic))
2595 error = ieee80211_init(ic, RESCAN);
2596 else if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
2597 /*
2598 * When not up+running and a real channel has
2599 * been specified fix the current channel so
2600 * there is immediate feedback; e.g. via ifconfig.
2601 */
2602 ic->ic_curchan = ic->ic_des_chan;
2603 }
2604 }
2605 return error;
2606 }
2607
2608 #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
2609 /*
2610 * Old api for setting the current channel; this is
2611 * deprecated because channel numbers are ambiguous.
2612 */
2613 static int
2614 ieee80211_ioctl_setchannel(struct ieee80211com *ic,
2615 const struct ieee80211req *ireq)
2616 {
2617 struct ieee80211_channel *c;
2618
2619 /* XXX 0xffff overflows 16-bit signed */
2620 if (ireq->i_val == 0 ||
2621 ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) {
2622 c = IEEE80211_CHAN_ANYC;
2623 } else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX) {
2624 return EINVAL;
2625 } else {
2626 struct ieee80211_channel *c2;
2627
2628 c = findchannel(ic, ireq->i_val, ic->ic_des_mode);
2629 if (c == NULL) {
2630 c = findchannel(ic, ireq->i_val,
2631 IEEE80211_MODE_AUTO);
2632 if (c == NULL)
2633 return EINVAL;
2634 }
2635 /*
2636 * Fine tune channel selection based on desired mode:
2637 * if 11b is requested, find the 11b version of any
2638 * 11g channel returned,
2639 * if static turbo, find the turbo version of any
2640 * 11a channel return,
2641 * if 11na is requested, find the ht version of any
2642 * 11a channel returned,
2643 * if 11ng is requested, find the ht version of any
2644 * 11g channel returned,
2645 * otherwise we should be ok with what we've got.
2646 */
2647 switch (ic->ic_des_mode) {
2648 case IEEE80211_MODE_11B:
2649 if (IEEE80211_IS_CHAN_ANYG(c)) {
2650 c2 = findchannel(ic, ireq->i_val,
2651 IEEE80211_MODE_11B);
2652 /* NB: should not happen, =>'s 11g w/o 11b */
2653 if (c2 != NULL)
2654 c = c2;
2655 }
2656 break;
2657 case IEEE80211_MODE_TURBO_A:
2658 if (IEEE80211_IS_CHAN_A(c)) {
2659 c2 = findchannel(ic, ireq->i_val,
2660 IEEE80211_MODE_TURBO_A);
2661 if (c2 != NULL)
2662 c = c2;
2663 }
2664 break;
2665 case IEEE80211_MODE_11NA:
2666 if (IEEE80211_IS_CHAN_A(c)) {
2667 c2 = findchannel(ic, ireq->i_val,
2668 IEEE80211_MODE_11NA);
2669 if (c2 != NULL)
2670 c = c2;
2671 }
2672 break;
2673 case IEEE80211_MODE_11NG:
2674 if (IEEE80211_IS_CHAN_ANYG(c)) {
2675 c2 = findchannel(ic, ireq->i_val,
2676 IEEE80211_MODE_11NG);
2677 if (c2 != NULL)
2678 c = c2;
2679 }
2680 break;
2681 default: /* NB: no static turboG */
2682 break;
2683 }
2684 }
2685 return setcurchan(ic, c);
2686 }
2687 #endif /*__FreeBSD__ || COMPAT_FREEBSD_NET80211 */
2688
2689 /*
2690 * New/current api for setting the current channel; a complete
2691 * channel description is provide so there is no ambiguity in
2692 * identifying the channel.
2693 */
2694 static int
2695 ieee80211_ioctl_setcurchan(struct ieee80211com *ic,
2696 const struct ieee80211req *ireq)
2697 {
2698 struct ieee80211_channel chan, *c;
2699 int error;
2700
2701 if (ireq->i_len != sizeof(chan))
2702 return EINVAL;
2703 error = copyin(ireq->i_data, &chan, sizeof(chan));
2704 if (error != 0)
2705 return error;
2706 /* XXX 0xffff overflows 16-bit signed */
2707 if (chan.ic_freq == 0 || chan.ic_freq == IEEE80211_CHAN_ANY) {
2708 c = IEEE80211_CHAN_ANYC;
2709 } else {
2710 c = ieee80211_find_channel(ic, chan.ic_freq, chan.ic_flags);
2711 if (c == NULL)
2712 return EINVAL;
2713 }
2714 return setcurchan(ic, c);
2715 }
2716
2717 static int
2718 ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
2719 {
2720 #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
2721 static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
2722 struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
2723 int error;
2724 const struct ieee80211_authenticator *auth;
2725 uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
2726 char tmpssid[IEEE80211_NWID_LEN];
2727 uint8_t tmpbssid[IEEE80211_ADDR_LEN];
2728 struct ieee80211_key *k;
2729 u_int kid;
2730 #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
2731 struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
2732 int error;
2733 const struct ieee80211_authenticator *auth;
2734 int j, caps;
2735
2736 error = 0;
2737 switch (ireq->i_type) {
2738 #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
2739 case IEEE80211_IOC_SSID:
2740 if (ireq->i_val != 0 ||
2741 ireq->i_len > IEEE80211_NWID_LEN)
2742 return EINVAL;
2743 error = copyin(ireq->i_data, tmpssid, ireq->i_len);
2744 if (error)
2745 break;
2746 memset(ic->ic_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
2747 ic->ic_des_ssid[0].len = ireq->i_len;
2748 memcpy(ic->ic_des_ssid[0].ssid, tmpssid, ireq->i_len);
2749 ic->ic_des_nssid = (ireq->i_len > 0);
2750 if (IS_UP_AUTO(ic))
2751 error = ieee80211_init(ic, RESCAN);
2752 break;
2753 #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
2754 case IEEE80211_IOC_WEP:
2755 switch (ireq->i_val) {
2756 case IEEE80211_WEP_OFF:
2757 ic->ic_flags &= ~IEEE80211_F_PRIVACY;
2758 ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
2759 break;
2760 case IEEE80211_WEP_ON:
2761 ic->ic_flags |= IEEE80211_F_PRIVACY;
2762 ic->ic_flags |= IEEE80211_F_DROPUNENC;
2763 break;
2764 case IEEE80211_WEP_MIXED:
2765 ic->ic_flags |= IEEE80211_F_PRIVACY;
2766 ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
2767 break;
2768 }
2769 if (IS_UP_AUTO(ic))
2770 error = ieee80211_init(ic, RESCAN);
2771 break;
2772 #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
2773 case IEEE80211_IOC_WEPKEY:
2774 kid = (u_int) ireq->i_val;
2775 if (kid >= IEEE80211_WEP_NKID)
2776 return EINVAL;
2777 k = &ic->ic_nw_keys[kid];
2778 if (ireq->i_len == 0) {
2779 /* zero-len =>'s delete any existing key */
2780 (void) ieee80211_crypto_delkey(ic, k);
2781 break;
2782 }
2783 if (ireq->i_len > sizeof(tmpkey))
2784 return EINVAL;
2785 memset(tmpkey, 0, sizeof(tmpkey));
2786 error = copyin(ireq->i_data, tmpkey, ireq->i_len);
2787 if (error)
2788 break;
2789 ieee80211_key_update_begin(ic);
2790 k->wk_keyix = kid; /* NB: force fixed key id */
2791 if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
2792 IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
2793 k->wk_keylen = ireq->i_len;
2794 memcpy(k->wk_key, tmpkey, sizeof(tmpkey));
2795 if (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
2796 error = EINVAL;
2797 } else
2798 error = EINVAL;
2799 ieee80211_key_update_end(ic);
2800 break;
2801 case IEEE80211_IOC_WEPTXKEY:
2802 kid = (u_int) ireq->i_val;
2803 if (kid >= IEEE80211_WEP_NKID &&
2804 (uint16_t) kid != IEEE80211_KEYIX_NONE)
2805 return EINVAL;
2806 ic->ic_def_txkey = kid;
2807 break;
2808 #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
2809 case IEEE80211_IOC_AUTHMODE:
2810 switch (ireq->i_val) {
2811 case IEEE80211_AUTH_WPA:
2812 case IEEE80211_AUTH_8021X: /* 802.1x */
2813 case IEEE80211_AUTH_OPEN: /* open */
2814 case IEEE80211_AUTH_SHARED: /* shared-key */
2815 case IEEE80211_AUTH_AUTO: /* auto */
2816 auth = ieee80211_authenticator_get(ireq->i_val);
2817 if (auth == NULL)
2818 return EINVAL;
2819 break;
2820 default:
2821 return EINVAL;
2822 }
2823 switch (ireq->i_val) {
2824 case IEEE80211_AUTH_WPA: /* WPA w/ 802.1x */
2825 ic->ic_flags |= IEEE80211_F_PRIVACY;
2826 ireq->i_val = IEEE80211_AUTH_8021X;
2827 break;
2828 case IEEE80211_AUTH_OPEN: /* open */
2829 ic->ic_flags &= ~(IEEE80211_F_WPA|IEEE80211_F_PRIVACY);
2830 break;
2831 case IEEE80211_AUTH_SHARED: /* shared-key */
2832 case IEEE80211_AUTH_8021X: /* 802.1x */
2833 ic->ic_flags &= ~IEEE80211_F_WPA;
2834 /* both require a key so mark the PRIVACY capability */
2835 ic->ic_flags |= IEEE80211_F_PRIVACY;
2836 break;
2837 case IEEE80211_AUTH_AUTO: /* auto */
2838 ic->ic_flags &= ~IEEE80211_F_WPA;
2839 /* XXX PRIVACY handling? */
2840 /* XXX what's the right way to do this? */
2841 break;
2842 }
2843 /* NB: authenticator attach/detach happens on state change */
2844 ic->ic_bss->ni_authmode = ireq->i_val;
2845 /* XXX mixed/mode/usage? */
2846 ic->ic_auth = auth;
2847 if (IS_UP_AUTO(ic))
2848 error = ieee80211_init(ic, RESCAN);
2849 break;
2850 #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
2851 case IEEE80211_IOC_CHANNEL:
2852 error = ieee80211_ioctl_setchannel(ic, ireq);
2853 break;
2854 case IEEE80211_IOC_POWERSAVE:
2855 switch (ireq->i_val) {
2856 case IEEE80211_POWERSAVE_OFF:
2857 if (ic->ic_flags & IEEE80211_F_PMGTON) {
2858 ic->ic_flags &= ~IEEE80211_F_PMGTON;
2859 error = ENETRESET;
2860 }
2861 break;
2862 case IEEE80211_POWERSAVE_ON:
2863 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
2864 error = EINVAL;
2865 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
2866 ic->ic_flags |= IEEE80211_F_PMGTON;
2867 error = ENETRESET;
2868 }
2869 break;
2870 default:
2871 error = EINVAL;
2872 break;
2873 }
2874 if (error == ENETRESET) {
2875 /*
2876 * Switching in+out of power save mode
2877 * should not require a state change.
2878 */
2879 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2880 }
2881 break;
2882 case IEEE80211_IOC_POWERSAVESLEEP:
2883 if (ireq->i_val < 0)
2884 return EINVAL;
2885 ic->ic_lintval = ireq->i_val;
2886 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2887 break;
2888 #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
2889 case IEEE80211_IOC_RTSTHRESHOLD:
2890 if (!(IEEE80211_RTS_MIN <= ireq->i_val &&
2891 ireq->i_val <= IEEE80211_RTS_MAX))
2892 return EINVAL;
2893 ic->ic_rtsthreshold = ireq->i_val;
2894 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2895 break;
2896 case IEEE80211_IOC_PROTMODE:
2897 if (ireq->i_val > IEEE80211_PROT_RTSCTS)
2898 return EINVAL;
2899 ic->ic_protmode = ireq->i_val;
2900 /* NB: if not operating in 11g this can wait */
2901 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2902 IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
2903 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2904 break;
2905 case IEEE80211_IOC_TXPOWER:
2906 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
2907 return EINVAL;
2908 if (!(IEEE80211_TXPOWER_MIN <= ireq->i_val &&
2909 ireq->i_val <= IEEE80211_TXPOWER_MAX))
2910 return EINVAL;
2911 ic->ic_txpowlimit = ireq->i_val;
2912 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2913 break;
2914 case IEEE80211_IOC_ROAMING:
2915 if (!(IEEE80211_ROAMING_DEVICE <= ireq->i_val &&
2916 ireq->i_val <= IEEE80211_ROAMING_MANUAL))
2917 return EINVAL;
2918 ic->ic_roaming = ireq->i_val;
2919 /* XXXX reset? */
2920 break;
2921 case IEEE80211_IOC_PRIVACY:
2922 if (ireq->i_val) {
2923 /* XXX check for key state? */
2924 ic->ic_flags |= IEEE80211_F_PRIVACY;
2925 } else
2926 ic->ic_flags &= ~IEEE80211_F_PRIVACY;
2927 break;
2928 case IEEE80211_IOC_DROPUNENCRYPTED:
2929 if (ireq->i_val)
2930 ic->ic_flags |= IEEE80211_F_DROPUNENC;
2931 else
2932 ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
2933 break;
2934 case IEEE80211_IOC_WPAKEY:
2935 error = ieee80211_ioctl_setkey(ic, ireq);
2936 break;
2937 case IEEE80211_IOC_DELKEY:
2938 error = ieee80211_ioctl_delkey(ic, ireq);
2939 break;
2940 case IEEE80211_IOC_MLME:
2941 error = ieee80211_ioctl_setmlme(ic, ireq);
2942 break;
2943 case IEEE80211_IOC_OPTIE:
2944 error = ieee80211_ioctl_setoptie(ic, ireq);
2945 break;
2946 case IEEE80211_IOC_COUNTERMEASURES:
2947 if (ireq->i_val) {
2948 if ((ic->ic_flags & IEEE80211_F_WPA) == 0)
2949 return EINVAL;
2950 ic->ic_flags |= IEEE80211_F_COUNTERM;
2951 } else
2952 ic->ic_flags &= ~IEEE80211_F_COUNTERM;
2953 break;
2954 case IEEE80211_IOC_WPA:
2955 if (ireq->i_val > 3)
2956 return EINVAL;
2957 /* XXX verify ciphers available */
2958 ic->ic_flags &= ~IEEE80211_F_WPA;
2959 switch (ireq->i_val) {
2960 case 1:
2961 ic->ic_flags |= IEEE80211_F_WPA1;
2962 break;
2963 case 2:
2964 ic->ic_flags |= IEEE80211_F_WPA2;
2965 break;
2966 case 3:
2967 ic->ic_flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2;
2968 break;
2969 }
2970 error = ENETRESET;
2971 break;
2972 case IEEE80211_IOC_WME:
2973 if (ireq->i_val) {
2974 if ((ic->ic_caps & IEEE80211_C_WME) == 0)
2975 return EINVAL;
2976 ic->ic_flags |= IEEE80211_F_WME;
2977 } else
2978 ic->ic_flags &= ~IEEE80211_F_WME;
2979 if (IS_UP_AUTO(ic))
2980 error = ieee80211_init(ic, 0);
2981 break;
2982 case IEEE80211_IOC_HIDESSID:
2983 if (ireq->i_val)
2984 ic->ic_flags |= IEEE80211_F_HIDESSID;
2985 else
2986 ic->ic_flags &= ~IEEE80211_F_HIDESSID;
2987 error = ENETRESET;
2988 break;
2989 case IEEE80211_IOC_APBRIDGE:
2990 if (ireq->i_val == 0)
2991 ic->ic_flags |= IEEE80211_F_NOBRIDGE;
2992 else
2993 ic->ic_flags &= ~IEEE80211_F_NOBRIDGE;
2994 break;
2995 case IEEE80211_IOC_MCASTCIPHER:
2996 if ((ic->ic_caps & cipher2cap(ireq->i_val)) == 0 &&
2997 !ieee80211_crypto_available(ireq->i_val))
2998 return EINVAL;
2999 rsn->rsn_mcastcipher = ireq->i_val;
3000 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
3001 break;
3002 case IEEE80211_IOC_MCASTKEYLEN:
3003 if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
3004 return EINVAL;
3005 /* XXX no way to verify driver capability */
3006 rsn->rsn_mcastkeylen = ireq->i_val;
3007 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
3008 break;
3009 case IEEE80211_IOC_UCASTCIPHERS:
3010 /*
3011 * Convert user-specified cipher set to the set
3012 * we can support (via hardware or software).
3013 * NB: this logic intentionally ignores unknown and
3014 * unsupported ciphers so folks can specify 0xff or
3015 * similar and get all available ciphers.
3016 */
3017 caps = 0;
3018 for (j = 1; j < 32; j++) /* NB: skip WEP */
3019 if ((ireq->i_val & (1<<j)) &&
3020 ((ic->ic_caps & cipher2cap(j)) ||
3021 ieee80211_crypto_available(j)))
3022 caps |= 1<<j;
3023 if (caps == 0) /* nothing available */
3024 return EINVAL;
3025 /* XXX verify ciphers ok for unicast use? */
3026 /* XXX disallow if running as it'll have no effect */
3027 rsn->rsn_ucastcipherset = caps;
3028 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
3029 break;
3030 case IEEE80211_IOC_UCASTCIPHER:
3031 if ((rsn->rsn_ucastcipherset & cipher2cap(ireq->i_val)) == 0)
3032 return EINVAL;
3033 rsn->rsn_ucastcipher = ireq->i_val;
3034 break;
3035 case IEEE80211_IOC_UCASTKEYLEN:
3036 if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
3037 return EINVAL;
3038 /* XXX no way to verify driver capability */
3039 rsn->rsn_ucastkeylen = ireq->i_val;
3040 break;
3041 case IEEE80211_IOC_DRIVER_CAPS:
3042 /* NB: for testing */
3043 ic->ic_caps = (((uint16_t) ireq->i_val) << 16) |
3044 ((uint16_t) ireq->i_len);
3045 break;
3046 case IEEE80211_IOC_KEYMGTALGS:
3047 /* XXX check */
3048 rsn->rsn_keymgmtset = ireq->i_val;
3049 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
3050 break;
3051 case IEEE80211_IOC_RSNCAPS:
3052 /* XXX check */
3053 rsn->rsn_caps = ireq->i_val;
3054 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
3055 break;
3056 #if defined(__FreeBSD__) || defined(COMPAT_FREEBSD_NET80211)
3057 case IEEE80211_IOC_BSSID:
3058 if (ireq->i_len != sizeof(tmpbssid))
3059 return EINVAL;
3060 error = copyin(ireq->i_data, tmpbssid, ireq->i_len);
3061 if (error)
3062 break;
3063 IEEE80211_ADDR_COPY(ic->ic_des_bssid, tmpbssid);
3064 if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid))
3065 ic->ic_flags &= ~IEEE80211_F_DESBSSID;
3066 else
3067 ic->ic_flags |= IEEE80211_F_DESBSSID;
3068 if (IS_UP_AUTO(ic))
3069 error = ieee80211_init(ic, RESCAN);
3070 break;
3071 #endif /* __FreeBSD__ || COMPAT_FREEBSD_NET80211 */
3072 case IEEE80211_IOC_CHANLIST:
3073 error = ieee80211_ioctl_setchanlist(ic, ireq);
3074 break;
3075 case IEEE80211_IOC_SCAN_REQ:
3076 if (!IS_UP(ic))
3077 return EINVAL;
3078 (void) ieee80211_start_scan(ic,
3079 IEEE80211_SCAN_ACTIVE |
3080 IEEE80211_SCAN_NOPICK |
3081 IEEE80211_SCAN_ONCE, IEEE80211_SCAN_FOREVER,
3082 /* XXX use ioctl params */
3083 ic->ic_des_nssid, ic->ic_des_ssid);
3084 break;
3085 case IEEE80211_IOC_ADDMAC:
3086 case IEEE80211_IOC_DELMAC:
3087 error = ieee80211_ioctl_macmac(ic, ireq);
3088 break;
3089 case IEEE80211_IOC_MACCMD:
3090 error = ieee80211_ioctl_setmaccmd(ic, ireq);
3091 break;
3092 case IEEE80211_IOC_STA_STATS:
3093 error = ieee80211_ioctl_setstastats(ic, ireq);
3094 break;
3095 case IEEE80211_IOC_STA_TXPOW:
3096 error = ieee80211_ioctl_setstatxpow(ic, ireq);
3097 break;
3098 case IEEE80211_IOC_WME_CWMIN: /* WME: CWmin */
3099 case IEEE80211_IOC_WME_CWMAX: /* WME: CWmax */
3100 case IEEE80211_IOC_WME_AIFS: /* WME: AIFS */
3101 case IEEE80211_IOC_WME_TXOPLIMIT: /* WME: txops limit */
3102 case IEEE80211_IOC_WME_ACM: /* WME: ACM (bss only) */
3103 case IEEE80211_IOC_WME_ACKPOLICY: /* WME: ACK policy (bss only) */
3104 error = ieee80211_ioctl_setwmeparam(ic, ireq);
3105 break;
3106 case IEEE80211_IOC_DTIM_PERIOD:
3107 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
3108 ic->ic_opmode != IEEE80211_M_IBSS)
3109 return EINVAL;
3110 if (IEEE80211_DTIM_MIN <= ireq->i_val &&
3111 ireq->i_val <= IEEE80211_DTIM_MAX) {
3112 ic->ic_dtim_period = ireq->i_val;
3113 error = ENETRESET; /* requires restart */
3114 } else
3115 error = EINVAL;
3116 break;
3117 case IEEE80211_IOC_BEACON_INTERVAL:
3118 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
3119 ic->ic_opmode != IEEE80211_M_IBSS)
3120 return EINVAL;
3121 if (IEEE80211_BINTVAL_MIN <= ireq->i_val &&
3122 ireq->i_val <= IEEE80211_BINTVAL_MAX) {
3123 ic->ic_bintval = ireq->i_val;
3124 error = ENETRESET; /* requires restart */
3125 } else
3126 error = EINVAL;
3127 break;
3128 case IEEE80211_IOC_PUREG:
3129 if (ireq->i_val)
3130 ic->ic_flags |= IEEE80211_F_PUREG;
3131 else
3132 ic->ic_flags &= ~IEEE80211_F_PUREG;
3133 /* NB: reset only if we're operating on an 11g channel */
3134 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
3135 IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
3136 error = ENETRESET;
3137 break;
3138 case IEEE80211_IOC_FF:
3139 if (ireq->i_val) {
3140 if ((ic->ic_caps & IEEE80211_C_FF) == 0)
3141 return EINVAL;
3142 ic->ic_flags |= IEEE80211_F_FF;
3143 } else
3144 ic->ic_flags &= ~IEEE80211_F_FF;
3145 error = ENETRESET;
3146 break;
3147 case IEEE80211_IOC_TURBOP:
3148 if (ireq->i_val) {
3149 if ((ic->ic_caps & IEEE80211_C_TURBOP) == 0)
3150 return EINVAL;
3151 ic->ic_flags |= IEEE80211_F_TURBOP;
3152 } else
3153 ic->ic_flags &= ~IEEE80211_F_TURBOP;
3154 error = ENETRESET;
3155 break;
3156 case IEEE80211_IOC_BGSCAN:
3157 if (ireq->i_val) {
3158 if ((ic->ic_caps & IEEE80211_C_BGSCAN) == 0)
3159 return EINVAL;
3160 ic->ic_flags |= IEEE80211_F_BGSCAN;
3161 } else
3162 ic->ic_flags &= ~IEEE80211_F_BGSCAN;
3163 break;
3164 case IEEE80211_IOC_BGSCAN_IDLE:
3165 if (ireq->i_val >= IEEE80211_BGSCAN_IDLE_MIN)
3166 ic->ic_bgscanidle = ireq->i_val*hz/1000;
3167 else
3168 error = EINVAL;
3169 break;
3170 case IEEE80211_IOC_BGSCAN_INTERVAL:
3171 if (ireq->i_val >= IEEE80211_BGSCAN_INTVAL_MIN)
3172 ic->ic_bgscanintvl = ireq->i_val*hz;
3173 else
3174 error = EINVAL;
3175 break;
3176 case IEEE80211_IOC_SCANVALID:
3177 if (ireq->i_val >= IEEE80211_SCAN_VALID_MIN)
3178 ic->ic_scanvalid = ireq->i_val*hz;
3179 else
3180 error = EINVAL;
3181 break;
3182 case IEEE80211_IOC_ROAM_RSSI_11A:
3183 ic->ic_roam.rssi11a = ireq->i_val;
3184 break;
3185 case IEEE80211_IOC_ROAM_RSSI_11B:
3186 ic->ic_roam.rssi11bOnly = ireq->i_val;
3187 break;
3188 case IEEE80211_IOC_ROAM_RSSI_11G:
3189 ic->ic_roam.rssi11b = ireq->i_val;
3190 break;
3191 case IEEE80211_IOC_ROAM_RATE_11A:
3192 ic->ic_roam.rate11a = ireq->i_val & IEEE80211_RATE_VAL;
3193 break;
3194 case IEEE80211_IOC_ROAM_RATE_11B:
3195 ic->ic_roam.rate11bOnly = ireq->i_val & IEEE80211_RATE_VAL;
3196 break;
3197 case IEEE80211_IOC_ROAM_RATE_11G:
3198 ic->ic_roam.rate11b = ireq->i_val & IEEE80211_RATE_VAL;
3199 break;
3200 case IEEE80211_IOC_MCAST_RATE:
3201 ic->ic_mcast_rate = ireq->i_val & IEEE80211_RATE_VAL;
3202 break;
3203 case IEEE80211_IOC_FRAGTHRESHOLD:
3204 if ((ic->ic_caps & IEEE80211_C_TXFRAG) == 0 &&
3205 ireq->i_val != IEEE80211_FRAG_MAX)
3206 return EINVAL;
3207 if (!(IEEE80211_FRAG_MIN <= ireq->i_val &&
3208 ireq->i_val <= IEEE80211_FRAG_MAX))
3209 return EINVAL;
3210 ic->ic_fragthreshold = ireq->i_val;
3211 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
3212 break;
3213 case IEEE80211_IOC_BURST:
3214 if (ireq->i_val) {
3215 if ((ic->ic_caps & IEEE80211_C_BURST) == 0)
3216 return EINVAL;
3217 ic->ic_flags |= IEEE80211_F_BURST;
3218 } else
3219 ic->ic_flags &= ~IEEE80211_F_BURST;
3220 error = ENETRESET; /* XXX maybe not for station? */
3221 break;
3222 case IEEE80211_IOC_BMISSTHRESHOLD:
3223 if (!(IEEE80211_HWBMISS_MIN <= ireq->i_val &&
3224 ireq->i_val <= IEEE80211_HWBMISS_MAX))
3225 return EINVAL;
3226 ic->ic_bmissthreshold = ireq->i_val;
3227 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
3228 break;
3229 case IEEE80211_IOC_CURCHAN:
3230 error = ieee80211_ioctl_setcurchan(ic, ireq);
3231 break;
3232 case IEEE80211_IOC_SHORTGI:
3233 if (ireq->i_val) {
3234 #define IEEE80211_HTCAP_SHORTGI \
3235 (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40)
3236 if (((ireq->i_val ^ ic->ic_htcaps) & IEEE80211_HTCAP_SHORTGI) != 0)
3237 return EINVAL;
3238 if (ireq->i_val & IEEE80211_HTCAP_SHORTGI20)
3239 ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI20;
3240 if (ireq->i_val & IEEE80211_HTCAP_SHORTGI40)
3241 ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI40;
3242 #undef IEEE80211_HTCAP_SHORTGI
3243 } else
3244 ic->ic_flags_ext &=
3245 ~(IEEE80211_FEXT_SHORTGI20 | IEEE80211_FEXT_SHORTGI40);
3246 /* XXX kick state machine? */
3247 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
3248 break;
3249 case IEEE80211_IOC_AMPDU:
3250 if (ireq->i_val) {
3251 if ((ic->ic_htcaps & IEEE80211_HTC_AMPDU) == 0)
3252 return EINVAL;
3253 if (ireq->i_val & 1)
3254 ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_TX;
3255 if (ireq->i_val & 2)
3256 ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_RX;
3257 } else
3258 ic->ic_flags_ext &=
3259 ~(IEEE80211_FEXT_AMPDU_TX|IEEE80211_FEXT_AMPDU_RX);
3260 /* NB: reset only if we're operating on an 11n channel */
3261 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
3262 IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
3263 error = ENETRESET;
3264 break;
3265 case IEEE80211_IOC_AMPDU_LIMIT:
3266 /* XXX validate */
3267 ic->ic_ampdu_limit = ireq->i_val;
3268 break;
3269 case IEEE80211_IOC_AMPDU_DENSITY:
3270 /* XXX validate */
3271 ic->ic_ampdu_density = ireq->i_val;
3272 break;
3273 case IEEE80211_IOC_AMSDU:
3274 if (ireq->i_val) {
3275 if ((ic->ic_htcaps & IEEE80211_HTC_AMSDU) == 0)
3276 return EINVAL;
3277 if (ireq->i_val & 1)
3278 ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_TX;
3279 if (ireq->i_val & 2)
3280 ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_RX;
3281 } else
3282 ic->ic_flags_ext &=
3283 ~(IEEE80211_FEXT_AMSDU_TX|IEEE80211_FEXT_AMSDU_RX);
3284 /* NB: reset only if we're operating on an 11n channel */
3285 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
3286 IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
3287 error = ENETRESET;
3288 break;
3289 case IEEE80211_IOC_AMSDU_LIMIT:
3290 /* XXX validate */
3291 ic->ic_amsdu_limit = ireq->i_val; /* XXX truncation? */
3292 break;
3293 case IEEE80211_IOC_PUREN:
3294 if (ireq->i_val) {
3295 if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) == 0)
3296 return EINVAL;
3297 ic->ic_flags_ext |= IEEE80211_FEXT_PUREN;
3298 } else
3299 ic->ic_flags_ext &= ~IEEE80211_FEXT_PUREN;
3300 /* NB: reset only if we're operating on an 11n channel */
3301 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
3302 IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
3303 error = ENETRESET;
3304 break;
3305 case IEEE80211_IOC_DOTH:
3306 if (ireq->i_val) {
3307 #if 0
3308 /* XXX no capability */
3309 if ((ic->ic_caps & IEEE80211_C_DOTH) == 0)
3310 return EINVAL;
3311 #endif
3312 ic->ic_flags |= IEEE80211_F_DOTH;
3313 } else
3314 ic->ic_flags &= ~IEEE80211_F_DOTH;
3315 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
3316 break;
3317 case IEEE80211_IOC_HTCOMPAT:
3318 if (ireq->i_val) {
3319 if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) == 0)
3320 return EINVAL;
3321 ic->ic_flags_ext |= IEEE80211_FEXT_HTCOMPAT;
3322 } else
3323 ic->ic_flags_ext &= ~IEEE80211_FEXT_HTCOMPAT;
3324 /* NB: reset only if we're operating on an 11n channel */
3325 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
3326 IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
3327 error = ENETRESET;
3328 break;
3329 case IEEE80211_IOC_INACTIVITY:
3330 if (ireq->i_val)
3331 ic->ic_flags_ext |= IEEE80211_FEXT_INACT;
3332 else
3333 ic->ic_flags_ext &= ~IEEE80211_FEXT_INACT;
3334 break;
3335 case IEEE80211_IOC_HTPROTMODE:
3336 if (ireq->i_val > IEEE80211_PROT_RTSCTS)
3337 return EINVAL;
3338 ic->ic_htprotmode = ireq->i_val ?
3339 IEEE80211_PROT_RTSCTS : IEEE80211_PROT_NONE;
3340 /* NB: if not operating in 11n this can wait */
3341 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
3342 IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
3343 error = ERESTART;
3344 break;
3345 case IEEE80211_IOC_HTCONF:
3346 if (ireq->i_val & 1)
3347 ic->ic_flags_ext |= IEEE80211_FEXT_HT;
3348 else
3349 ic->ic_flags_ext &= ~IEEE80211_FEXT_HT;
3350 if (ireq->i_val & 2)
3351 ic->ic_flags_ext |= IEEE80211_FEXT_USEHT40;
3352 else
3353 ic->ic_flags_ext &= ~IEEE80211_FEXT_USEHT40;
3354 error = ENETRESET;
3355 break;
3356 default:
3357 error = EINVAL;
3358 break;
3359 }
3360 if (error == ENETRESET)
3361 error = IS_UP_AUTO(ic) ? ieee80211_init(ic, 0) : 0;
3362 return error;
3363 }
3364
3365 #ifdef __FreeBSD__
3366 int
3367 ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, void *data)
3368 {
3369 struct ifnet *ifp = ic->ic_ifp;
3370 int error = 0;
3371 struct ifreq *ifr;
3372 struct ifaddr *ifa; /* XXX */
3373
3374 switch (cmd) {
3375 case SIOCSIFMEDIA:
3376 case SIOCGIFMEDIA:
3377 error = ifmedia_ioctl(ifp, (struct ifreq *) data,
3378 &ic->ic_media, cmd);
3379 break;
3380 case SIOCG80211:
3381 error = ieee80211_ioctl_get80211(ic, cmd,
3382 (struct ieee80211req *) data);
3383 break;
3384 case SIOCS80211:
3385 error = priv_check(curthread, PRIV_NET80211_MANAGE);
3386 if (error == 0)
3387 error = ieee80211_ioctl_set80211(ic, cmd,
3388 (struct ieee80211req *) data);
3389 break;
3390 case SIOCG80211STATS:
3391 ifr = (struct ifreq *)data;
3392 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
3393 break;
3394 case SIOCSIFMTU:
3395 ifr = (struct ifreq *)data;
3396 if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
3397 ifr->ifr_mtu <= IEEE80211_MTU_MAX))
3398 error = EINVAL;
3399 else
3400 ifp->if_mtu = ifr->ifr_mtu;
3401 break;
3402 case SIOCSIFADDR:
3403 /*
3404 * XXX Handle this directly so we can supress if_init calls.
3405 * XXX This should be done in ether_ioctl but for the moment
3406 * XXX there are too many other parts of the system that
3407 * XXX set IFF_UP and so supress if_init being called when
3408 * XXX it should be.
3409 */
3410 ifa = (struct ifaddr *) data;
3411 switch (ifa->ifa_addr->sa_family) {
3412 #ifdef INET
3413 case AF_INET:
3414 if ((ifp->if_flags & IFF_UP) == 0) {
3415 ifp->if_flags |= IFF_UP;
3416 ifp->if_init(ifp->if_softc);
3417 }
3418 arp_ifinit(ifp, ifa);
3419 break;
3420 #endif
3421 #ifdef IPX
3422 /*
3423 * XXX - This code is probably wrong,
3424 * but has been copied many times.
3425 */
3426 case AF_IPX: {
3427 struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
3428
3429 if (ipx_nullhost(*ina))
3430 ina->x_host = *(union ipx_host *)
3431 IF_LLADDR(ifp);
3432 else
3433 bcopy((void *) ina->x_host.c_host,
3434 (void *) IFP2ENADDR(ifp),
3435 ETHER_ADDR_LEN);
3436 /* fall thru... */
3437 }
3438 #endif
3439 default:
3440 if ((ifp->if_flags & IFF_UP) == 0) {
3441 ifp->if_flags |= IFF_UP;
3442 ifp->if_init(ifp->if_softc);
3443 }
3444 break;
3445 }
3446 break;
3447 default:
3448 error = ether_ioctl(ifp, cmd, data);
3449 break;
3450 }
3451 return error;
3452 }
3453 #endif /* __FreeBSD__ */
3454
3455 #ifdef COMPAT_20
3456 static void
3457 ieee80211_get_ostats(struct ieee80211_ostats *ostats,
3458 struct ieee80211_stats *stats)
3459 {
3460 #define COPYSTATS1(__ostats, __nstats, __dstmemb, __srcmemb, __lastmemb)\
3461 (void)memcpy(&(__ostats)->__dstmemb, &(__nstats)->__srcmemb, \
3462 offsetof(struct ieee80211_stats, __lastmemb) - \
3463 offsetof(struct ieee80211_stats, __srcmemb))
3464 #define COPYSTATS(__ostats, __nstats, __dstmemb, __lastmemb) \
3465 COPYSTATS1(__ostats, __nstats, __dstmemb, __dstmemb, __lastmemb)
3466
3467 COPYSTATS(ostats, stats, is_rx_badversion, is_rx_unencrypted);
3468 COPYSTATS(ostats, stats, is_rx_wepfail, is_rx_beacon);
3469 COPYSTATS(ostats, stats, is_rx_rstoobig, is_rx_auth_countermeasures);
3470 COPYSTATS(ostats, stats, is_rx_assoc_bss, is_rx_assoc_badwpaie);
3471 COPYSTATS(ostats, stats, is_rx_deauth, is_rx_unauth);
3472 COPYSTATS1(ostats, stats, is_tx_nombuf, is_tx_nobuf, is_tx_badcipher);
3473 COPYSTATS(ostats, stats, is_scan_active, is_crypto_tkip);
3474 }
3475 #endif /* COMPAT_20 */
3476
3477 #ifdef __NetBSD__
3478 int
3479 ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, void *data)
3480 {
3481 struct ifnet *ifp = ic->ic_ifp;
3482 struct ifreq *ifr = (struct ifreq *)data;
3483 int i, error = 0, kid, klen, s;
3484 struct ieee80211_key *k;
3485 struct ieee80211_nwid nwid;
3486 struct ieee80211_nwkey *nwkey;
3487 struct ieee80211_power *power;
3488 struct ieee80211_bssid *bssid;
3489 struct ieee80211chanreq *chanreq;
3490 struct ieee80211_channel *chan;
3491 uint32_t oflags;
3492 #ifdef COMPAT_20
3493 struct ieee80211_ostats ostats;
3494 #endif /* COMPAT_20 */
3495 static const u_int8_t zerobssid[IEEE80211_ADDR_LEN];
3496 u_int8_t tmpkey[IEEE80211_WEP_NKID][IEEE80211_KEYBUF_SIZE];
3497
3498 switch (cmd) {
3499 #ifdef OSIOCSIFMEDIA
3500 case OSIOCSIFMEDIA:
3501 #endif
3502 case SIOCSIFMEDIA:
3503 case SIOCGIFMEDIA:
3504 error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
3505 break;
3506 case SIOCG80211:
3507 error = ieee80211_ioctl_get80211(ic, cmd,
3508 (struct ieee80211req *) data);
3509 break;
3510 case SIOCS80211:
3511 if ((error = kauth_authorize_network(curlwp->l_cred,
3512 KAUTH_NETWORK_INTERFACE,
3513 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
3514 NULL) != 0))
3515 break;
3516 error = ieee80211_ioctl_set80211(ic, cmd,
3517 (struct ieee80211req *) data);
3518 break;
3519 case SIOCS80211NWID:
3520 if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
3521 break;
3522 if (nwid.i_len > IEEE80211_NWID_LEN) {
3523 error = EINVAL;
3524 break;
3525 }
3526 memset(ic->ic_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
3527 ic->ic_des_ssid[0].len = nwid.i_len;
3528 memcpy(ic->ic_des_ssid[0].ssid, nwid.i_nwid, nwid.i_len);
3529 error = ENETRESET;
3530 break;
3531 case SIOCG80211NWID:
3532 memset(&nwid, 0, sizeof(nwid));
3533 switch (ic->ic_state) {
3534 case IEEE80211_S_INIT:
3535 case IEEE80211_S_SCAN:
3536 nwid.i_len = ic->ic_des_ssid[0].len;
3537 memcpy(nwid.i_nwid, ic->ic_des_ssid[0].ssid, nwid.i_len);
3538 break;
3539 default:
3540 nwid.i_len = ic->ic_bss->ni_esslen;
3541 memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
3542 break;
3543 }
3544 error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
3545 break;
3546 case SIOCS80211NWKEY:
3547 nwkey = (struct ieee80211_nwkey *)data;
3548 /* transmit key index out of range? */
3549 kid = nwkey->i_defkid - 1;
3550 if (kid < 0 || kid >= IEEE80211_WEP_NKID) {
3551 error = EINVAL;
3552 break;
3553 }
3554 /* no such transmit key is set? */
3555 if (nwkey->i_key[kid].i_keylen == 0 ||
3556 (nwkey->i_key[kid].i_keylen == -1 &&
3557 ic->ic_nw_keys[kid].wk_keylen == 0)) {
3558 if (nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
3559 error = EINVAL;
3560 break;
3561 }
3562 }
3563 /* check key lengths */
3564 for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
3565 klen = nwkey->i_key[kid].i_keylen;
3566 if ((klen > 0 &&
3567 klen < IEEE80211_WEP_KEYLEN) ||
3568 klen > sizeof(ic->ic_nw_keys[kid].wk_key)) {
3569 error = EINVAL;
3570 break;
3571 }
3572 }
3573
3574 if (error)
3575 break;
3576
3577 /* copy in keys */
3578 (void)memset(tmpkey, 0, sizeof(tmpkey));
3579 for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
3580 klen = nwkey->i_key[kid].i_keylen;
3581 if (klen <= 0)
3582 continue;
3583 if ((error = copyin(nwkey->i_key[kid].i_keydat,
3584 tmpkey[kid], klen)) != 0)
3585 break;
3586 }
3587
3588 if (error)
3589 break;
3590
3591 /* set keys */
3592 ieee80211_key_update_begin(ic);
3593 for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
3594 klen = nwkey->i_key[kid].i_keylen;
3595 if (klen <= 0)
3596 continue;
3597 k = &ic->ic_nw_keys[kid];
3598 k->wk_keyix = kid;
3599 if (!ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
3600 IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
3601 error = EINVAL;
3602 continue;
3603 }
3604 k->wk_keylen = nwkey->i_key[kid].i_keylen;
3605 (void)memcpy(k->wk_key, tmpkey[kid],
3606 sizeof(tmpkey[kid]));
3607 if (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
3608 error = EINVAL;
3609 }
3610 ieee80211_key_update_end(ic);
3611
3612 if (error)
3613 break;
3614
3615 /* delete keys */
3616 for (kid = 0; kid < IEEE80211_WEP_NKID; kid++) {
3617 klen = nwkey->i_key[kid].i_keylen;
3618 k = &ic->ic_nw_keys[kid];
3619 if (klen <= 0)
3620 (void)ieee80211_crypto_delkey(ic, k);
3621 }
3622
3623 /* set transmit key */
3624 kid = nwkey->i_defkid - 1;
3625 if (ic->ic_def_txkey != kid) {
3626 ic->ic_def_txkey = kid;
3627 error = ENETRESET;
3628 }
3629 oflags = ic->ic_flags;
3630 if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) {
3631 ic->ic_flags &= ~IEEE80211_F_PRIVACY;
3632 ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
3633 } else {
3634 ic->ic_flags |= IEEE80211_F_PRIVACY;
3635 ic->ic_flags |= IEEE80211_F_DROPUNENC;
3636 }
3637 if (oflags != ic->ic_flags)
3638 error = ENETRESET;
3639 break;
3640 case SIOCG80211NWKEY:
3641 nwkey = (struct ieee80211_nwkey *)data;
3642 if (ic->ic_flags & IEEE80211_F_PRIVACY)
3643 nwkey->i_wepon = IEEE80211_NWKEY_WEP;
3644 else
3645 nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
3646 nwkey->i_defkid = ic->ic_def_txkey + 1;
3647 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
3648 if (nwkey->i_key[i].i_keydat == NULL)
3649 continue;
3650 /* do not show any keys to non-root user */
3651 if ((error = kauth_authorize_network(curlwp->l_cred,
3652 KAUTH_NETWORK_INTERFACE,
3653 KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp,
3654 (void *)cmd, NULL)) != 0)
3655 break;
3656 nwkey->i_key[i].i_keylen = ic->ic_nw_keys[i].wk_keylen;
3657 if ((error = copyout(ic->ic_nw_keys[i].wk_key,
3658 nwkey->i_key[i].i_keydat,
3659 ic->ic_nw_keys[i].wk_keylen)) != 0)
3660 break;
3661 }
3662 break;
3663 case SIOCS80211POWER:
3664 power = (struct ieee80211_power *)data;
3665 ic->ic_lintval = power->i_maxsleep;
3666 if (power->i_enabled != 0) {
3667 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
3668 error = EINVAL;
3669 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
3670 ic->ic_flags |= IEEE80211_F_PMGTON;
3671 error = ENETRESET;
3672 }
3673 } else {
3674 if (ic->ic_flags & IEEE80211_F_PMGTON) {
3675 ic->ic_flags &= ~IEEE80211_F_PMGTON;
3676 error = ENETRESET;
3677 }
3678 }
3679 break;
3680 case SIOCG80211POWER:
3681 power = (struct ieee80211_power *)data;
3682 power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
3683 power->i_maxsleep = ic->ic_lintval;
3684 break;
3685 case SIOCS80211BSSID:
3686 bssid = (struct ieee80211_bssid *)data;
3687 IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
3688 if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid))
3689 ic->ic_flags &= ~IEEE80211_F_DESBSSID;
3690 else
3691 ic->ic_flags |= IEEE80211_F_DESBSSID;
3692 error = ENETRESET;
3693 break;
3694 case SIOCG80211BSSID:
3695 bssid = (struct ieee80211_bssid *)data;
3696 switch (ic->ic_state) {
3697 case IEEE80211_S_INIT:
3698 case IEEE80211_S_SCAN:
3699 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
3700 IEEE80211_ADDR_COPY(bssid->i_bssid,
3701 ic->ic_myaddr);
3702 else if (ic->ic_flags & IEEE80211_F_DESBSSID)
3703 IEEE80211_ADDR_COPY(bssid->i_bssid,
3704 ic->ic_des_bssid);
3705 else
3706 memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
3707 break;
3708 default:
3709 IEEE80211_ADDR_COPY(bssid->i_bssid,
3710 ic->ic_bss->ni_bssid);
3711 break;
3712 }
3713 break;
3714 case SIOCS80211CHANNEL:
3715 chanreq = (struct ieee80211chanreq *)data;
3716 if (chanreq->i_channel == IEEE80211_CHAN_ANY)
3717 ic->ic_des_chan = IEEE80211_CHAN_ANYC;
3718 else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
3719 isclr(ic->ic_chan_active, chanreq->i_channel)) {
3720 error = EINVAL;
3721 break;
3722 } else
3723 ic->ic_bsschan = ic->ic_des_chan =
3724 &ic->ic_channels[chanreq->i_channel];
3725 switch (ic->ic_state) {
3726 case IEEE80211_S_INIT:
3727 case IEEE80211_S_SCAN:
3728 error = ENETRESET;
3729 break;
3730 default:
3731 if (ic->ic_opmode == IEEE80211_M_STA) {
3732 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
3733 ic->ic_bss->ni_chan != ic->ic_des_chan)
3734 error = ENETRESET;
3735 } else {
3736 if (ic->ic_bss->ni_chan != ic->ic_bsschan)
3737 error = ENETRESET;
3738 }
3739 break;
3740 }
3741 break;
3742 case SIOCG80211CHANNEL:
3743 chanreq = (struct ieee80211chanreq *)data;
3744 switch (ic->ic_state) {
3745 case IEEE80211_S_INIT:
3746 case IEEE80211_S_SCAN:
3747 if (ic->ic_opmode == IEEE80211_M_STA)
3748 chan = ic->ic_des_chan;
3749 else
3750 chan = ic->ic_bsschan;
3751 break;
3752 default:
3753 chan = ic->ic_curchan;
3754 break;
3755 }
3756 chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
3757 break;
3758 case SIOCGIFGENERIC:
3759 error = ieee80211_cfgget(ic, cmd, data);
3760 break;
3761 case SIOCSIFGENERIC:
3762 error = kauth_authorize_network(curlwp->l_cred,
3763 KAUTH_NETWORK_INTERFACE,
3764 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
3765 NULL);
3766 if (error)
3767 break;
3768 error = ieee80211_cfgset(ic, cmd, data);
3769 break;
3770 #ifdef COMPAT_20
3771 case OSIOCG80211STATS:
3772 case OSIOCG80211ZSTATS:
3773 ifr = (struct ifreq *)data;
3774 s = splnet();
3775 ieee80211_get_ostats(&ostats, &ic->ic_stats);
3776 error = copyout(&ostats, ifr->ifr_data, sizeof(ostats));
3777 if (error == 0 && cmd == OSIOCG80211ZSTATS)
3778 (void)memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
3779 splx(s);
3780 break;
3781 #endif /* COMPAT_20 */
3782 case SIOCG80211ZSTATS:
3783 case SIOCG80211STATS:
3784 ifr = (struct ifreq *)data;
3785 s = splnet();
3786 error = copyout(&ic->ic_stats, ifr->ifr_buf,
3787 MIN(sizeof(ic->ic_stats), ifr->ifr_buflen));
3788 if (error == 0 && cmd == SIOCG80211ZSTATS)
3789 (void)memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
3790 splx(s);
3791 break;
3792 case SIOCSIFMTU:
3793 ifr = (struct ifreq *)data;
3794 if (ifr->ifr_mtu < IEEE80211_MTU_MIN &&
3795 ifr->ifr_mtu > IEEE80211_MTU_MAX)
3796 error = EINVAL;
3797 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
3798 error = 0;
3799 break;
3800 default:
3801 error = ether_ioctl(ifp, cmd, data);
3802 break;
3803 }
3804 return error;
3805 }
3806 #endif /* __NetBSD__ */
3807