ieee80211_ioctl.c revision 1.9 1 /* $NetBSD: ieee80211_ioctl.c,v 1.9 2004/04/21 18:16:14 itojun Exp $ */
2 /*-
3 * Copyright (c) 2001 Atsushi Onoe
4 * Copyright (c) 2002, 2003 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.9 2003/11/13 05:23:58 sam Exp $");
37 #else
38 __KERNEL_RCSID(0, "$NetBSD: ieee80211_ioctl.c,v 1.9 2004/04/21 18:16:14 itojun Exp $");
39 #endif
40
41 /*
42 * IEEE 802.11 ioctl support (FreeBSD-specific)
43 */
44
45 #include <sys/endian.h>
46 #include <sys/param.h>
47 #include <sys/kernel.h>
48 #include <sys/socket.h>
49 #include <sys/sockio.h>
50 #include <sys/systm.h>
51 #include <sys/proc.h>
52
53 #include <net/if.h>
54 #include <net/if_arp.h>
55 #include <net/if_media.h>
56 #ifdef __FreeBSD__
57 #include <net/ethernet.h>
58 #else
59 #include <net/if_ether.h>
60 #endif
61
62 #include <net80211/ieee80211_var.h>
63 #include <net80211/ieee80211_ioctl.h>
64
65 #ifdef __FreeBSD__
66 #include <dev/wi/if_wavelan_ieee.h>
67 #else
68 #include <dev/ic/wi_ieee.h>
69 #endif
70
71 /*
72 * XXX
73 * Wireless LAN specific configuration interface, which is compatible
74 * with wicontrol(8).
75 */
76
77 int
78 ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data)
79 {
80 struct ieee80211com *ic = (void *)ifp;
81 int i, j, error;
82 struct ifreq *ifr = (struct ifreq *)data;
83 struct wi_req wreq;
84 struct wi_ltv_keys *keys;
85 struct wi_apinfo *ap;
86 struct ieee80211_node *ni;
87 struct ieee80211_rateset *rs;
88 #ifdef WICACHE
89 struct wi_sigcache wsc;
90 #endif /* WICACHE */
91 #if 0 /* TBD */
92 struct wi_scan_p2_hdr *p2;
93 struct wi_scan_res *res;
94 #endif
95
96 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
97 if (error)
98 return error;
99 wreq.wi_len = 0;
100 switch (wreq.wi_type) {
101 case WI_RID_SERIALNO:
102 case WI_RID_STA_IDENTITY:
103 /* nothing appropriate */
104 break;
105 case WI_RID_NODENAME:
106 strlcpy((char *)&wreq.wi_val[1], hostname,
107 sizeof(wreq.wi_val) - sizeof(wreq.wi_val[0]));
108 wreq.wi_val[0] = htole16(strlen(hostname));
109 wreq.wi_len = (1 + strlen(hostname) + 1) / 2;
110 break;
111 case WI_RID_CURRENT_SSID:
112 if (ic->ic_state != IEEE80211_S_RUN) {
113 wreq.wi_val[0] = 0;
114 wreq.wi_len = 1;
115 break;
116 }
117 wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen);
118 memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid,
119 ic->ic_bss->ni_esslen);
120 wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
121 break;
122 case WI_RID_OWN_SSID:
123 case WI_RID_DESIRED_SSID:
124 wreq.wi_val[0] = htole16(ic->ic_des_esslen);
125 memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
126 wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2;
127 break;
128 case WI_RID_CURRENT_BSSID:
129 if (ic->ic_state == IEEE80211_S_RUN)
130 IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid);
131 else
132 memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN);
133 wreq.wi_len = IEEE80211_ADDR_LEN / 2;
134 break;
135 case WI_RID_CHANNEL_LIST:
136 memset(wreq.wi_val, 0, sizeof(wreq.wi_val));
137 /*
138 * Since channel 0 is not available for DS, channel 1
139 * is assigned to LSB on WaveLAN.
140 */
141 if (ic->ic_phytype == IEEE80211_T_DS)
142 i = 1;
143 else
144 i = 0;
145 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
146 if (isset(ic->ic_chan_active, i)) {
147 setbit((u_int8_t *)wreq.wi_val, j);
148 wreq.wi_len = j / 16 + 1;
149 }
150 break;
151 case WI_RID_OWN_CHNL:
152 wreq.wi_val[0] = htole16(
153 ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
154 wreq.wi_len = 1;
155 break;
156 case WI_RID_CURRENT_CHAN:
157 wreq.wi_val[0] = htole16(
158 ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
159 wreq.wi_len = 1;
160 break;
161 case WI_RID_COMMS_QUALITY:
162 wreq.wi_val[0] = 0; /* quality */
163 wreq.wi_val[1] =
164 htole16((*ic->ic_node_getrssi)(ic, ic->ic_bss));
165 wreq.wi_val[2] = 0; /* noise */
166 wreq.wi_len = 3;
167 break;
168 case WI_RID_PROMISC:
169 wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
170 wreq.wi_len = 1;
171 break;
172 case WI_RID_PORTTYPE:
173 wreq.wi_val[0] = htole16(ic->ic_opmode);
174 wreq.wi_len = 1;
175 break;
176 case WI_RID_MAC_NODE:
177 IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr);
178 wreq.wi_len = IEEE80211_ADDR_LEN / 2;
179 break;
180 case WI_RID_TX_RATE:
181 if (ic->ic_fixed_rate == -1)
182 wreq.wi_val[0] = 0; /* auto */
183 else
184 wreq.wi_val[0] = htole16(
185 (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
186 IEEE80211_RATE_VAL) / 2);
187 wreq.wi_len = 1;
188 break;
189 case WI_RID_CUR_TX_RATE:
190 wreq.wi_val[0] = htole16(
191 (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
192 IEEE80211_RATE_VAL) / 2);
193 wreq.wi_len = 1;
194 break;
195 case WI_RID_FRAG_THRESH:
196 wreq.wi_val[0] = htole16(ic->ic_fragthreshold);
197 wreq.wi_len = 1;
198 break;
199 case WI_RID_RTS_THRESH:
200 wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
201 wreq.wi_len = 1;
202 break;
203 case WI_RID_CREATE_IBSS:
204 wreq.wi_val[0] =
205 htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
206 wreq.wi_len = 1;
207 break;
208 case WI_RID_MICROWAVE_OVEN:
209 wreq.wi_val[0] = 0; /* no ... not supported */
210 wreq.wi_len = 1;
211 break;
212 case WI_RID_ROAMING_MODE:
213 wreq.wi_val[0] = htole16(1); /* enabled ... not supported */
214 wreq.wi_len = 1;
215 break;
216 case WI_RID_SYSTEM_SCALE:
217 wreq.wi_val[0] = htole16(1); /* low density ... not supp */
218 wreq.wi_len = 1;
219 break;
220 case WI_RID_PM_ENABLED:
221 wreq.wi_val[0] =
222 htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
223 wreq.wi_len = 1;
224 break;
225 case WI_RID_MAX_SLEEP:
226 wreq.wi_val[0] = htole16(ic->ic_lintval);
227 wreq.wi_len = 1;
228 break;
229 case WI_RID_CUR_BEACON_INT:
230 wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
231 wreq.wi_len = 1;
232 break;
233 case WI_RID_WEP_AVAIL:
234 wreq.wi_val[0] =
235 htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0);
236 wreq.wi_len = 1;
237 break;
238 case WI_RID_CNFAUTHMODE:
239 wreq.wi_val[0] = htole16(1); /* TODO: open system only */
240 wreq.wi_len = 1;
241 break;
242 case WI_RID_ENCRYPTION:
243 wreq.wi_val[0] =
244 htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0);
245 wreq.wi_len = 1;
246 break;
247 case WI_RID_TX_CRYPT_KEY:
248 wreq.wi_val[0] = htole16(ic->ic_wep_txkey);
249 wreq.wi_len = 1;
250 break;
251 case WI_RID_DEFLT_CRYPT_KEYS:
252 keys = (struct wi_ltv_keys *)&wreq;
253 /* do not show keys to non-root user */
254 error = suser(curproc->p_ucred, &curproc->p_acflag);
255 if (error) {
256 memset(keys, 0, sizeof(*keys));
257 error = 0;
258 break;
259 }
260 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
261 keys->wi_keys[i].wi_keylen =
262 htole16(ic->ic_nw_keys[i].wk_len);
263 memcpy(keys->wi_keys[i].wi_keydat,
264 ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len);
265 }
266 wreq.wi_len = sizeof(*keys) / 2;
267 break;
268 case WI_RID_MAX_DATALEN:
269 wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN); /* TODO: frag */
270 wreq.wi_len = 1;
271 break;
272 case WI_RID_DBM_ADJUST:
273 /* not supported, we just pass rssi value from driver. */
274 break;
275 case WI_RID_IFACE_STATS:
276 /* XXX: should be implemented in lower drivers */
277 break;
278 case WI_RID_READ_APS:
279 if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
280 /*
281 * Don't return results until active scan completes.
282 */
283 if (ic->ic_state == IEEE80211_S_SCAN &&
284 (ic->ic_flags & IEEE80211_F_ASCAN)) {
285 error = EINPROGRESS;
286 break;
287 }
288 }
289 i = 0;
290 ap = (void *)((char *)wreq.wi_val + sizeof(i));
291 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
292 if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1))
293 break;
294 memset(ap, 0, sizeof(*ap));
295 if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
296 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
297 ap->namelen = ic->ic_des_esslen;
298 if (ic->ic_des_esslen)
299 memcpy(ap->name, ic->ic_des_essid,
300 ic->ic_des_esslen);
301 } else {
302 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
303 ap->namelen = ni->ni_esslen;
304 if (ni->ni_esslen)
305 memcpy(ap->name, ni->ni_essid,
306 ni->ni_esslen);
307 }
308 ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
309 ap->signal = (*ic->ic_node_getrssi)(ic, ni);
310 ap->capinfo = ni->ni_capinfo;
311 ap->interval = ni->ni_intval;
312 rs = &ni->ni_rates;
313 for (j = 0; j < rs->rs_nrates; j++) {
314 if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
315 ap->rate = (rs->rs_rates[j] &
316 IEEE80211_RATE_VAL) * 5; /* XXX */
317 }
318 }
319 i++;
320 ap++;
321 }
322 memcpy(wreq.wi_val, &i, sizeof(i));
323 wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2;
324 break;
325 #if 0
326 case WI_RID_PRISM2:
327 wreq.wi_val[0] = 1; /* XXX lie so SCAN_RES can give rates */
328 wreq.wi_len = sizeof(u_int16_t) / 2;
329 break;
330 case WI_RID_SCAN_RES: /* compatibility interface */
331 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
332 ic->ic_state == IEEE80211_S_SCAN) {
333 error = EINPROGRESS;
334 break;
335 }
336 /* NB: we use the Prism2 format so we can return rate info */
337 p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
338 res = (void *)&p2[1];
339 i = 0;
340 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
341 if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1))
342 break;
343 res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
344 res->wi_noise = 0;
345 res->wi_signal = (*ic->ic_node_getrssi)(ic, ni);
346 IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
347 res->wi_interval = ni->ni_intval;
348 res->wi_capinfo = ni->ni_capinfo;
349 res->wi_ssid_len = ni->ni_esslen;
350 memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
351 /* NB: assumes wi_srates holds <= ni->ni_rates */
352 memcpy(res->wi_srates, ni->ni_rates.rs_rates,
353 sizeof(res->wi_srates));
354 if (ni->ni_rates.rs_nrates < 10)
355 res->wi_srates[ni->ni_rates.rs_nrates] = 0;
356 res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
357 res->wi_rsvd = 0;
358 res++, i++;
359 }
360 p2->wi_rsvd = 0;
361 p2->wi_reason = i;
362 wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2;
363 break;
364 #endif /* 0 */
365 #ifdef WICACHE
366 case WI_RID_READ_CACHE:
367 i = 0;
368 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
369 if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1)
370 break;
371 IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr);
372 memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc));
373 wsc.signal = (*ic->ic_node_getrssi)(ic, ni);
374 wsc.noise = 0;
375 wsc.quality = 0;
376 memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
377 &wsc, sizeof(wsc));
378 i++;
379 }
380 wreq.wi_len = sizeof(wsc) * i / 2;
381 break;
382 #endif /* WICACHE */
383 case WI_RID_SCAN_APS:
384 error = EINVAL;
385 break;
386 default:
387 error = EINVAL;
388 break;
389 }
390 if (error == 0) {
391 wreq.wi_len++;
392 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
393 }
394 return error;
395 }
396
397 static int
398 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
399 {
400 #define IEEERATE(_ic,_m,_i) \
401 ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
402 int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
403 for (i = 0; i < nrates; i++)
404 if (IEEERATE(ic, mode, i) == rate)
405 return i;
406 return -1;
407 #undef IEEERATE
408 }
409
410 /*
411 * Prepare to do a user-initiated scan for AP's. If no
412 * current/default channel is setup or the current channel
413 * is invalid then pick the first available channel from
414 * the active list as the place to start the scan.
415 */
416 static int
417 ieee80211_setupscan(struct ieee80211com *ic)
418 {
419 u_char *chanlist = ic->ic_chan_active;
420 int i;
421
422 if (ic->ic_ibss_chan == NULL ||
423 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
424 for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
425 if (isset(chanlist, i)) {
426 ic->ic_ibss_chan = &ic->ic_channels[i];
427 goto found;
428 }
429 return EINVAL; /* no active channels */
430 found:
431 ;
432 }
433 if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
434 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
435 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
436 /*
437 * XXX don't permit a scan to be started unless we
438 * know the device is ready. For the moment this means
439 * the device is marked up as this is the required to
440 * initialize the hardware. It would be better to permit
441 * scanning prior to being up but that'll require some
442 * changes to the infrastructure.
443 */
444 return (ic->ic_if.if_flags & IFF_UP) ? 0 : ENETRESET;
445 }
446
447 int
448 ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data)
449 {
450 struct ieee80211com *ic = (void *)ifp;
451 int i, j, len, error, rate;
452 struct ifreq *ifr = (struct ifreq *)data;
453 struct wi_ltv_keys *keys;
454 struct wi_req wreq;
455 u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
456
457 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
458 if (error)
459 return error;
460 len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
461 switch (wreq.wi_type) {
462 case WI_RID_SERIALNO:
463 case WI_RID_NODENAME:
464 return EPERM;
465 case WI_RID_CURRENT_SSID:
466 return EPERM;
467 case WI_RID_OWN_SSID:
468 case WI_RID_DESIRED_SSID:
469 if (le16toh(wreq.wi_val[0]) * 2 > len ||
470 le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
471 error = ENOSPC;
472 break;
473 }
474 memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
475 ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
476 memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
477 error = ENETRESET;
478 break;
479 case WI_RID_CURRENT_BSSID:
480 return EPERM;
481 case WI_RID_OWN_CHNL:
482 if (len != 2)
483 return EINVAL;
484 i = le16toh(wreq.wi_val[0]);
485 if (i < 0 ||
486 i > IEEE80211_CHAN_MAX ||
487 isclr(ic->ic_chan_active, i))
488 return EINVAL;
489 ic->ic_ibss_chan = &ic->ic_channels[i];
490 if (ic->ic_flags & IEEE80211_F_SIBSS)
491 error = ENETRESET;
492 break;
493 case WI_RID_CURRENT_CHAN:
494 return EPERM;
495 case WI_RID_COMMS_QUALITY:
496 return EPERM;
497 case WI_RID_PROMISC:
498 if (len != 2)
499 return EINVAL;
500 if (ifp->if_flags & IFF_PROMISC) {
501 if (wreq.wi_val[0] == 0) {
502 ifp->if_flags &= ~IFF_PROMISC;
503 error = ENETRESET;
504 }
505 } else {
506 if (wreq.wi_val[0] != 0) {
507 ifp->if_flags |= IFF_PROMISC;
508 error = ENETRESET;
509 }
510 }
511 break;
512 case WI_RID_PORTTYPE:
513 if (len != 2)
514 return EINVAL;
515 switch (le16toh(wreq.wi_val[0])) {
516 case IEEE80211_M_STA:
517 break;
518 case IEEE80211_M_IBSS:
519 if (!(ic->ic_caps & IEEE80211_C_IBSS))
520 return EINVAL;
521 break;
522 case IEEE80211_M_AHDEMO:
523 if (ic->ic_phytype != IEEE80211_T_DS ||
524 !(ic->ic_caps & IEEE80211_C_AHDEMO))
525 return EINVAL;
526 break;
527 case IEEE80211_M_HOSTAP:
528 if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
529 return EINVAL;
530 break;
531 default:
532 return EINVAL;
533 }
534 if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
535 ic->ic_opmode = le16toh(wreq.wi_val[0]);
536 error = ENETRESET;
537 }
538 break;
539 #if 0
540 case WI_RID_MAC_NODE:
541 if (len != IEEE80211_ADDR_LEN)
542 return EINVAL;
543 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
544 /* if_init will copy lladdr into ic_myaddr */
545 error = ENETRESET;
546 break;
547 #endif
548 case WI_RID_TX_RATE:
549 if (len != 2)
550 return EINVAL;
551 if (wreq.wi_val[0] == 0) {
552 /* auto */
553 ic->ic_fixed_rate = -1;
554 break;
555 }
556 rate = 2 * le16toh(wreq.wi_val[0]);
557 if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
558 /*
559 * In autoselect mode search for the rate. We take
560 * the first instance which may not be right, but we
561 * are limited by the interface. Note that we also
562 * lock the mode to insure the rate is meaningful
563 * when it is used.
564 */
565 for (j = IEEE80211_MODE_11A;
566 j < IEEE80211_MODE_MAX; j++) {
567 if ((ic->ic_modecaps & (1<<j)) == 0)
568 continue;
569 i = findrate(ic, j, rate);
570 if (i != -1) {
571 /* lock mode too */
572 ic->ic_curmode = j;
573 goto setrate;
574 }
575 }
576 } else {
577 i = findrate(ic, ic->ic_curmode, rate);
578 if (i != -1)
579 goto setrate;
580 }
581 return EINVAL;
582 setrate:
583 ic->ic_fixed_rate = i;
584 error = ENETRESET;
585 break;
586 case WI_RID_CUR_TX_RATE:
587 return EPERM;
588 case WI_RID_FRAG_THRESH:
589 if (len != 2)
590 return EINVAL;
591 ic->ic_fragthreshold = le16toh(wreq.wi_val[0]);
592 error = ENETRESET;
593 break;
594 case WI_RID_RTS_THRESH:
595 if (len != 2)
596 return EINVAL;
597 ic->ic_rtsthreshold = le16toh(wreq.wi_val[0]);
598 error = ENETRESET;
599 break;
600 case WI_RID_CREATE_IBSS:
601 if (len != 2)
602 return EINVAL;
603 if (wreq.wi_val[0] != 0) {
604 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
605 return EINVAL;
606 if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
607 ic->ic_flags |= IEEE80211_F_IBSSON;
608 if (ic->ic_opmode == IEEE80211_M_IBSS &&
609 ic->ic_state == IEEE80211_S_SCAN)
610 error = ENETRESET;
611 }
612 } else {
613 if (ic->ic_flags & IEEE80211_F_IBSSON) {
614 ic->ic_flags &= ~IEEE80211_F_IBSSON;
615 if (ic->ic_flags & IEEE80211_F_SIBSS) {
616 ic->ic_flags &= ~IEEE80211_F_SIBSS;
617 error = ENETRESET;
618 }
619 }
620 }
621 break;
622 case WI_RID_MICROWAVE_OVEN:
623 if (len != 2)
624 return EINVAL;
625 if (wreq.wi_val[0] != 0)
626 return EINVAL; /* not supported */
627 break;
628 case WI_RID_ROAMING_MODE:
629 if (len != 2)
630 return EINVAL;
631 if (le16toh(wreq.wi_val[0]) != 1)
632 return EINVAL; /* not supported */
633 break;
634 case WI_RID_SYSTEM_SCALE:
635 if (len != 2)
636 return EINVAL;
637 if (le16toh(wreq.wi_val[0]) != 1)
638 return EINVAL; /* not supported */
639 break;
640 case WI_RID_PM_ENABLED:
641 if (len != 2)
642 return EINVAL;
643 if (wreq.wi_val[0] != 0) {
644 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
645 return EINVAL;
646 if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
647 ic->ic_flags |= IEEE80211_F_PMGTON;
648 error = ENETRESET;
649 }
650 } else {
651 if (ic->ic_flags & IEEE80211_F_PMGTON) {
652 ic->ic_flags &= ~IEEE80211_F_PMGTON;
653 error = ENETRESET;
654 }
655 }
656 break;
657 case WI_RID_MAX_SLEEP:
658 if (len != 2)
659 return EINVAL;
660 ic->ic_lintval = le16toh(wreq.wi_val[0]);
661 if (ic->ic_flags & IEEE80211_F_PMGTON)
662 error = ENETRESET;
663 break;
664 case WI_RID_CUR_BEACON_INT:
665 return EPERM;
666 case WI_RID_WEP_AVAIL:
667 return EPERM;
668 case WI_RID_CNFAUTHMODE:
669 if (len != 2)
670 return EINVAL;
671 if (le16toh(wreq.wi_val[0]) != 1)
672 return EINVAL; /* TODO: shared key auth */
673 break;
674 case WI_RID_ENCRYPTION:
675 if (len != 2)
676 return EINVAL;
677 if (wreq.wi_val[0] != 0) {
678 if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
679 return EINVAL;
680 if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) {
681 ic->ic_flags |= IEEE80211_F_WEPON;
682 error = ENETRESET;
683 }
684 } else {
685 if (ic->ic_flags & IEEE80211_F_WEPON) {
686 ic->ic_flags &= ~IEEE80211_F_WEPON;
687 error = ENETRESET;
688 }
689 }
690 break;
691 case WI_RID_TX_CRYPT_KEY:
692 if (len != 2)
693 return EINVAL;
694 i = le16toh(wreq.wi_val[0]);
695 if (i >= IEEE80211_WEP_NKID)
696 return EINVAL;
697 ic->ic_wep_txkey = i;
698 break;
699 case WI_RID_DEFLT_CRYPT_KEYS:
700 if (len != sizeof(struct wi_ltv_keys))
701 return EINVAL;
702 keys = (struct wi_ltv_keys *)&wreq;
703 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
704 len = le16toh(keys->wi_keys[i].wi_keylen);
705 if (len != 0 && len < IEEE80211_WEP_KEYLEN)
706 return EINVAL;
707 if (len > sizeof(ic->ic_nw_keys[i].wk_key))
708 return EINVAL;
709 }
710 memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys));
711 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
712 len = le16toh(keys->wi_keys[i].wi_keylen);
713 ic->ic_nw_keys[i].wk_len = len;
714 memcpy(ic->ic_nw_keys[i].wk_key,
715 keys->wi_keys[i].wi_keydat, len);
716 }
717 error = ENETRESET;
718 break;
719 case WI_RID_MAX_DATALEN:
720 if (len != 2)
721 return EINVAL;
722 len = le16toh(wreq.wi_val[0]);
723 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
724 return EINVAL;
725 if (len != IEEE80211_MAX_LEN)
726 return EINVAL; /* TODO: fragment */
727 ic->ic_fragthreshold = len;
728 error = ENETRESET;
729 break;
730 case WI_RID_IFACE_STATS:
731 error = EPERM;
732 break;
733 case WI_RID_SCAN_REQ: /* XXX wicontrol */
734 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
735 break;
736 error = ieee80211_setupscan(ic);
737 if (error == 0)
738 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
739 break;
740 case WI_RID_SCAN_APS:
741 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
742 break;
743 len--; /* XXX: tx rate? */
744 /* FALLTHRU */
745 case WI_RID_CHANNEL_LIST:
746 memset(chanlist, 0, sizeof(chanlist));
747 /*
748 * Since channel 0 is not available for DS, channel 1
749 * is assigned to LSB on WaveLAN.
750 */
751 if (ic->ic_phytype == IEEE80211_T_DS)
752 i = 1;
753 else
754 i = 0;
755 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
756 if ((j / 8) >= len)
757 break;
758 if (isclr((u_int8_t *)wreq.wi_val, j))
759 continue;
760 if (isclr(ic->ic_chan_active, i)) {
761 if (wreq.wi_type != WI_RID_CHANNEL_LIST)
762 continue;
763 if (isclr(ic->ic_chan_avail, i))
764 return EPERM;
765 }
766 setbit(chanlist, i);
767 }
768 memcpy(ic->ic_chan_active, chanlist,
769 sizeof(ic->ic_chan_active));
770 error = ieee80211_setupscan(ic);
771 if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
772 /* NB: ignore error from ieee80211_setupscan */
773 error = ENETRESET;
774 } else if (error == 0)
775 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
776 break;
777 default:
778 error = EINVAL;
779 break;
780 }
781 return error;
782 }
783
784 #ifdef __FreeBSD__
785 int
786 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
787 {
788 struct ieee80211com *ic = (void *)ifp;
789 int error = 0;
790 u_int kid, len;
791 struct ieee80211req *ireq;
792 struct ifreq *ifr;
793 u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
794 char tmpssid[IEEE80211_NWID_LEN];
795 struct ieee80211_channel *chan;
796
797 switch (cmd) {
798 case SIOCSIFMEDIA:
799 case SIOCGIFMEDIA:
800 error = ifmedia_ioctl(ifp, (struct ifreq *) data,
801 &ic->ic_media, cmd);
802 break;
803 case SIOCG80211:
804 ireq = (struct ieee80211req *) data;
805 switch (ireq->i_type) {
806 case IEEE80211_IOC_SSID:
807 switch (ic->ic_state) {
808 case IEEE80211_S_INIT:
809 case IEEE80211_S_SCAN:
810 ireq->i_len = ic->ic_des_esslen;
811 memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
812 break;
813 default:
814 ireq->i_len = ic->ic_bss->ni_esslen;
815 memcpy(tmpssid, ic->ic_bss->ni_essid,
816 ireq->i_len);
817 break;
818 }
819 error = copyout(tmpssid, ireq->i_data, ireq->i_len);
820 break;
821 case IEEE80211_IOC_NUMSSIDS:
822 ireq->i_val = 1;
823 break;
824 case IEEE80211_IOC_WEP:
825 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
826 ireq->i_val = IEEE80211_WEP_NOSUP;
827 } else {
828 if (ic->ic_flags & IEEE80211_F_WEPON) {
829 ireq->i_val =
830 IEEE80211_WEP_MIXED;
831 } else {
832 ireq->i_val =
833 IEEE80211_WEP_OFF;
834 }
835 }
836 break;
837 case IEEE80211_IOC_WEPKEY:
838 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
839 error = EINVAL;
840 break;
841 }
842 kid = (u_int) ireq->i_val;
843 if (kid >= IEEE80211_WEP_NKID) {
844 error = EINVAL;
845 break;
846 }
847 len = (u_int) ic->ic_nw_keys[kid].wk_len;
848 /* NB: only root can read WEP keys */
849 if (suser(curthread) == 0) {
850 bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
851 } else {
852 bzero(tmpkey, len);
853 }
854 ireq->i_len = len;
855 error = copyout(tmpkey, ireq->i_data, len);
856 break;
857 case IEEE80211_IOC_NUMWEPKEYS:
858 if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
859 error = EINVAL;
860 else
861 ireq->i_val = IEEE80211_WEP_NKID;
862 break;
863 case IEEE80211_IOC_WEPTXKEY:
864 if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
865 error = EINVAL;
866 else
867 ireq->i_val = ic->ic_wep_txkey;
868 break;
869 case IEEE80211_IOC_AUTHMODE:
870 ireq->i_val = IEEE80211_AUTH_OPEN;
871 break;
872 case IEEE80211_IOC_CHANNEL:
873 switch (ic->ic_state) {
874 case IEEE80211_S_INIT:
875 case IEEE80211_S_SCAN:
876 if (ic->ic_opmode == IEEE80211_M_STA)
877 chan = ic->ic_des_chan;
878 else
879 chan = ic->ic_ibss_chan;
880 break;
881 default:
882 chan = ic->ic_bss->ni_chan;
883 break;
884 }
885 ireq->i_val = ieee80211_chan2ieee(ic, chan);
886 break;
887 case IEEE80211_IOC_POWERSAVE:
888 if (ic->ic_flags & IEEE80211_F_PMGTON)
889 ireq->i_val = IEEE80211_POWERSAVE_ON;
890 else
891 ireq->i_val = IEEE80211_POWERSAVE_OFF;
892 break;
893 case IEEE80211_IOC_POWERSAVESLEEP:
894 ireq->i_val = ic->ic_lintval;
895 break;
896 case IEEE80211_IOC_RTSTHRESHOLD:
897 ireq->i_val = ic->ic_rtsthreshold;
898 break;
899 default:
900 error = EINVAL;
901 }
902 break;
903 case SIOCS80211:
904 error = suser(curproc->p_ucred, &curproc->p_acflag);
905 if (error)
906 break;
907 ireq = (struct ieee80211req *) data;
908 switch (ireq->i_type) {
909 case IEEE80211_IOC_SSID:
910 if (ireq->i_val != 0 ||
911 ireq->i_len > IEEE80211_NWID_LEN) {
912 error = EINVAL;
913 break;
914 }
915 error = copyin(ireq->i_data, tmpssid, ireq->i_len);
916 if (error)
917 break;
918 memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
919 ic->ic_des_esslen = ireq->i_len;
920 memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
921 error = ENETRESET;
922 break;
923 case IEEE80211_IOC_WEP:
924 /*
925 * These cards only support one mode so
926 * we just turn wep on if what ever is
927 * passed in is not OFF.
928 */
929 if (ireq->i_val == IEEE80211_WEP_OFF) {
930 ic->ic_flags &= ~IEEE80211_F_WEPON;
931 } else {
932 ic->ic_flags |= IEEE80211_F_WEPON;
933 }
934 error = ENETRESET;
935 break;
936 case IEEE80211_IOC_WEPKEY:
937 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
938 error = EINVAL;
939 break;
940 }
941 kid = (u_int) ireq->i_val;
942 if (kid >= IEEE80211_WEP_NKID) {
943 error = EINVAL;
944 break;
945 }
946 if (ireq->i_len > sizeof(tmpkey)) {
947 error = EINVAL;
948 break;
949 }
950 memset(tmpkey, 0, sizeof(tmpkey));
951 error = copyin(ireq->i_data, tmpkey, ireq->i_len);
952 if (error)
953 break;
954 memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey,
955 sizeof(tmpkey));
956 ic->ic_nw_keys[kid].wk_len = ireq->i_len;
957 error = ENETRESET;
958 break;
959 case IEEE80211_IOC_WEPTXKEY:
960 kid = (u_int) ireq->i_val;
961 if (kid >= IEEE80211_WEP_NKID) {
962 error = EINVAL;
963 break;
964 }
965 ic->ic_wep_txkey = kid;
966 error = ENETRESET;
967 break;
968 #if 0
969 case IEEE80211_IOC_AUTHMODE:
970 sc->wi_authmode = ireq->i_val;
971 break;
972 #endif
973 case IEEE80211_IOC_CHANNEL:
974 /* XXX 0xffff overflows 16-bit signed */
975 if (ireq->i_val == 0 ||
976 ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
977 ic->ic_des_chan = IEEE80211_CHAN_ANYC;
978 else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
979 isclr(ic->ic_chan_active, ireq->i_val)) {
980 error = EINVAL;
981 break;
982 } else
983 ic->ic_ibss_chan = ic->ic_des_chan =
984 &ic->ic_channels[ireq->i_val];
985 switch (ic->ic_state) {
986 case IEEE80211_S_INIT:
987 case IEEE80211_S_SCAN:
988 error = ENETRESET;
989 break;
990 default:
991 if (ic->ic_opmode == IEEE80211_M_STA) {
992 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
993 ic->ic_bss->ni_chan != ic->ic_des_chan)
994 error = ENETRESET;
995 } else {
996 if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
997 error = ENETRESET;
998 }
999 break;
1000 }
1001 break;
1002 case IEEE80211_IOC_POWERSAVE:
1003 switch (ireq->i_val) {
1004 case IEEE80211_POWERSAVE_OFF:
1005 if (ic->ic_flags & IEEE80211_F_PMGTON) {
1006 ic->ic_flags &= ~IEEE80211_F_PMGTON;
1007 error = ENETRESET;
1008 }
1009 break;
1010 case IEEE80211_POWERSAVE_ON:
1011 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
1012 error = EINVAL;
1013 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
1014 ic->ic_flags |= IEEE80211_F_PMGTON;
1015 error = ENETRESET;
1016 }
1017 break;
1018 default:
1019 error = EINVAL;
1020 break;
1021 }
1022 break;
1023 case IEEE80211_IOC_POWERSAVESLEEP:
1024 if (ireq->i_val < 0) {
1025 error = EINVAL;
1026 break;
1027 }
1028 ic->ic_lintval = ireq->i_val;
1029 error = ENETRESET;
1030 break;
1031 case IEEE80211_IOC_RTSTHRESHOLD:
1032 if (!(IEEE80211_RTS_MIN < ireq->i_val &&
1033 ireq->i_val <= IEEE80211_RTS_MAX + 1)) {
1034 error = EINVAL;
1035 break;
1036 }
1037 ic->ic_rtsthreshold = ireq->i_val;
1038 error = ENETRESET;
1039 break;
1040 default:
1041 error = EINVAL;
1042 break;
1043 }
1044 break;
1045 case SIOCGIFGENERIC:
1046 error = ieee80211_cfgget(ifp, cmd, data);
1047 break;
1048 case SIOCSIFGENERIC:
1049 error = suser(curproc->p_ucred, &curproc->p_acflag);
1050 if (error)
1051 break;
1052 error = ieee80211_cfgset(ifp, cmd, data);
1053 break;
1054 default:
1055 error = ether_ioctl(ifp, cmd, data);
1056 break;
1057 }
1058 return error;
1059 }
1060 #endif /* __FreeBSD__ */
1061
1062 #ifdef __NetBSD__
1063 int
1064 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1065 {
1066 struct ieee80211com *ic = (void *)ifp;
1067 struct ifreq *ifr = (struct ifreq *)data;
1068 int i, error = 0;
1069 struct ieee80211_nwid nwid;
1070 struct ieee80211_nwkey *nwkey;
1071 struct ieee80211_power *power;
1072 struct ieee80211_bssid *bssid;
1073 struct ieee80211chanreq *chanreq;
1074 struct ieee80211_channel *chan;
1075 struct ieee80211_wepkey keys[IEEE80211_WEP_NKID];
1076 static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
1077 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1078 };
1079
1080 switch (cmd) {
1081 case SIOCSIFMEDIA:
1082 case SIOCGIFMEDIA:
1083 error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
1084 break;
1085 case SIOCS80211NWID:
1086 if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
1087 break;
1088 if (nwid.i_len > IEEE80211_NWID_LEN) {
1089 error = EINVAL;
1090 break;
1091 }
1092 memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
1093 ic->ic_des_esslen = nwid.i_len;
1094 memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
1095 error = ENETRESET;
1096 break;
1097 case SIOCG80211NWID:
1098 memset(&nwid, 0, sizeof(nwid));
1099 switch (ic->ic_state) {
1100 case IEEE80211_S_INIT:
1101 case IEEE80211_S_SCAN:
1102 nwid.i_len = ic->ic_des_esslen;
1103 memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
1104 break;
1105 default:
1106 nwid.i_len = ic->ic_bss->ni_esslen;
1107 memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
1108 break;
1109 }
1110 error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
1111 break;
1112 case SIOCS80211NWKEY:
1113 nwkey = (struct ieee80211_nwkey *)data;
1114 if ((ic->ic_caps & IEEE80211_C_WEP) == 0 &&
1115 nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
1116 error = EINVAL;
1117 break;
1118 }
1119 /* check and copy keys */
1120 memset(keys, 0, sizeof(keys));
1121 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1122 keys[i].wk_len = nwkey->i_key[i].i_keylen;
1123 if ((keys[i].wk_len > 0 &&
1124 keys[i].wk_len < IEEE80211_WEP_KEYLEN) ||
1125 keys[i].wk_len > sizeof(keys[i].wk_key)) {
1126 error = EINVAL;
1127 break;
1128 }
1129 if (keys[i].wk_len <= 0)
1130 continue;
1131 if ((error = copyin(nwkey->i_key[i].i_keydat,
1132 keys[i].wk_key, keys[i].wk_len)) != 0)
1133 break;
1134 }
1135 if (error)
1136 break;
1137 i = nwkey->i_defkid - 1;
1138 if (i < 0 || i >= IEEE80211_WEP_NKID ||
1139 keys[i].wk_len == 0 ||
1140 (keys[i].wk_len == -1 && ic->ic_nw_keys[i].wk_len == 0)) {
1141 if (nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
1142 error = EINVAL;
1143 break;
1144 }
1145 } else
1146 ic->ic_wep_txkey = i;
1147 /* save the key */
1148 if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN)
1149 ic->ic_flags &= ~IEEE80211_F_WEPON;
1150 else
1151 ic->ic_flags |= IEEE80211_F_WEPON;
1152 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1153 if (keys[i].wk_len < 0)
1154 continue;
1155 ic->ic_nw_keys[i].wk_len = keys[i].wk_len;
1156 memcpy(ic->ic_nw_keys[i].wk_key, keys[i].wk_key,
1157 sizeof(keys[i].wk_key));
1158 }
1159 error = ENETRESET;
1160 break;
1161 case SIOCG80211NWKEY:
1162 nwkey = (struct ieee80211_nwkey *)data;
1163 if (ic->ic_flags & IEEE80211_F_WEPON)
1164 nwkey->i_wepon = IEEE80211_NWKEY_WEP;
1165 else
1166 nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
1167 nwkey->i_defkid = ic->ic_wep_txkey + 1;
1168 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1169 if (nwkey->i_key[i].i_keydat == NULL)
1170 continue;
1171 /* do not show any keys to non-root user */
1172 if ((error = suser(curproc->p_ucred,
1173 &curproc->p_acflag)) != 0)
1174 break;
1175 nwkey->i_key[i].i_keylen = ic->ic_nw_keys[i].wk_len;
1176 if ((error = copyout(ic->ic_nw_keys[i].wk_key,
1177 nwkey->i_key[i].i_keydat,
1178 ic->ic_nw_keys[i].wk_len)) != 0)
1179 break;
1180 }
1181 break;
1182 case SIOCS80211POWER:
1183 power = (struct ieee80211_power *)data;
1184 ic->ic_lintval = power->i_maxsleep;
1185 if (power->i_enabled != 0) {
1186 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
1187 error = EINVAL;
1188 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
1189 ic->ic_flags |= IEEE80211_F_PMGTON;
1190 error = ENETRESET;
1191 }
1192 } else {
1193 if (ic->ic_flags & IEEE80211_F_PMGTON) {
1194 ic->ic_flags &= ~IEEE80211_F_PMGTON;
1195 error = ENETRESET;
1196 }
1197 }
1198 break;
1199 case SIOCG80211POWER:
1200 power = (struct ieee80211_power *)data;
1201 power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
1202 power->i_maxsleep = ic->ic_lintval;
1203 break;
1204 case SIOCS80211BSSID:
1205 bssid = (struct ieee80211_bssid *)data;
1206 if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr))
1207 ic->ic_flags &= ~IEEE80211_F_DESBSSID;
1208 else {
1209 ic->ic_flags |= IEEE80211_F_DESBSSID;
1210 IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
1211 }
1212 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
1213 break;
1214 switch (ic->ic_state) {
1215 case IEEE80211_S_INIT:
1216 case IEEE80211_S_SCAN:
1217 error = ENETRESET;
1218 break;
1219 default:
1220 if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
1221 !IEEE80211_ADDR_EQ(ic->ic_des_bssid,
1222 ic->ic_bss->ni_bssid))
1223 error = ENETRESET;
1224 break;
1225 }
1226 break;
1227 case SIOCG80211BSSID:
1228 bssid = (struct ieee80211_bssid *)data;
1229 switch (ic->ic_state) {
1230 case IEEE80211_S_INIT:
1231 case IEEE80211_S_SCAN:
1232 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
1233 IEEE80211_ADDR_COPY(bssid->i_bssid,
1234 ic->ic_myaddr);
1235 else if (ic->ic_flags & IEEE80211_F_DESBSSID)
1236 IEEE80211_ADDR_COPY(bssid->i_bssid,
1237 ic->ic_des_bssid);
1238 else
1239 memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
1240 break;
1241 default:
1242 IEEE80211_ADDR_COPY(bssid->i_bssid,
1243 ic->ic_bss->ni_bssid);
1244 break;
1245 }
1246 break;
1247 case SIOCS80211CHANNEL:
1248 chanreq = (struct ieee80211chanreq *)data;
1249 if (chanreq->i_channel == IEEE80211_CHAN_ANY)
1250 ic->ic_des_chan = IEEE80211_CHAN_ANYC;
1251 else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
1252 isclr(ic->ic_chan_active, chanreq->i_channel)) {
1253 error = EINVAL;
1254 break;
1255 } else
1256 ic->ic_ibss_chan = ic->ic_des_chan =
1257 &ic->ic_channels[chanreq->i_channel];
1258 switch (ic->ic_state) {
1259 case IEEE80211_S_INIT:
1260 case IEEE80211_S_SCAN:
1261 error = ENETRESET;
1262 break;
1263 default:
1264 if (ic->ic_opmode == IEEE80211_M_STA) {
1265 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
1266 ic->ic_bss->ni_chan != ic->ic_des_chan)
1267 error = ENETRESET;
1268 } else {
1269 if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
1270 error = ENETRESET;
1271 }
1272 break;
1273 }
1274 break;
1275 case SIOCG80211CHANNEL:
1276 chanreq = (struct ieee80211chanreq *)data;
1277 switch (ic->ic_state) {
1278 case IEEE80211_S_INIT:
1279 case IEEE80211_S_SCAN:
1280 if (ic->ic_opmode == IEEE80211_M_STA)
1281 chan = ic->ic_des_chan;
1282 else
1283 chan = ic->ic_ibss_chan;
1284 break;
1285 default:
1286 chan = ic->ic_bss->ni_chan;
1287 break;
1288 }
1289 chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
1290 break;
1291 case SIOCGIFGENERIC:
1292 error = ieee80211_cfgget(ifp, cmd, data);
1293 break;
1294 case SIOCSIFGENERIC:
1295 error = suser(curproc->p_ucred, &curproc->p_acflag);
1296 if (error)
1297 break;
1298 error = ieee80211_cfgset(ifp, cmd, data);
1299 break;
1300 case SIOCG80211STATS:
1301 ifr = (struct ifreq *)data;
1302 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
1303 break;
1304 default:
1305 error = ether_ioctl(ifp, cmd, data);
1306 break;
1307 }
1308 return error;
1309 }
1310 #endif /* __NetBSD__ */
1311