1 /*-
2 * Copyright (c) 2001 Atsushi Onoe
3 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * Alternatively, this software may be distributed under the terms of the
18 * GNU General Public License ("GPL") version 2 as published by the Free
19 * Software Foundation.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: releng/5.2/sys/net80211/ieee80211_ioctl.c 122600 2003-11-13 05:23:58Z sam $");
35
36 /*
37 * IEEE 802.11 ioctl support (FreeBSD-specific)
38 */
39
40 #include <sys/endian.h>
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <sys/systm.h>
46
47 #include <net/if.h>
48 #include <net/if_arp.h>
49 #include <net/if_media.h>
50 #include <net/ethernet.h>
51
52 #include <net80211/ieee80211_var.h>
53 #include <net80211/ieee80211_ioctl.h>
54
55 #include <dev/wi/if_wavelan_ieee.h>
56
57 /*
58 * XXX
59 * Wireless LAN specific configuration interface, which is compatible
60 * with wicontrol(8).
61 */
62
63 int
64 ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data)
65 {
66 struct ieee80211com *ic = (void *)ifp;
67 int i, j, error;
68 struct ifreq *ifr = (struct ifreq *)data;
69 struct wi_req wreq;
70 struct wi_ltv_keys *keys;
71 struct wi_apinfo *ap;
72 struct ieee80211_node *ni;
73 struct ieee80211_rateset *rs;
74 struct wi_sigcache wsc;
75 struct wi_scan_p2_hdr *p2;
76 struct wi_scan_res *res;
77
78 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
79 if (error)
80 return error;
81 wreq.wi_len = 0;
82 switch (wreq.wi_type) {
83 case WI_RID_SERIALNO:
84 /* nothing appropriate */
85 break;
86 case WI_RID_NODENAME:
87 strcpy((char *)&wreq.wi_val[1], hostname);
88 wreq.wi_val[0] = htole16(strlen(hostname));
89 wreq.wi_len = (1 + strlen(hostname) + 1) / 2;
90 break;
91 case WI_RID_CURRENT_SSID:
92 if (ic->ic_state != IEEE80211_S_RUN) {
93 wreq.wi_val[0] = 0;
94 wreq.wi_len = 1;
95 break;
96 }
97 wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen);
98 memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid,
99 ic->ic_bss->ni_esslen);
100 wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
101 break;
102 case WI_RID_OWN_SSID:
103 case WI_RID_DESIRED_SSID:
104 wreq.wi_val[0] = htole16(ic->ic_des_esslen);
105 memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
106 wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2;
107 break;
108 case WI_RID_CURRENT_BSSID:
109 if (ic->ic_state == IEEE80211_S_RUN)
110 IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid);
111 else
112 memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN);
113 wreq.wi_len = IEEE80211_ADDR_LEN / 2;
114 break;
115 case WI_RID_CHANNEL_LIST:
116 memset(wreq.wi_val, 0, sizeof(wreq.wi_val));
117 /*
118 * Since channel 0 is not available for DS, channel 1
119 * is assigned to LSB on WaveLAN.
120 */
121 if (ic->ic_phytype == IEEE80211_T_DS)
122 i = 1;
123 else
124 i = 0;
125 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
126 if (isset(ic->ic_chan_active, i)) {
127 setbit((u_int8_t *)wreq.wi_val, j);
128 wreq.wi_len = j / 16 + 1;
129 }
130 break;
131 case WI_RID_OWN_CHNL:
132 wreq.wi_val[0] = htole16(
133 ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
134 wreq.wi_len = 1;
135 break;
136 case WI_RID_CURRENT_CHAN:
137 wreq.wi_val[0] = htole16(
138 ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
139 wreq.wi_len = 1;
140 break;
141 case WI_RID_COMMS_QUALITY:
142 wreq.wi_val[0] = 0; /* quality */
143 wreq.wi_val[1] =
144 htole16((*ic->ic_node_getrssi)(ic, ic->ic_bss));
145 wreq.wi_val[2] = 0; /* noise */
146 wreq.wi_len = 3;
147 break;
148 case WI_RID_PROMISC:
149 wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
150 wreq.wi_len = 1;
151 break;
152 case WI_RID_PORTTYPE:
153 wreq.wi_val[0] = htole16(ic->ic_opmode);
154 wreq.wi_len = 1;
155 break;
156 case WI_RID_MAC_NODE:
157 IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr);
158 wreq.wi_len = IEEE80211_ADDR_LEN / 2;
159 break;
160 case WI_RID_TX_RATE:
161 if (ic->ic_fixed_rate == -1)
162 wreq.wi_val[0] = 0; /* auto */
163 else
164 wreq.wi_val[0] = htole16(
165 (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
166 IEEE80211_RATE_VAL) / 2);
167 wreq.wi_len = 1;
168 break;
169 case WI_RID_CUR_TX_RATE:
170 wreq.wi_val[0] = htole16(
171 (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
172 IEEE80211_RATE_VAL) / 2);
173 wreq.wi_len = 1;
174 break;
175 case WI_RID_RTS_THRESH:
176 wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
177 wreq.wi_len = 1;
178 break;
179 case WI_RID_CREATE_IBSS:
180 wreq.wi_val[0] =
181 htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
182 wreq.wi_len = 1;
183 break;
184 case WI_RID_MICROWAVE_OVEN:
185 wreq.wi_val[0] = 0; /* no ... not supported */
186 wreq.wi_len = 1;
187 break;
188 case WI_RID_ROAMING_MODE:
189 wreq.wi_val[0] = htole16(1); /* enabled ... not supported */
190 wreq.wi_len = 1;
191 break;
192 case WI_RID_SYSTEM_SCALE:
193 wreq.wi_val[0] = htole16(1); /* low density ... not supp */
194 wreq.wi_len = 1;
195 break;
196 case WI_RID_PM_ENABLED:
197 wreq.wi_val[0] =
198 htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
199 wreq.wi_len = 1;
200 break;
201 case WI_RID_MAX_SLEEP:
202 wreq.wi_val[0] = htole16(ic->ic_lintval);
203 wreq.wi_len = 1;
204 break;
205 case WI_RID_CUR_BEACON_INT:
206 wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
207 wreq.wi_len = 1;
208 break;
209 case WI_RID_WEP_AVAIL:
210 wreq.wi_val[0] =
211 htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0);
212 wreq.wi_len = 1;
213 break;
214 case WI_RID_CNFAUTHMODE:
215 wreq.wi_val[0] = htole16(1); /* TODO: open system only */
216 wreq.wi_len = 1;
217 break;
218 case WI_RID_ENCRYPTION:
219 wreq.wi_val[0] =
220 htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0);
221 wreq.wi_len = 1;
222 break;
223 case WI_RID_TX_CRYPT_KEY:
224 wreq.wi_val[0] = htole16(ic->ic_wep_txkey);
225 wreq.wi_len = 1;
226 break;
227 case WI_RID_DEFLT_CRYPT_KEYS:
228 keys = (struct wi_ltv_keys *)&wreq;
229 /* do not show keys to non-root user */
230 error = suser(curthread);
231 if (error) {
232 memset(keys, 0, sizeof(*keys));
233 error = 0;
234 break;
235 }
236 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
237 keys->wi_keys[i].wi_keylen =
238 htole16(ic->ic_nw_keys[i].wk_len);
239 memcpy(keys->wi_keys[i].wi_keydat,
240 ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len);
241 }
242 wreq.wi_len = sizeof(*keys) / 2;
243 break;
244 case WI_RID_MAX_DATALEN:
245 wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN); /* TODO: frag */
246 wreq.wi_len = 1;
247 break;
248 case WI_RID_IFACE_STATS:
249 /* XXX: should be implemented in lower drivers */
250 break;
251 case WI_RID_READ_APS:
252 if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
253 /*
254 * Don't return results until active scan completes.
255 */
256 if (ic->ic_state == IEEE80211_S_SCAN &&
257 (ic->ic_flags & IEEE80211_F_ASCAN)) {
258 error = EINPROGRESS;
259 break;
260 }
261 }
262 i = 0;
263 ap = (void *)((char *)wreq.wi_val + sizeof(i));
264 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
265 if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1))
266 break;
267 memset(ap, 0, sizeof(*ap));
268 if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
269 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
270 ap->namelen = ic->ic_des_esslen;
271 if (ic->ic_des_esslen)
272 memcpy(ap->name, ic->ic_des_essid,
273 ic->ic_des_esslen);
274 } else {
275 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
276 ap->namelen = ni->ni_esslen;
277 if (ni->ni_esslen)
278 memcpy(ap->name, ni->ni_essid,
279 ni->ni_esslen);
280 }
281 ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
282 ap->signal = (*ic->ic_node_getrssi)(ic, ni);
283 ap->capinfo = ni->ni_capinfo;
284 ap->interval = ni->ni_intval;
285 rs = &ni->ni_rates;
286 for (j = 0; j < rs->rs_nrates; j++) {
287 if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
288 ap->rate = (rs->rs_rates[j] &
289 IEEE80211_RATE_VAL) * 5; /* XXX */
290 }
291 }
292 i++;
293 ap++;
294 }
295 memcpy(wreq.wi_val, &i, sizeof(i));
296 wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2;
297 break;
298 case WI_RID_PRISM2:
299 wreq.wi_val[0] = 1; /* XXX lie so SCAN_RES can give rates */
300 wreq.wi_len = sizeof(u_int16_t) / 2;
301 break;
302 case WI_RID_SCAN_RES: /* compatibility interface */
303 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
304 ic->ic_state == IEEE80211_S_SCAN) {
305 error = EINPROGRESS;
306 break;
307 }
308 /* NB: we use the Prism2 format so we can return rate info */
309 p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
310 res = (void *)&p2[1];
311 i = 0;
312 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
313 if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1))
314 break;
315 res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
316 res->wi_noise = 0;
317 res->wi_signal = (*ic->ic_node_getrssi)(ic, ni);
318 IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
319 res->wi_interval = ni->ni_intval;
320 res->wi_capinfo = ni->ni_capinfo;
321 res->wi_ssid_len = ni->ni_esslen;
322 memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
323 /* NB: assumes wi_srates holds <= ni->ni_rates */
324 memcpy(res->wi_srates, ni->ni_rates.rs_rates,
325 sizeof(res->wi_srates));
326 if (ni->ni_rates.rs_nrates < 10)
327 res->wi_srates[ni->ni_rates.rs_nrates] = 0;
328 res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
329 res->wi_rsvd = 0;
330 res++, i++;
331 }
332 p2->wi_rsvd = 0;
333 p2->wi_reason = i;
334 wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2;
335 break;
336 case WI_RID_READ_CACHE:
337 i = 0;
338 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
339 if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1)
340 break;
341 IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr);
342 memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc));
343 wsc.signal = (*ic->ic_node_getrssi)(ic, ni);
344 wsc.noise = 0;
345 wsc.quality = 0;
346 memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
347 &wsc, sizeof(wsc));
348 i++;
349 }
350 wreq.wi_len = sizeof(wsc) * i / 2;
351 break;
352 case WI_RID_SCAN_APS:
353 error = EINVAL;
354 break;
355 default:
356 error = EINVAL;
357 break;
358 }
359 if (error == 0) {
360 wreq.wi_len++;
361 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
362 }
363 return error;
364 }
365
366 static int
367 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
368 {
369 #define IEEERATE(_ic,_m,_i) \
370 ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
371 int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
372 for (i = 0; i < nrates; i++)
373 if (IEEERATE(ic, mode, i) == rate)
374 return i;
375 return -1;
376 #undef IEEERATE
377 }
378
379 /*
380 * Prepare to do a user-initiated scan for AP's. If no
381 * current/default channel is setup or the current channel
382 * is invalid then pick the first available channel from
383 * the active list as the place to start the scan.
384 */
385 static int
386 ieee80211_setupscan(struct ieee80211com *ic)
387 {
388 u_char *chanlist = ic->ic_chan_active;
389 int i;
390
391 if (ic->ic_ibss_chan == NULL ||
392 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
393 for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
394 if (isset(chanlist, i)) {
395 ic->ic_ibss_chan = &ic->ic_channels[i];
396 goto found;
397 }
398 return EINVAL; /* no active channels */
399 found:
400 ;
401 }
402 if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
403 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
404 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
405 /*
406 * XXX don't permit a scan to be started unless we
407 * know the device is ready. For the moment this means
408 * the device is marked up as this is the required to
409 * initialize the hardware. It would be better to permit
410 * scanning prior to being up but that'll require some
411 * changes to the infrastructure.
412 */
413 return (ic->ic_if.if_flags & IFF_UP) ? 0 : ENETRESET;
414 }
415
416 int
417 ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data)
418 {
419 struct ieee80211com *ic = (void *)ifp;
420 int i, j, len, error, rate;
421 struct ifreq *ifr = (struct ifreq *)data;
422 struct wi_ltv_keys *keys;
423 struct wi_req wreq;
424 u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
425
426 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
427 if (error)
428 return error;
429 len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
430 switch (wreq.wi_type) {
431 case WI_RID_SERIALNO:
432 case WI_RID_NODENAME:
433 return EPERM;
434 case WI_RID_CURRENT_SSID:
435 return EPERM;
436 case WI_RID_OWN_SSID:
437 case WI_RID_DESIRED_SSID:
438 if (le16toh(wreq.wi_val[0]) * 2 > len ||
439 le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
440 error = ENOSPC;
441 break;
442 }
443 memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
444 ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
445 memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
446 error = ENETRESET;
447 break;
448 case WI_RID_CURRENT_BSSID:
449 return EPERM;
450 case WI_RID_OWN_CHNL:
451 if (len != 2)
452 return EINVAL;
453 i = le16toh(wreq.wi_val[0]);
454 if (i < 0 ||
455 i > IEEE80211_CHAN_MAX ||
456 isclr(ic->ic_chan_active, i))
457 return EINVAL;
458 ic->ic_ibss_chan = &ic->ic_channels[i];
459 if (ic->ic_flags & IEEE80211_F_SIBSS)
460 error = ENETRESET;
461 break;
462 case WI_RID_CURRENT_CHAN:
463 return EPERM;
464 case WI_RID_COMMS_QUALITY:
465 return EPERM;
466 case WI_RID_PROMISC:
467 if (len != 2)
468 return EINVAL;
469 if (ifp->if_flags & IFF_PROMISC) {
470 if (wreq.wi_val[0] == 0) {
471 ifp->if_flags &= ~IFF_PROMISC;
472 error = ENETRESET;
473 }
474 } else {
475 if (wreq.wi_val[0] != 0) {
476 ifp->if_flags |= IFF_PROMISC;
477 error = ENETRESET;
478 }
479 }
480 break;
481 case WI_RID_PORTTYPE:
482 if (len != 2)
483 return EINVAL;
484 switch (le16toh(wreq.wi_val[0])) {
485 case IEEE80211_M_STA:
486 break;
487 case IEEE80211_M_IBSS:
488 if (!(ic->ic_caps & IEEE80211_C_IBSS))
489 return EINVAL;
490 break;
491 case IEEE80211_M_AHDEMO:
492 if (ic->ic_phytype != IEEE80211_T_DS ||
493 !(ic->ic_caps & IEEE80211_C_AHDEMO))
494 return EINVAL;
495 break;
496 case IEEE80211_M_HOSTAP:
497 if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
498 return EINVAL;
499 break;
500 default:
501 return EINVAL;
502 }
503 if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
504 ic->ic_opmode = le16toh(wreq.wi_val[0]);
505 error = ENETRESET;
506 }
507 break;
508 #if 0
509 case WI_RID_MAC_NODE:
510 if (len != IEEE80211_ADDR_LEN)
511 return EINVAL;
512 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
513 /* if_init will copy lladdr into ic_myaddr */
514 error = ENETRESET;
515 break;
516 #endif
517 case WI_RID_TX_RATE:
518 if (len != 2)
519 return EINVAL;
520 if (wreq.wi_val[0] == 0) {
521 /* auto */
522 ic->ic_fixed_rate = -1;
523 break;
524 }
525 rate = 2 * le16toh(wreq.wi_val[0]);
526 if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
527 /*
528 * In autoselect mode search for the rate. We take
529 * the first instance which may not be right, but we
530 * are limited by the interface. Note that we also
531 * lock the mode to insure the rate is meaningful
532 * when it is used.
533 */
534 for (j = IEEE80211_MODE_11A;
535 j < IEEE80211_MODE_MAX; j++) {
536 if ((ic->ic_modecaps & (1<<j)) == 0)
537 continue;
538 i = findrate(ic, j, rate);
539 if (i != -1) {
540 /* lock mode too */
541 ic->ic_curmode = j;
542 goto setrate;
543 }
544 }
545 } else {
546 i = findrate(ic, ic->ic_curmode, rate);
547 if (i != -1)
548 goto setrate;
549 }
550 return EINVAL;
551 setrate:
552 ic->ic_fixed_rate = i;
553 error = ENETRESET;
554 break;
555 case WI_RID_CUR_TX_RATE:
556 return EPERM;
557 case WI_RID_RTS_THRESH:
558 if (len != 2)
559 return EINVAL;
560 if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN)
561 return EINVAL; /* TODO: RTS */
562 break;
563 case WI_RID_CREATE_IBSS:
564 if (len != 2)
565 return EINVAL;
566 if (wreq.wi_val[0] != 0) {
567 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
568 return EINVAL;
569 if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
570 ic->ic_flags |= IEEE80211_F_IBSSON;
571 if (ic->ic_opmode == IEEE80211_M_IBSS &&
572 ic->ic_state == IEEE80211_S_SCAN)
573 error = ENETRESET;
574 }
575 } else {
576 if (ic->ic_flags & IEEE80211_F_IBSSON) {
577 ic->ic_flags &= ~IEEE80211_F_IBSSON;
578 if (ic->ic_flags & IEEE80211_F_SIBSS) {
579 ic->ic_flags &= ~IEEE80211_F_SIBSS;
580 error = ENETRESET;
581 }
582 }
583 }
584 break;
585 case WI_RID_MICROWAVE_OVEN:
586 if (len != 2)
587 return EINVAL;
588 if (wreq.wi_val[0] != 0)
589 return EINVAL; /* not supported */
590 break;
591 case WI_RID_ROAMING_MODE:
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_SYSTEM_SCALE:
598 if (len != 2)
599 return EINVAL;
600 if (le16toh(wreq.wi_val[0]) != 1)
601 return EINVAL; /* not supported */
602 break;
603 case WI_RID_PM_ENABLED:
604 if (len != 2)
605 return EINVAL;
606 if (wreq.wi_val[0] != 0) {
607 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
608 return EINVAL;
609 if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
610 ic->ic_flags |= IEEE80211_F_PMGTON;
611 error = ENETRESET;
612 }
613 } else {
614 if (ic->ic_flags & IEEE80211_F_PMGTON) {
615 ic->ic_flags &= ~IEEE80211_F_PMGTON;
616 error = ENETRESET;
617 }
618 }
619 break;
620 case WI_RID_MAX_SLEEP:
621 if (len != 2)
622 return EINVAL;
623 ic->ic_lintval = le16toh(wreq.wi_val[0]);
624 if (ic->ic_flags & IEEE80211_F_PMGTON)
625 error = ENETRESET;
626 break;
627 case WI_RID_CUR_BEACON_INT:
628 return EPERM;
629 case WI_RID_WEP_AVAIL:
630 return EPERM;
631 case WI_RID_CNFAUTHMODE:
632 if (len != 2)
633 return EINVAL;
634 if (le16toh(wreq.wi_val[0]) != 1)
635 return EINVAL; /* TODO: shared key auth */
636 break;
637 case WI_RID_ENCRYPTION:
638 if (len != 2)
639 return EINVAL;
640 if (wreq.wi_val[0] != 0) {
641 if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
642 return EINVAL;
643 if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) {
644 ic->ic_flags |= IEEE80211_F_WEPON;
645 error = ENETRESET;
646 }
647 } else {
648 if (ic->ic_flags & IEEE80211_F_WEPON) {
649 ic->ic_flags &= ~IEEE80211_F_WEPON;
650 error = ENETRESET;
651 }
652 }
653 break;
654 case WI_RID_TX_CRYPT_KEY:
655 if (len != 2)
656 return EINVAL;
657 i = le16toh(wreq.wi_val[0]);
658 if (i >= IEEE80211_WEP_NKID)
659 return EINVAL;
660 ic->ic_wep_txkey = i;
661 break;
662 case WI_RID_DEFLT_CRYPT_KEYS:
663 if (len != sizeof(struct wi_ltv_keys))
664 return EINVAL;
665 keys = (struct wi_ltv_keys *)&wreq;
666 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
667 len = le16toh(keys->wi_keys[i].wi_keylen);
668 if (len != 0 && len < IEEE80211_WEP_KEYLEN)
669 return EINVAL;
670 if (len > sizeof(ic->ic_nw_keys[i].wk_key))
671 return EINVAL;
672 }
673 memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys));
674 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
675 len = le16toh(keys->wi_keys[i].wi_keylen);
676 ic->ic_nw_keys[i].wk_len = len;
677 memcpy(ic->ic_nw_keys[i].wk_key,
678 keys->wi_keys[i].wi_keydat, len);
679 }
680 error = ENETRESET;
681 break;
682 case WI_RID_MAX_DATALEN:
683 if (len != 2)
684 return EINVAL;
685 len = le16toh(wreq.wi_val[0]);
686 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
687 return EINVAL;
688 if (len != IEEE80211_MAX_LEN)
689 return EINVAL; /* TODO: fragment */
690 ic->ic_fragthreshold = len;
691 error = ENETRESET;
692 break;
693 case WI_RID_IFACE_STATS:
694 error = EPERM;
695 break;
696 case WI_RID_SCAN_REQ: /* XXX wicontrol */
697 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
698 break;
699 error = ieee80211_setupscan(ic);
700 if (error == 0)
701 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
702 break;
703 case WI_RID_SCAN_APS:
704 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
705 break;
706 len--; /* XXX: tx rate? */
707 /* FALLTHRU */
708 case WI_RID_CHANNEL_LIST:
709 memset(chanlist, 0, sizeof(chanlist));
710 /*
711 * Since channel 0 is not available for DS, channel 1
712 * is assigned to LSB on WaveLAN.
713 */
714 if (ic->ic_phytype == IEEE80211_T_DS)
715 i = 1;
716 else
717 i = 0;
718 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
719 if ((j / 8) >= len)
720 break;
721 if (isclr((u_int8_t *)wreq.wi_val, j))
722 continue;
723 if (isclr(ic->ic_chan_active, i)) {
724 if (wreq.wi_type != WI_RID_CHANNEL_LIST)
725 continue;
726 if (isclr(ic->ic_chan_avail, i))
727 return EPERM;
728 }
729 setbit(chanlist, i);
730 }
731 memcpy(ic->ic_chan_active, chanlist,
732 sizeof(ic->ic_chan_active));
733 error = ieee80211_setupscan(ic);
734 if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
735 /* NB: ignore error from ieee80211_setupscan */
736 error = ENETRESET;
737 } else if (error == 0)
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 int
748 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
749 {
750 struct ieee80211com *ic = (void *)ifp;
751 int error = 0;
752 u_int kid, len;
753 struct ieee80211req *ireq;
754 struct ifreq *ifr;
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(curthread) == 0) {
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_IOC_RTSTHRESHOLD:
859 ireq->i_val = ic->ic_rtsthreshold;
860 break;
861 default:
862 error = EINVAL;
863 }
864 break;
865 case SIOCS80211:
866 error = suser(curthread);
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_IOC_RTSTHRESHOLD:
994 if (!(IEEE80211_RTS_MIN < ireq->i_val &&
995 ireq->i_val < IEEE80211_RTS_MAX)) {
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(curthread);
1012 if (error)
1013 break;
1014 error = ieee80211_cfgset(ifp, cmd, data);
1015 break;
1016 case SIOCG80211STATS:
1017 ifr = (struct ifreq *)data;
1018 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
1019 break;
1020 default:
1021 error = ether_ioctl(ifp, cmd, data);
1022 break;
1023 }
1024 return error;
1025 }
Cache object: f7eddfed5932e684152fec7b5f390ca3
|