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