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