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