Deleted Added
full compact
ieee80211_ioctl.c (127648) ieee80211_ioctl.c (138568)
1/*-
2 * Copyright (c) 2001 Atsushi Onoe
1/*-
2 * Copyright (c) 2001 Atsushi Onoe
3 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2004 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

--- 14 unchanged lines hidden (view full) ---

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>
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

--- 14 unchanged lines hidden (view full) ---

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: head/sys/net80211/ieee80211_ioctl.c 127648 2004-03-30 22:57:57Z sam $");
34__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_ioctl.c 138568 2004-12-08 17:26:47Z sam $");
35
36/*
37 * IEEE 802.11 ioctl support (FreeBSD-specific)
38 */
39
40#include "opt_inet.h"
41#include "opt_ipx.h"
42

--- 19 unchanged lines hidden (view full) ---

62#include <netipx/ipx_if.h>
63#endif
64
65#include <net80211/ieee80211_var.h>
66#include <net80211/ieee80211_ioctl.h>
67
68#include <dev/wi/if_wavelan_ieee.h>
69
35
36/*
37 * IEEE 802.11 ioctl support (FreeBSD-specific)
38 */
39
40#include "opt_inet.h"
41#include "opt_ipx.h"
42

--- 19 unchanged lines hidden (view full) ---

62#include <netipx/ipx_if.h>
63#endif
64
65#include <net80211/ieee80211_var.h>
66#include <net80211/ieee80211_ioctl.h>
67
68#include <dev/wi/if_wavelan_ieee.h>
69
70#define IS_UP(_ic) \
71 (((_ic)->ic_ifp->if_flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP))
72#define IS_UP_AUTO(_ic) \
73 (IS_UP(_ic) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO)
74
70/*
71 * XXX
72 * Wireless LAN specific configuration interface, which is compatible
73 * with wicontrol(8).
74 */
75
75/*
76 * XXX
77 * Wireless LAN specific configuration interface, which is compatible
78 * with wicontrol(8).
79 */
80
81struct wi_read_ap_args {
82 int i; /* result count */
83 struct wi_apinfo *ap; /* current entry in result buffer */
84 caddr_t max; /* result buffer bound */
85};
86
87static void
88wi_read_ap_result(void *arg, struct ieee80211_node *ni)
89{
90 struct ieee80211com *ic = ni->ni_ic;
91 struct wi_read_ap_args *sa = arg;
92 struct wi_apinfo *ap = sa->ap;
93 struct ieee80211_rateset *rs;
94 int j;
95
96 if ((caddr_t)(ap + 1) > sa->max)
97 return;
98 memset(ap, 0, sizeof(struct wi_apinfo));
99 if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
100 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
101 ap->namelen = ic->ic_des_esslen;
102 if (ic->ic_des_esslen)
103 memcpy(ap->name, ic->ic_des_essid,
104 ic->ic_des_esslen);
105 } else {
106 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
107 ap->namelen = ni->ni_esslen;
108 if (ni->ni_esslen)
109 memcpy(ap->name, ni->ni_essid,
110 ni->ni_esslen);
111 }
112 ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
113 ap->signal = ic->ic_node_getrssi(ni);
114 ap->capinfo = ni->ni_capinfo;
115 ap->interval = ni->ni_intval;
116 rs = &ni->ni_rates;
117 for (j = 0; j < rs->rs_nrates; j++) {
118 if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
119 ap->rate = (rs->rs_rates[j] &
120 IEEE80211_RATE_VAL) * 5; /* XXX */
121 }
122 }
123 sa->i++;
124 sa->ap++;
125}
126
127struct wi_read_prism2_args {
128 int i; /* result count */
129 struct wi_scan_res *res;/* current entry in result buffer */
130 caddr_t max; /* result buffer bound */
131};
132
133static void
134wi_read_prism2_result(void *arg, struct ieee80211_node *ni)
135{
136 struct ieee80211com *ic = ni->ni_ic;
137 struct wi_read_prism2_args *sa = arg;
138 struct wi_scan_res *res = sa->res;
139
140 if ((caddr_t)(res + 1) > sa->max)
141 return;
142 res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
143 res->wi_noise = 0;
144 res->wi_signal = ic->ic_node_getrssi(ni);
145 IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
146 res->wi_interval = ni->ni_intval;
147 res->wi_capinfo = ni->ni_capinfo;
148 res->wi_ssid_len = ni->ni_esslen;
149 memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
150 /* NB: assumes wi_srates holds <= ni->ni_rates */
151 memcpy(res->wi_srates, ni->ni_rates.rs_rates,
152 sizeof(res->wi_srates));
153 if (ni->ni_rates.rs_nrates < 10)
154 res->wi_srates[ni->ni_rates.rs_nrates] = 0;
155 res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
156 res->wi_rsvd = 0;
157
158 sa->i++;
159 sa->res++;
160}
161
162struct wi_read_sigcache_args {
163 int i; /* result count */
164 struct wi_sigcache *wsc;/* current entry in result buffer */
165 caddr_t max; /* result buffer bound */
166};
167
168static void
169wi_read_sigcache(void *arg, struct ieee80211_node *ni)
170{
171 struct ieee80211com *ic = ni->ni_ic;
172 struct wi_read_sigcache_args *sa = arg;
173 struct wi_sigcache *wsc = sa->wsc;
174
175 if ((caddr_t)(wsc + 1) > sa->max)
176 return;
177 memset(wsc, 0, sizeof(struct wi_sigcache));
178 IEEE80211_ADDR_COPY(wsc->macsrc, ni->ni_macaddr);
179 wsc->signal = ic->ic_node_getrssi(ni);
180
181 sa->wsc++;
182 sa->i++;
183}
184
76int
185int
77ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data)
186ieee80211_cfgget(struct ieee80211com *ic, u_long cmd, caddr_t data)
78{
187{
79 struct ieee80211com *ic = (void *)ifp;
188 struct ifnet *ifp = ic->ic_ifp;
80 int i, j, error;
81 struct ifreq *ifr = (struct ifreq *)data;
82 struct wi_req wreq;
83 struct wi_ltv_keys *keys;
189 int i, j, error;
190 struct ifreq *ifr = (struct ifreq *)data;
191 struct wi_req wreq;
192 struct wi_ltv_keys *keys;
84 struct wi_apinfo *ap;
85 struct ieee80211_node *ni;
86 struct ieee80211_rateset *rs;
87 struct wi_sigcache wsc;
88 struct wi_scan_p2_hdr *p2;
89 struct wi_scan_res *res;
90
91 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
92 if (error)
93 return error;
94 wreq.wi_len = 0;
95 switch (wreq.wi_type) {
96 case WI_RID_SERIALNO:
97 /* nothing appropriate */

--- 50 unchanged lines hidden (view full) ---

148 break;
149 case WI_RID_CURRENT_CHAN:
150 wreq.wi_val[0] = htole16(
151 ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
152 wreq.wi_len = 1;
153 break;
154 case WI_RID_COMMS_QUALITY:
155 wreq.wi_val[0] = 0; /* quality */
193
194 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
195 if (error)
196 return error;
197 wreq.wi_len = 0;
198 switch (wreq.wi_type) {
199 case WI_RID_SERIALNO:
200 /* nothing appropriate */

--- 50 unchanged lines hidden (view full) ---

251 break;
252 case WI_RID_CURRENT_CHAN:
253 wreq.wi_val[0] = htole16(
254 ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
255 wreq.wi_len = 1;
256 break;
257 case WI_RID_COMMS_QUALITY:
258 wreq.wi_val[0] = 0; /* quality */
156 wreq.wi_val[1] =
157 htole16((*ic->ic_node_getrssi)(ic, ic->ic_bss));
259 wreq.wi_val[1] = htole16(ic->ic_node_getrssi(ic->ic_bss));
158 wreq.wi_val[2] = 0; /* noise */
159 wreq.wi_len = 3;
160 break;
161 case WI_RID_PROMISC:
162 wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
163 wreq.wi_len = 1;
164 break;
165 case WI_RID_PORTTYPE:

--- 28 unchanged lines hidden (view full) ---

194 htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
195 wreq.wi_len = 1;
196 break;
197 case WI_RID_MICROWAVE_OVEN:
198 wreq.wi_val[0] = 0; /* no ... not supported */
199 wreq.wi_len = 1;
200 break;
201 case WI_RID_ROAMING_MODE:
260 wreq.wi_val[2] = 0; /* noise */
261 wreq.wi_len = 3;
262 break;
263 case WI_RID_PROMISC:
264 wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
265 wreq.wi_len = 1;
266 break;
267 case WI_RID_PORTTYPE:

--- 28 unchanged lines hidden (view full) ---

296 htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
297 wreq.wi_len = 1;
298 break;
299 case WI_RID_MICROWAVE_OVEN:
300 wreq.wi_val[0] = 0; /* no ... not supported */
301 wreq.wi_len = 1;
302 break;
303 case WI_RID_ROAMING_MODE:
202 wreq.wi_val[0] = htole16(1); /* enabled ... not supported */
304 wreq.wi_val[0] = htole16(ic->ic_roaming); /* XXX map */
203 wreq.wi_len = 1;
204 break;
205 case WI_RID_SYSTEM_SCALE:
206 wreq.wi_val[0] = htole16(1); /* low density ... not supp */
207 wreq.wi_len = 1;
208 break;
209 case WI_RID_PM_ENABLED:
210 wreq.wi_val[0] =

--- 4 unchanged lines hidden (view full) ---

215 wreq.wi_val[0] = htole16(ic->ic_lintval);
216 wreq.wi_len = 1;
217 break;
218 case WI_RID_CUR_BEACON_INT:
219 wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
220 wreq.wi_len = 1;
221 break;
222 case WI_RID_WEP_AVAIL:
305 wreq.wi_len = 1;
306 break;
307 case WI_RID_SYSTEM_SCALE:
308 wreq.wi_val[0] = htole16(1); /* low density ... not supp */
309 wreq.wi_len = 1;
310 break;
311 case WI_RID_PM_ENABLED:
312 wreq.wi_val[0] =

--- 4 unchanged lines hidden (view full) ---

317 wreq.wi_val[0] = htole16(ic->ic_lintval);
318 wreq.wi_len = 1;
319 break;
320 case WI_RID_CUR_BEACON_INT:
321 wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
322 wreq.wi_len = 1;
323 break;
324 case WI_RID_WEP_AVAIL:
223 wreq.wi_val[0] =
224 htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0);
325 wreq.wi_val[0] = htole16(1); /* always available */
225 wreq.wi_len = 1;
226 break;
227 case WI_RID_CNFAUTHMODE:
228 wreq.wi_val[0] = htole16(1); /* TODO: open system only */
229 wreq.wi_len = 1;
230 break;
231 case WI_RID_ENCRYPTION:
232 wreq.wi_val[0] =
326 wreq.wi_len = 1;
327 break;
328 case WI_RID_CNFAUTHMODE:
329 wreq.wi_val[0] = htole16(1); /* TODO: open system only */
330 wreq.wi_len = 1;
331 break;
332 case WI_RID_ENCRYPTION:
333 wreq.wi_val[0] =
233 htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0);
334 htole16((ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0);
234 wreq.wi_len = 1;
235 break;
236 case WI_RID_TX_CRYPT_KEY:
335 wreq.wi_len = 1;
336 break;
337 case WI_RID_TX_CRYPT_KEY:
237 wreq.wi_val[0] = htole16(ic->ic_wep_txkey);
338 wreq.wi_val[0] = htole16(ic->ic_def_txkey);
238 wreq.wi_len = 1;
239 break;
240 case WI_RID_DEFLT_CRYPT_KEYS:
241 keys = (struct wi_ltv_keys *)&wreq;
242 /* do not show keys to non-root user */
243 error = suser(curthread);
244 if (error) {
245 memset(keys, 0, sizeof(*keys));
246 error = 0;
247 break;
248 }
249 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
250 keys->wi_keys[i].wi_keylen =
339 wreq.wi_len = 1;
340 break;
341 case WI_RID_DEFLT_CRYPT_KEYS:
342 keys = (struct wi_ltv_keys *)&wreq;
343 /* do not show keys to non-root user */
344 error = suser(curthread);
345 if (error) {
346 memset(keys, 0, sizeof(*keys));
347 error = 0;
348 break;
349 }
350 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
351 keys->wi_keys[i].wi_keylen =
251 htole16(ic->ic_nw_keys[i].wk_len);
352 htole16(ic->ic_nw_keys[i].wk_keylen);
252 memcpy(keys->wi_keys[i].wi_keydat,
353 memcpy(keys->wi_keys[i].wi_keydat,
253 ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len);
354 ic->ic_nw_keys[i].wk_key,
355 ic->ic_nw_keys[i].wk_keylen);
254 }
255 wreq.wi_len = sizeof(*keys) / 2;
256 break;
257 case WI_RID_MAX_DATALEN:
356 }
357 wreq.wi_len = sizeof(*keys) / 2;
358 break;
359 case WI_RID_MAX_DATALEN:
258 wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN); /* TODO: frag */
360 wreq.wi_val[0] = htole16(ic->ic_fragthreshold);
259 wreq.wi_len = 1;
260 break;
261 case WI_RID_IFACE_STATS:
262 /* XXX: should be implemented in lower drivers */
263 break;
264 case WI_RID_READ_APS:
361 wreq.wi_len = 1;
362 break;
363 case WI_RID_IFACE_STATS:
364 /* XXX: should be implemented in lower drivers */
365 break;
366 case WI_RID_READ_APS:
265 if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
266 /*
267 * Don't return results until active scan completes.
268 */
269 if (ic->ic_state == IEEE80211_S_SCAN &&
270 (ic->ic_flags & IEEE80211_F_ASCAN)) {
271 error = EINPROGRESS;
272 break;
273 }
274 }
275 i = 0;
276 ap = (void *)((char *)wreq.wi_val + sizeof(i));
277 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
278 if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1))
279 break;
280 memset(ap, 0, sizeof(*ap));
281 if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
282 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
283 ap->namelen = ic->ic_des_esslen;
284 if (ic->ic_des_esslen)
285 memcpy(ap->name, ic->ic_des_essid,
286 ic->ic_des_esslen);
287 } else {
288 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
289 ap->namelen = ni->ni_esslen;
290 if (ni->ni_esslen)
291 memcpy(ap->name, ni->ni_essid,
292 ni->ni_esslen);
293 }
294 ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
295 ap->signal = (*ic->ic_node_getrssi)(ic, ni);
296 ap->capinfo = ni->ni_capinfo;
297 ap->interval = ni->ni_intval;
298 rs = &ni->ni_rates;
299 for (j = 0; j < rs->rs_nrates; j++) {
300 if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
301 ap->rate = (rs->rs_rates[j] &
302 IEEE80211_RATE_VAL) * 5; /* XXX */
303 }
304 }
305 i++;
306 ap++;
307 }
308 memcpy(wreq.wi_val, &i, sizeof(i));
309 wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2;
367 /*
368 * Don't return results until active scan completes.
369 */
370 if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) {
371 struct wi_read_ap_args args;
372
373 args.i = 0;
374 args.ap = (void *)((char *)wreq.wi_val + sizeof(i));
375 args.max = (void *)(&wreq + 1);
376 ieee80211_iterate_nodes(&ic->ic_scan,
377 wi_read_ap_result, &args);
378 memcpy(wreq.wi_val, &args.i, sizeof(args.i));
379 wreq.wi_len = (sizeof(int) +
380 sizeof(struct wi_apinfo) * args.i) / 2;
381 } else
382 error = EINPROGRESS;
310 break;
311 case WI_RID_PRISM2:
383 break;
384 case WI_RID_PRISM2:
312 wreq.wi_val[0] = 1; /* XXX lie so SCAN_RES can give rates */
385 /* NB: we lie so WI_RID_SCAN_RES can include rates */
386 wreq.wi_val[0] = 1;
313 wreq.wi_len = sizeof(u_int16_t) / 2;
314 break;
315 case WI_RID_SCAN_RES: /* compatibility interface */
387 wreq.wi_len = sizeof(u_int16_t) / 2;
388 break;
389 case WI_RID_SCAN_RES: /* compatibility interface */
316 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
317 ic->ic_state == IEEE80211_S_SCAN &&
318 (ic->ic_flags & IEEE80211_F_ASCAN)) {
390 if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) {
391 struct wi_read_prism2_args args;
392 struct wi_scan_p2_hdr *p2;
393
394 /* NB: use Prism2 format so we can include rate info */
395 p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
396 args.i = 0;
397 args.res = (void *)&p2[1];
398 args.max = (void *)(&wreq + 1);
399 ieee80211_iterate_nodes(&ic->ic_scan,
400 wi_read_prism2_result, &args);
401 p2->wi_rsvd = 0;
402 p2->wi_reason = args.i;
403 wreq.wi_len = (sizeof(*p2) +
404 sizeof(struct wi_scan_res) * args.i) / 2;
405 } else
319 error = EINPROGRESS;
406 error = EINPROGRESS;
320 break;
321 }
322 /* NB: we use the Prism2 format so we can return rate info */
323 p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
324 res = (void *)&p2[1];
325 i = 0;
326 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
327 if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1))
328 break;
329 res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
330 res->wi_noise = 0;
331 res->wi_signal = (*ic->ic_node_getrssi)(ic, ni);
332 IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
333 res->wi_interval = ni->ni_intval;
334 res->wi_capinfo = ni->ni_capinfo;
335 res->wi_ssid_len = ni->ni_esslen;
336 memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
337 /* NB: assumes wi_srates holds <= ni->ni_rates */
338 memcpy(res->wi_srates, ni->ni_rates.rs_rates,
339 sizeof(res->wi_srates));
340 if (ni->ni_rates.rs_nrates < 10)
341 res->wi_srates[ni->ni_rates.rs_nrates] = 0;
342 res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
343 res->wi_rsvd = 0;
344 res++, i++;
345 }
346 p2->wi_rsvd = 0;
347 p2->wi_reason = i;
348 wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2;
349 break;
407 break;
350 case WI_RID_READ_CACHE:
351 i = 0;
352 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
353 if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1)
354 break;
355 IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr);
356 memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc));
357 wsc.signal = (*ic->ic_node_getrssi)(ic, ni);
358 wsc.noise = 0;
359 wsc.quality = 0;
360 memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
361 &wsc, sizeof(wsc));
362 i++;
363 }
364 wreq.wi_len = sizeof(wsc) * i / 2;
408 case WI_RID_READ_CACHE: {
409 struct wi_read_sigcache_args args;
410 args.i = 0;
411 args.wsc = (struct wi_sigcache *) wreq.wi_val;
412 args.max = (void *)(&wreq + 1);
413 ieee80211_iterate_nodes(&ic->ic_scan, wi_read_sigcache, &args);
414 wreq.wi_len = sizeof(struct wi_sigcache) * args.i / 2;
365 break;
415 break;
366 case WI_RID_SCAN_APS:
367 error = EINVAL;
368 break;
416 }
369 default:
370 error = EINVAL;
371 break;
372 }
373 if (error == 0) {
374 wreq.wi_len++;
375 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
376 }

--- 15 unchanged lines hidden (view full) ---

392
393/*
394 * Prepare to do a user-initiated scan for AP's. If no
395 * current/default channel is setup or the current channel
396 * is invalid then pick the first available channel from
397 * the active list as the place to start the scan.
398 */
399static int
417 default:
418 error = EINVAL;
419 break;
420 }
421 if (error == 0) {
422 wreq.wi_len++;
423 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
424 }

--- 15 unchanged lines hidden (view full) ---

440
441/*
442 * Prepare to do a user-initiated scan for AP's. If no
443 * current/default channel is setup or the current channel
444 * is invalid then pick the first available channel from
445 * the active list as the place to start the scan.
446 */
447static int
400ieee80211_setupscan(struct ieee80211com *ic)
448ieee80211_setupscan(struct ieee80211com *ic, const u_int8_t chanlist[])
401{
449{
402 u_char *chanlist = ic->ic_chan_active;
403 int i;
404
450 int i;
451
452 /*
453 * XXX don't permit a scan to be started unless we
454 * know the device is ready. For the moment this means
455 * the device is marked up as this is the required to
456 * initialize the hardware. It would be better to permit
457 * scanning prior to being up but that'll require some
458 * changes to the infrastructure.
459 */
460 if (!IS_UP(ic))
461 return EINVAL;
405 if (ic->ic_ibss_chan == NULL ||
406 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
407 for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
408 if (isset(chanlist, i)) {
409 ic->ic_ibss_chan = &ic->ic_channels[i];
410 goto found;
411 }
412 return EINVAL; /* no active channels */
413found:
414 ;
415 }
416 if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
417 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
418 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
462 if (ic->ic_ibss_chan == NULL ||
463 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
464 for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
465 if (isset(chanlist, i)) {
466 ic->ic_ibss_chan = &ic->ic_channels[i];
467 goto found;
468 }
469 return EINVAL; /* no active channels */
470found:
471 ;
472 }
473 if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
474 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
475 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
476 memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
419 /*
477 /*
420 * XXX don't permit a scan to be started unless we
421 * know the device is ready. For the moment this means
422 * the device is marked up as this is the required to
423 * initialize the hardware. It would be better to permit
424 * scanning prior to being up but that'll require some
425 * changes to the infrastructure.
478 * We force the state to INIT before calling ieee80211_new_state
479 * to get ieee80211_begin_scan called. We really want to scan w/o
480 * altering the current state but that's not possible right now.
426 */
481 */
427 return (ic->ic_if.if_flags & IFF_UP) ? 0 : ENETRESET;
482 /* XXX handle proberequest case */
483 ic->ic_state = IEEE80211_S_INIT; /* XXX bypass state machine */
484 return 0;
428}
429
430int
485}
486
487int
431ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data)
488ieee80211_cfgset(struct ieee80211com *ic, u_long cmd, caddr_t data)
432{
489{
433 struct ieee80211com *ic = (void *)ifp;
490 struct ifnet *ifp = ic->ic_ifp;
434 int i, j, len, error, rate;
435 struct ifreq *ifr = (struct ifreq *)data;
436 struct wi_ltv_keys *keys;
437 struct wi_req wreq;
438 u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
439
440 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
441 if (error)

--- 23 unchanged lines hidden (view full) ---

465 if (len != 2)
466 return EINVAL;
467 i = le16toh(wreq.wi_val[0]);
468 if (i < 0 ||
469 i > IEEE80211_CHAN_MAX ||
470 isclr(ic->ic_chan_active, i))
471 return EINVAL;
472 ic->ic_ibss_chan = &ic->ic_channels[i];
491 int i, j, len, error, rate;
492 struct ifreq *ifr = (struct ifreq *)data;
493 struct wi_ltv_keys *keys;
494 struct wi_req wreq;
495 u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
496
497 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
498 if (error)

--- 23 unchanged lines hidden (view full) ---

522 if (len != 2)
523 return EINVAL;
524 i = le16toh(wreq.wi_val[0]);
525 if (i < 0 ||
526 i > IEEE80211_CHAN_MAX ||
527 isclr(ic->ic_chan_active, i))
528 return EINVAL;
529 ic->ic_ibss_chan = &ic->ic_channels[i];
473 if (ic->ic_flags & IEEE80211_F_SIBSS)
530 if (ic->ic_opmode == IEEE80211_M_MONITOR)
531 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
532 else
474 error = ENETRESET;
475 break;
476 case WI_RID_CURRENT_CHAN:
477 return EPERM;
478 case WI_RID_COMMS_QUALITY:
479 return EPERM;
480 case WI_RID_PROMISC:
481 if (len != 2)

--- 29 unchanged lines hidden (view full) ---

511 if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
512 return EINVAL;
513 break;
514 default:
515 return EINVAL;
516 }
517 if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
518 ic->ic_opmode = le16toh(wreq.wi_val[0]);
533 error = ENETRESET;
534 break;
535 case WI_RID_CURRENT_CHAN:
536 return EPERM;
537 case WI_RID_COMMS_QUALITY:
538 return EPERM;
539 case WI_RID_PROMISC:
540 if (len != 2)

--- 29 unchanged lines hidden (view full) ---

570 if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
571 return EINVAL;
572 break;
573 default:
574 return EINVAL;
575 }
576 if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
577 ic->ic_opmode = le16toh(wreq.wi_val[0]);
519 error = ENETRESET;
578 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
520 }
521 break;
522#if 0
523 case WI_RID_MAC_NODE:
524 if (len != IEEE80211_ADDR_LEN)
525 return EINVAL;
526 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
527 /* if_init will copy lladdr into ic_myaddr */

--- 31 unchanged lines hidden (view full) ---

559 } else {
560 i = findrate(ic, ic->ic_curmode, rate);
561 if (i != -1)
562 goto setrate;
563 }
564 return EINVAL;
565 setrate:
566 ic->ic_fixed_rate = i;
579 }
580 break;
581#if 0
582 case WI_RID_MAC_NODE:
583 if (len != IEEE80211_ADDR_LEN)
584 return EINVAL;
585 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
586 /* if_init will copy lladdr into ic_myaddr */

--- 31 unchanged lines hidden (view full) ---

618 } else {
619 i = findrate(ic, ic->ic_curmode, rate);
620 if (i != -1)
621 goto setrate;
622 }
623 return EINVAL;
624 setrate:
625 ic->ic_fixed_rate = i;
567 error = ENETRESET;
626 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
568 break;
569 case WI_RID_CUR_TX_RATE:
570 return EPERM;
571 case WI_RID_RTS_THRESH:
572 if (len != 2)
573 return EINVAL;
574 if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN)
575 return EINVAL; /* TODO: RTS */
576 break;
577 case WI_RID_CREATE_IBSS:
578 if (len != 2)
579 return EINVAL;
580 if (wreq.wi_val[0] != 0) {
581 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
582 return EINVAL;
583 if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
584 ic->ic_flags |= IEEE80211_F_IBSSON;
585 if (ic->ic_opmode == IEEE80211_M_IBSS &&
586 ic->ic_state == IEEE80211_S_SCAN)
627 break;
628 case WI_RID_CUR_TX_RATE:
629 return EPERM;
630 case WI_RID_RTS_THRESH:
631 if (len != 2)
632 return EINVAL;
633 if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN)
634 return EINVAL; /* TODO: RTS */
635 break;
636 case WI_RID_CREATE_IBSS:
637 if (len != 2)
638 return EINVAL;
639 if (wreq.wi_val[0] != 0) {
640 if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
641 return EINVAL;
642 if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
643 ic->ic_flags |= IEEE80211_F_IBSSON;
644 if (ic->ic_opmode == IEEE80211_M_IBSS &&
645 ic->ic_state == IEEE80211_S_SCAN)
587 error = ENETRESET;
646 error = IS_UP_AUTO(ic) ? ENETRESET : 0;
588 }
589 } else {
590 if (ic->ic_flags & IEEE80211_F_IBSSON) {
591 ic->ic_flags &= ~IEEE80211_F_IBSSON;
592 if (ic->ic_flags & IEEE80211_F_SIBSS) {
593 ic->ic_flags &= ~IEEE80211_F_SIBSS;
647 }
648 } else {
649 if (ic->ic_flags & IEEE80211_F_IBSSON) {
650 ic->ic_flags &= ~IEEE80211_F_IBSSON;
651 if (ic->ic_flags & IEEE80211_F_SIBSS) {
652 ic->ic_flags &= ~IEEE80211_F_SIBSS;
594 error = ENETRESET;
653 error = IS_UP_AUTO(ic) ? ENETRESET : 0;
595 }
596 }
597 }
598 break;
599 case WI_RID_MICROWAVE_OVEN:
600 if (len != 2)
601 return EINVAL;
602 if (wreq.wi_val[0] != 0)
603 return EINVAL; /* not supported */
604 break;
605 case WI_RID_ROAMING_MODE:
606 if (len != 2)
607 return EINVAL;
654 }
655 }
656 }
657 break;
658 case WI_RID_MICROWAVE_OVEN:
659 if (len != 2)
660 return EINVAL;
661 if (wreq.wi_val[0] != 0)
662 return EINVAL; /* not supported */
663 break;
664 case WI_RID_ROAMING_MODE:
665 if (len != 2)
666 return EINVAL;
608 if (le16toh(wreq.wi_val[0]) != 1)
667 i = le16toh(wreq.wi_val[0]);
668 if (i > IEEE80211_ROAMING_MANUAL)
609 return EINVAL; /* not supported */
669 return EINVAL; /* not supported */
670 ic->ic_roaming = i;
610 break;
611 case WI_RID_SYSTEM_SCALE:
612 if (len != 2)
613 return EINVAL;
614 if (le16toh(wreq.wi_val[0]) != 1)
615 return EINVAL; /* not supported */
616 break;
617 case WI_RID_PM_ENABLED:
618 if (len != 2)
619 return EINVAL;
620 if (wreq.wi_val[0] != 0) {
621 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
622 return EINVAL;
623 if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
624 ic->ic_flags |= IEEE80211_F_PMGTON;
671 break;
672 case WI_RID_SYSTEM_SCALE:
673 if (len != 2)
674 return EINVAL;
675 if (le16toh(wreq.wi_val[0]) != 1)
676 return EINVAL; /* not supported */
677 break;
678 case WI_RID_PM_ENABLED:
679 if (len != 2)
680 return EINVAL;
681 if (wreq.wi_val[0] != 0) {
682 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
683 return EINVAL;
684 if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
685 ic->ic_flags |= IEEE80211_F_PMGTON;
625 error = ENETRESET;
686 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
626 }
627 } else {
628 if (ic->ic_flags & IEEE80211_F_PMGTON) {
629 ic->ic_flags &= ~IEEE80211_F_PMGTON;
687 }
688 } else {
689 if (ic->ic_flags & IEEE80211_F_PMGTON) {
690 ic->ic_flags &= ~IEEE80211_F_PMGTON;
630 error = ENETRESET;
691 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
631 }
632 }
633 break;
634 case WI_RID_MAX_SLEEP:
635 if (len != 2)
636 return EINVAL;
637 ic->ic_lintval = le16toh(wreq.wi_val[0]);
638 if (ic->ic_flags & IEEE80211_F_PMGTON)
692 }
693 }
694 break;
695 case WI_RID_MAX_SLEEP:
696 if (len != 2)
697 return EINVAL;
698 ic->ic_lintval = le16toh(wreq.wi_val[0]);
699 if (ic->ic_flags & IEEE80211_F_PMGTON)
639 error = ENETRESET;
700 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
640 break;
641 case WI_RID_CUR_BEACON_INT:
642 return EPERM;
643 case WI_RID_WEP_AVAIL:
644 return EPERM;
645 case WI_RID_CNFAUTHMODE:
646 if (len != 2)
647 return EINVAL;
701 break;
702 case WI_RID_CUR_BEACON_INT:
703 return EPERM;
704 case WI_RID_WEP_AVAIL:
705 return EPERM;
706 case WI_RID_CNFAUTHMODE:
707 if (len != 2)
708 return EINVAL;
648 if (le16toh(wreq.wi_val[0]) != 1)
649 return EINVAL; /* TODO: shared key auth */
709 i = le16toh(wreq.wi_val[0]);
710 if (i > IEEE80211_AUTH_WPA)
711 return EINVAL;
712 ic->ic_bss->ni_authmode = i; /* XXX ENETRESET? */
713 error = ENETRESET;
650 break;
651 case WI_RID_ENCRYPTION:
652 if (len != 2)
653 return EINVAL;
654 if (wreq.wi_val[0] != 0) {
655 if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
656 return EINVAL;
714 break;
715 case WI_RID_ENCRYPTION:
716 if (len != 2)
717 return EINVAL;
718 if (wreq.wi_val[0] != 0) {
719 if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
720 return EINVAL;
657 if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) {
658 ic->ic_flags |= IEEE80211_F_WEPON;
721 if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
722 ic->ic_flags |= IEEE80211_F_PRIVACY;
659 error = ENETRESET;
660 }
661 } else {
723 error = ENETRESET;
724 }
725 } else {
662 if (ic->ic_flags & IEEE80211_F_WEPON) {
663 ic->ic_flags &= ~IEEE80211_F_WEPON;
726 if (ic->ic_flags & IEEE80211_F_PRIVACY) {
727 ic->ic_flags &= ~IEEE80211_F_PRIVACY;
664 error = ENETRESET;
665 }
666 }
667 break;
668 case WI_RID_TX_CRYPT_KEY:
669 if (len != 2)
670 return EINVAL;
671 i = le16toh(wreq.wi_val[0]);
672 if (i >= IEEE80211_WEP_NKID)
673 return EINVAL;
728 error = ENETRESET;
729 }
730 }
731 break;
732 case WI_RID_TX_CRYPT_KEY:
733 if (len != 2)
734 return EINVAL;
735 i = le16toh(wreq.wi_val[0]);
736 if (i >= IEEE80211_WEP_NKID)
737 return EINVAL;
674 ic->ic_wep_txkey = i;
738 ic->ic_def_txkey = i;
739 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
675 break;
676 case WI_RID_DEFLT_CRYPT_KEYS:
677 if (len != sizeof(struct wi_ltv_keys))
678 return EINVAL;
679 keys = (struct wi_ltv_keys *)&wreq;
680 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
681 len = le16toh(keys->wi_keys[i].wi_keylen);
682 if (len != 0 && len < IEEE80211_WEP_KEYLEN)
683 return EINVAL;
740 break;
741 case WI_RID_DEFLT_CRYPT_KEYS:
742 if (len != sizeof(struct wi_ltv_keys))
743 return EINVAL;
744 keys = (struct wi_ltv_keys *)&wreq;
745 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
746 len = le16toh(keys->wi_keys[i].wi_keylen);
747 if (len != 0 && len < IEEE80211_WEP_KEYLEN)
748 return EINVAL;
684 if (len > sizeof(ic->ic_nw_keys[i].wk_key))
749 if (len > IEEE80211_KEYBUF_SIZE)
685 return EINVAL;
686 }
750 return EINVAL;
751 }
687 memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys));
688 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
752 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
753 struct ieee80211_key *k = &ic->ic_nw_keys[i];
754
689 len = le16toh(keys->wi_keys[i].wi_keylen);
755 len = le16toh(keys->wi_keys[i].wi_keylen);
690 ic->ic_nw_keys[i].wk_len = len;
691 memcpy(ic->ic_nw_keys[i].wk_key,
692 keys->wi_keys[i].wi_keydat, len);
756 k->wk_keylen = len;
757 k->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
758 memset(k->wk_key, 0, sizeof(k->wk_key));
759 memcpy(k->wk_key, keys->wi_keys[i].wi_keydat, len);
760#if 0
761 k->wk_type = IEEE80211_CIPHER_WEP;
762#endif
693 }
694 error = ENETRESET;
695 break;
696 case WI_RID_MAX_DATALEN:
697 if (len != 2)
698 return EINVAL;
699 len = le16toh(wreq.wi_val[0]);
700 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
701 return EINVAL;
763 }
764 error = ENETRESET;
765 break;
766 case WI_RID_MAX_DATALEN:
767 if (len != 2)
768 return EINVAL;
769 len = le16toh(wreq.wi_val[0]);
770 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
771 return EINVAL;
702 if (len != IEEE80211_MAX_LEN)
703 return EINVAL; /* TODO: fragment */
704 ic->ic_fragthreshold = len;
772 ic->ic_fragthreshold = len;
705 error = ENETRESET;
773 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
706 break;
707 case WI_RID_IFACE_STATS:
708 error = EPERM;
709 break;
710 case WI_RID_SCAN_REQ: /* XXX wicontrol */
711 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
712 break;
774 break;
775 case WI_RID_IFACE_STATS:
776 error = EPERM;
777 break;
778 case WI_RID_SCAN_REQ: /* XXX wicontrol */
779 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
780 break;
713 error = ieee80211_setupscan(ic);
781 error = ieee80211_setupscan(ic, ic->ic_chan_avail);
714 if (error == 0)
715 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
716 break;
717 case WI_RID_SCAN_APS:
718 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
719 break;
720 len--; /* XXX: tx rate? */
721 /* FALLTHRU */

--- 15 unchanged lines hidden (view full) ---

737 if (isclr(ic->ic_chan_active, i)) {
738 if (wreq.wi_type != WI_RID_CHANNEL_LIST)
739 continue;
740 if (isclr(ic->ic_chan_avail, i))
741 return EPERM;
742 }
743 setbit(chanlist, i);
744 }
782 if (error == 0)
783 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
784 break;
785 case WI_RID_SCAN_APS:
786 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
787 break;
788 len--; /* XXX: tx rate? */
789 /* FALLTHRU */

--- 15 unchanged lines hidden (view full) ---

805 if (isclr(ic->ic_chan_active, i)) {
806 if (wreq.wi_type != WI_RID_CHANNEL_LIST)
807 continue;
808 if (isclr(ic->ic_chan_avail, i))
809 return EPERM;
810 }
811 setbit(chanlist, i);
812 }
745 memcpy(ic->ic_chan_active, chanlist,
746 sizeof(ic->ic_chan_active));
747 error = ieee80211_setupscan(ic);
813 error = ieee80211_setupscan(ic, chanlist);
748 if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
749 /* NB: ignore error from ieee80211_setupscan */
750 error = ENETRESET;
751 } else if (error == 0)
752 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
753 break;
754 default:
755 error = EINVAL;
756 break;
757 }
814 if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
815 /* NB: ignore error from ieee80211_setupscan */
816 error = ENETRESET;
817 } else if (error == 0)
818 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
819 break;
820 default:
821 error = EINVAL;
822 break;
823 }
824 if (error == ENETRESET && !IS_UP_AUTO(ic))
825 error = 0;
758 return error;
759}
760
826 return error;
827}
828
761int
762ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
829static struct ieee80211_channel *
830getcurchan(struct ieee80211com *ic)
763{
831{
764 struct ieee80211com *ic = (void *)ifp;
832 switch (ic->ic_state) {
833 case IEEE80211_S_INIT:
834 case IEEE80211_S_SCAN:
835 return ic->ic_des_chan;
836 default:
837 return ic->ic_ibss_chan;
838 }
839}
840
841static int
842cap2cipher(int flag)
843{
844 switch (flag) {
845 case IEEE80211_C_WEP: return IEEE80211_CIPHER_WEP;
846 case IEEE80211_C_AES: return IEEE80211_CIPHER_AES_OCB;
847 case IEEE80211_C_AES_CCM: return IEEE80211_CIPHER_AES_CCM;
848 case IEEE80211_C_CKIP: return IEEE80211_CIPHER_CKIP;
849 case IEEE80211_C_TKIP: return IEEE80211_CIPHER_TKIP;
850 }
851 return -1;
852}
853
854static int
855ieee80211_ioctl_getkey(struct ieee80211com *ic, struct ieee80211req *ireq)
856{
857 struct ieee80211_node *ni;
858 struct ieee80211req_key ik;
859 struct ieee80211_key *wk;
860 const struct ieee80211_cipher *cip;
861 u_int kid;
862 int error;
863
864 if (ireq->i_len != sizeof(ik))
865 return EINVAL;
866 error = copyin(ireq->i_data, &ik, sizeof(ik));
867 if (error)
868 return error;
869 kid = ik.ik_keyix;
870 if (kid == IEEE80211_KEYIX_NONE) {
871 if (ic->ic_sta == NULL)
872 return EINVAL;
873 ni = ieee80211_find_node(ic->ic_sta, ik.ik_macaddr);
874 if (ni == NULL)
875 return EINVAL; /* XXX */
876 wk = &ni->ni_ucastkey;
877 } else {
878 if (kid >= IEEE80211_WEP_NKID)
879 return EINVAL;
880 wk = &ic->ic_nw_keys[kid];
881 IEEE80211_ADDR_COPY(&ik.ik_macaddr, ic->ic_bss->ni_macaddr);
882 ni = NULL;
883 }
884 cip = wk->wk_cipher;
885 ik.ik_type = cip->ic_cipher;
886 ik.ik_keylen = wk->wk_keylen;
887 ik.ik_flags = wk->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
888 if (wk->wk_keyix == ic->ic_def_txkey)
889 ik.ik_flags |= IEEE80211_KEY_DEFAULT;
890 if (suser(curthread) == 0) {
891 /* NB: only root can read key data */
892 ik.ik_keyrsc = wk->wk_keyrsc;
893 ik.ik_keytsc = wk->wk_keytsc;
894 memcpy(ik.ik_keydata, wk->wk_key, wk->wk_keylen);
895 if (cip->ic_cipher == IEEE80211_CIPHER_TKIP) {
896 memcpy(ik.ik_keydata+wk->wk_keylen,
897 wk->wk_key + IEEE80211_KEYBUF_SIZE,
898 IEEE80211_MICBUF_SIZE);
899 ik.ik_keylen += IEEE80211_MICBUF_SIZE;
900 }
901 } else {
902 ik.ik_keyrsc = 0;
903 ik.ik_keytsc = 0;
904 memset(ik.ik_keydata, 0, sizeof(ik.ik_keydata));
905 }
906 if (ni != NULL)
907 ieee80211_free_node(ni);
908 return copyout(&ik, ireq->i_data, sizeof(ik));
909}
910
911static int
912ieee80211_ioctl_getchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
913{
914
915 if (sizeof(ic->ic_chan_active) > ireq->i_len)
916 ireq->i_len = sizeof(ic->ic_chan_active);
917 return copyout(&ic->ic_chan_active, ireq->i_data, ireq->i_len);
918}
919
920static int
921ieee80211_ioctl_getchaninfo(struct ieee80211com *ic, struct ieee80211req *ireq)
922{
923 struct ieee80211req_chaninfo chans; /* XXX off stack? */
924 int i, space;
925
926 /*
927 * Since channel 0 is not available for DS, channel 1
928 * is assigned to LSB on WaveLAN.
929 */
930 if (ic->ic_phytype == IEEE80211_T_DS)
931 i = 1;
932 else
933 i = 0;
934 memset(&chans, 0, sizeof(chans));
935 for (; i <= IEEE80211_CHAN_MAX; i++)
936 if (isset(ic->ic_chan_avail, i)) {
937 struct ieee80211_channel *c = &ic->ic_channels[i];
938 chans.ic_chans[chans.ic_nchans].ic_freq = c->ic_freq;
939 chans.ic_chans[chans.ic_nchans].ic_flags = c->ic_flags;
940 chans.ic_nchans++;
941 }
942 space = __offsetof(struct ieee80211req_chaninfo,
943 ic_chans[chans.ic_nchans]);
944 if (space > ireq->i_len)
945 space = ireq->i_len;
946 return copyout(&chans, ireq->i_data, space);
947}
948
949static int
950ieee80211_ioctl_getwpaie(struct ieee80211com *ic, struct ieee80211req *ireq)
951{
952 struct ieee80211_node *ni;
953 struct ieee80211req_wpaie wpaie;
954 int error;
955
956 if (ireq->i_len < IEEE80211_ADDR_LEN)
957 return EINVAL;
958 error = copyin(ireq->i_data, wpaie.wpa_macaddr, IEEE80211_ADDR_LEN);
959 if (error != 0)
960 return error;
961 if (ic->ic_sta == NULL)
962 return EINVAL;
963 ni = ieee80211_find_node(ic->ic_sta, wpaie.wpa_macaddr);
964 if (ni == NULL)
965 return EINVAL; /* XXX */
966 memset(wpaie.wpa_ie, 0, sizeof(wpaie.wpa_ie));
967 if (ni->ni_wpa_ie != NULL) {
968 int ielen = ni->ni_wpa_ie[1] + 2;
969 if (ielen > sizeof(wpaie.wpa_ie))
970 ielen = sizeof(wpaie.wpa_ie);
971 memcpy(wpaie.wpa_ie, ni->ni_wpa_ie, ielen);
972 }
973 ieee80211_free_node(ni);
974 if (ireq->i_len > sizeof(wpaie))
975 ireq->i_len = sizeof(wpaie);
976 return copyout(&wpaie, ireq->i_data, ireq->i_len);
977}
978
979static int
980ieee80211_ioctl_getstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
981{
982 struct ieee80211_node *ni;
983 u_int8_t macaddr[IEEE80211_ADDR_LEN];
984 const int off = __offsetof(struct ieee80211req_sta_stats, is_stats);
985 int error;
986
987 if (ireq->i_len < off)
988 return EINVAL;
989 error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
990 if (error != 0)
991 return error;
992 if (ic->ic_sta == NULL)
993 return EINVAL;
994 ni = ieee80211_find_node(ic->ic_sta, macaddr);
995 if (ni == NULL)
996 return EINVAL; /* XXX */
997 if (ireq->i_len > sizeof(struct ieee80211req_sta_stats))
998 ireq->i_len = sizeof(struct ieee80211req_sta_stats);
999 /* NB: copy out only the statistics */
1000 error = copyout(&ni->ni_stats, (u_int8_t *) ireq->i_data + off,
1001 ireq->i_len - off);
1002 ieee80211_free_node(ni);
1003 return error;
1004}
1005
1006static void
1007get_scan_result(struct ieee80211req_scan_result *sr,
1008 const struct ieee80211_node *ni)
1009{
1010 struct ieee80211com *ic = ni->ni_ic;
1011
1012 memset(sr, 0, sizeof(*sr));
1013 sr->isr_ssid_len = ni->ni_esslen;
1014 if (ni->ni_wpa_ie != NULL)
1015 sr->isr_ie_len += 2+ni->ni_wpa_ie[1];
1016 if (ni->ni_wme_ie != NULL)
1017 sr->isr_ie_len += 2+ni->ni_wme_ie[1];
1018 sr->isr_len = sizeof(*sr) + sr->isr_ssid_len + sr->isr_ie_len;
1019 sr->isr_len = roundup(sr->isr_len, sizeof(u_int32_t));
1020 if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
1021 sr->isr_freq = ni->ni_chan->ic_freq;
1022 sr->isr_flags = ni->ni_chan->ic_flags;
1023 }
1024 sr->isr_rssi = ic->ic_node_getrssi(ni);
1025 sr->isr_intval = ni->ni_intval;
1026 sr->isr_capinfo = ni->ni_capinfo;
1027 sr->isr_erp = ni->ni_erp;
1028 IEEE80211_ADDR_COPY(sr->isr_bssid, ni->ni_bssid);
1029 sr->isr_nrates = ni->ni_rates.rs_nrates;
1030 if (sr->isr_nrates > 15)
1031 sr->isr_nrates = 15;
1032 memcpy(sr->isr_rates, ni->ni_rates.rs_rates, sr->isr_nrates);
1033}
1034
1035static int
1036ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq)
1037{
1038 union {
1039 struct ieee80211req_scan_result res;
1040 char data[512]; /* XXX shrink? */
1041 } u;
1042 struct ieee80211req_scan_result *sr = &u.res;
1043 struct ieee80211_node_table *nt;
1044 struct ieee80211_node *ni;
1045 int error, space;
1046 u_int8_t *p, *cp;
1047
1048 p = ireq->i_data;
1049 space = ireq->i_len;
1050 error = 0;
1051 /* XXX locking */
1052 nt = &ic->ic_scan;
1053 TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
1054 /* NB: skip pre-scan node state */
1055 if (ni->ni_chan == IEEE80211_CHAN_ANYC)
1056 continue;
1057 get_scan_result(sr, ni);
1058 if (sr->isr_len > sizeof(u))
1059 continue; /* XXX */
1060 if (space < sr->isr_len)
1061 break;
1062 cp = (u_int8_t *)(sr+1);
1063 memcpy(cp, ni->ni_essid, ni->ni_esslen);
1064 cp += ni->ni_esslen;
1065 if (ni->ni_wpa_ie != NULL) {
1066 memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
1067 cp += 2+ni->ni_wpa_ie[1];
1068 }
1069 if (ni->ni_wme_ie != NULL) {
1070 memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
1071 cp += 2+ni->ni_wme_ie[1];
1072 }
1073 error = copyout(sr, p, sr->isr_len);
1074 if (error)
1075 break;
1076 p += sr->isr_len;
1077 space -= sr->isr_len;
1078 }
1079 ireq->i_len -= space;
1080 return error;
1081}
1082
1083static void
1084get_sta_info(struct ieee80211req_sta_info *si, const struct ieee80211_node *ni)
1085{
1086 struct ieee80211com *ic = ni->ni_ic;
1087
1088 si->isi_ie_len = 0;
1089 if (ni->ni_wpa_ie != NULL)
1090 si->isi_ie_len += 2+ni->ni_wpa_ie[1];
1091 if (ni->ni_wme_ie != NULL)
1092 si->isi_ie_len += 2+ni->ni_wme_ie[1];
1093 si->isi_len = sizeof(*si) + si->isi_ie_len, sizeof(u_int32_t);
1094 si->isi_len = roundup(si->isi_len, sizeof(u_int32_t));
1095 si->isi_freq = ni->ni_chan->ic_freq;
1096 si->isi_flags = ni->ni_chan->ic_flags;
1097 si->isi_state = ni->ni_flags;
1098 si->isi_authmode = ni->ni_authmode;
1099 si->isi_rssi = ic->ic_node_getrssi(ni);
1100 si->isi_capinfo = ni->ni_capinfo;
1101 si->isi_erp = ni->ni_erp;
1102 IEEE80211_ADDR_COPY(si->isi_macaddr, ni->ni_macaddr);
1103 si->isi_nrates = ni->ni_rates.rs_nrates;
1104 if (si->isi_nrates > 15)
1105 si->isi_nrates = 15;
1106 memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates);
1107 si->isi_txrate = ni->ni_txrate;
1108 si->isi_associd = ni->ni_associd;
1109 si->isi_txpower = ni->ni_txpower;
1110 si->isi_vlan = ni->ni_vlan;
1111 if (ni->ni_flags & IEEE80211_NODE_QOS) {
1112 memcpy(si->isi_txseqs, ni->ni_txseqs, sizeof(ni->ni_txseqs));
1113 memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs));
1114 } else {
1115 si->isi_txseqs[0] = ni->ni_txseqs[0];
1116 si->isi_rxseqs[0] = ni->ni_rxseqs[0];
1117 }
1118 if (ic->ic_opmode == IEEE80211_M_IBSS || ni->ni_associd != 0)
1119 si->isi_inact = ic->ic_inact_run;
1120 else if (ieee80211_node_is_authorized(ni))
1121 si->isi_inact = ic->ic_inact_auth;
1122 else
1123 si->isi_inact = ic->ic_inact_init;
1124 si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
1125}
1126
1127static int
1128ieee80211_ioctl_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
1129{
1130 union {
1131 struct ieee80211req_sta_info info;
1132 char data[512]; /* XXX shrink? */
1133 } u;
1134 struct ieee80211req_sta_info *si = &u.info;
1135 struct ieee80211_node_table *nt;
1136 struct ieee80211_node *ni;
1137 int error, space;
1138 u_int8_t *p, *cp;
1139
1140 nt = ic->ic_sta;
1141 if (nt == NULL)
1142 return EINVAL;
1143 p = ireq->i_data;
1144 space = ireq->i_len;
1145 error = 0;
1146 /* XXX locking */
1147 TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
1148 get_sta_info(si, ni);
1149 if (si->isi_len > sizeof(u))
1150 continue; /* XXX */
1151 if (space < si->isi_len)
1152 break;
1153 cp = (u_int8_t *)(si+1);
1154 if (ni->ni_wpa_ie != NULL) {
1155 memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
1156 cp += 2+ni->ni_wpa_ie[1];
1157 }
1158 if (ni->ni_wme_ie != NULL) {
1159 memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
1160 cp += 2+ni->ni_wme_ie[1];
1161 }
1162 error = copyout(si, p, si->isi_len);
1163 if (error)
1164 break;
1165 p += si->isi_len;
1166 space -= si->isi_len;
1167 }
1168 ireq->i_len -= space;
1169 return error;
1170}
1171
1172static int
1173ieee80211_ioctl_getstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
1174{
1175 struct ieee80211_node *ni;
1176 struct ieee80211req_sta_txpow txpow;
1177 int error;
1178
1179 if (ireq->i_len != sizeof(txpow))
1180 return EINVAL;
1181 error = copyin(ireq->i_data, &txpow, sizeof(txpow));
1182 if (error != 0)
1183 return error;
1184 if (ic->ic_sta == NULL)
1185 return EINVAL;
1186 ni = ieee80211_find_node(ic->ic_sta, txpow.it_macaddr);
1187 if (ni == NULL)
1188 return EINVAL; /* XXX */
1189 txpow.it_txpow = ni->ni_txpower;
1190 error = copyout(&txpow, ireq->i_data, sizeof(txpow));
1191 ieee80211_free_node(ni);
1192 return error;
1193}
1194
1195static int
1196ieee80211_ioctl_getwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
1197{
1198 struct ieee80211_wme_state *wme = &ic->ic_wme;
1199 struct wmeParams *wmep;
1200 int ac;
1201
1202 if ((ic->ic_caps & IEEE80211_C_WME) == 0)
1203 return EINVAL;
1204
1205 ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
1206 if (ac >= WME_NUM_AC)
1207 ac = WME_AC_BE;
1208 if (ireq->i_len & IEEE80211_WMEPARAM_BSS)
1209 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1210 else
1211 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1212 switch (ireq->i_type) {
1213 case IEEE80211_IOC_WME_CWMIN: /* WME: CWmin */
1214 ireq->i_val = wmep->wmep_logcwmin;
1215 break;
1216 case IEEE80211_IOC_WME_CWMAX: /* WME: CWmax */
1217 ireq->i_val = wmep->wmep_logcwmax;
1218 break;
1219 case IEEE80211_IOC_WME_AIFS: /* WME: AIFS */
1220 ireq->i_val = wmep->wmep_aifsn;
1221 break;
1222 case IEEE80211_IOC_WME_TXOPLIMIT: /* WME: txops limit */
1223 ireq->i_val = wmep->wmep_txopLimit;
1224 break;
1225 case IEEE80211_IOC_WME_ACM: /* WME: ACM (bss only) */
1226 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1227 ireq->i_val = wmep->wmep_acm;
1228 break;
1229 case IEEE80211_IOC_WME_ACKPOLICY: /* WME: ACK policy (!bss only)*/
1230 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1231 ireq->i_val = !wmep->wmep_noackPolicy;
1232 break;
1233 }
1234 return 0;
1235}
1236
1237static int
1238ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
1239{
1240 const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
765 int error = 0;
1241 int error = 0;
766 u_int kid, len;
767 struct ieee80211req *ireq;
768 struct ifreq *ifr;
1242 u_int kid, len, m;
769 u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
770 char tmpssid[IEEE80211_NWID_LEN];
1243 u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
1244 char tmpssid[IEEE80211_NWID_LEN];
771 struct ieee80211_channel *chan;
772 struct ifaddr *ifa; /* XXX */
773
1245
774 switch (cmd) {
775 case SIOCSIFMEDIA:
776 case SIOCGIFMEDIA:
777 error = ifmedia_ioctl(ifp, (struct ifreq *) data,
778 &ic->ic_media, cmd);
779 break;
780 case SIOCG80211:
781 ireq = (struct ieee80211req *) data;
782 switch (ireq->i_type) {
783 case IEEE80211_IOC_SSID:
784 switch (ic->ic_state) {
785 case IEEE80211_S_INIT:
786 case IEEE80211_S_SCAN:
787 ireq->i_len = ic->ic_des_esslen;
788 memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
789 break;
790 default:
791 ireq->i_len = ic->ic_bss->ni_esslen;
792 memcpy(tmpssid, ic->ic_bss->ni_essid,
793 ireq->i_len);
794 break;
795 }
796 error = copyout(tmpssid, ireq->i_data, ireq->i_len);
1246 switch (ireq->i_type) {
1247 case IEEE80211_IOC_SSID:
1248 switch (ic->ic_state) {
1249 case IEEE80211_S_INIT:
1250 case IEEE80211_S_SCAN:
1251 ireq->i_len = ic->ic_des_esslen;
1252 memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
797 break;
1253 break;
798 case IEEE80211_IOC_NUMSSIDS:
1254 default:
1255 ireq->i_len = ic->ic_bss->ni_esslen;
1256 memcpy(tmpssid, ic->ic_bss->ni_essid,
1257 ireq->i_len);
1258 break;
1259 }
1260 error = copyout(tmpssid, ireq->i_data, ireq->i_len);
1261 break;
1262 case IEEE80211_IOC_NUMSSIDS:
1263 ireq->i_val = 1;
1264 break;
1265 case IEEE80211_IOC_WEP:
1266 if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0)
1267 ireq->i_val = IEEE80211_WEP_OFF;
1268 else if (ic->ic_flags & IEEE80211_F_DROPUNENC)
1269 ireq->i_val = IEEE80211_WEP_ON;
1270 else
1271 ireq->i_val = IEEE80211_WEP_MIXED;
1272 break;
1273 case IEEE80211_IOC_WEPKEY:
1274 kid = (u_int) ireq->i_val;
1275 if (kid >= IEEE80211_WEP_NKID)
1276 return EINVAL;
1277 len = (u_int) ic->ic_nw_keys[kid].wk_keylen;
1278 /* NB: only root can read WEP keys */
1279 if (suser(curthread) == 0) {
1280 bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
1281 } else {
1282 bzero(tmpkey, len);
1283 }
1284 ireq->i_len = len;
1285 error = copyout(tmpkey, ireq->i_data, len);
1286 break;
1287 case IEEE80211_IOC_NUMWEPKEYS:
1288 ireq->i_val = IEEE80211_WEP_NKID;
1289 break;
1290 case IEEE80211_IOC_WEPTXKEY:
1291 ireq->i_val = ic->ic_def_txkey;
1292 break;
1293 case IEEE80211_IOC_AUTHMODE:
1294 if (ic->ic_flags & IEEE80211_F_WPA)
1295 ireq->i_val = IEEE80211_AUTH_WPA;
1296 else
1297 ireq->i_val = ic->ic_bss->ni_authmode;
1298 break;
1299 case IEEE80211_IOC_CHANNEL:
1300 ireq->i_val = ieee80211_chan2ieee(ic, getcurchan(ic));
1301 break;
1302 case IEEE80211_IOC_POWERSAVE:
1303 if (ic->ic_flags & IEEE80211_F_PMGTON)
1304 ireq->i_val = IEEE80211_POWERSAVE_ON;
1305 else
1306 ireq->i_val = IEEE80211_POWERSAVE_OFF;
1307 break;
1308 case IEEE80211_IOC_POWERSAVESLEEP:
1309 ireq->i_val = ic->ic_lintval;
1310 break;
1311 case IEEE80211_IOC_RTSTHRESHOLD:
1312 ireq->i_val = ic->ic_rtsthreshold;
1313 break;
1314 case IEEE80211_IOC_PROTMODE:
1315 ireq->i_val = ic->ic_protmode;
1316 break;
1317 case IEEE80211_IOC_TXPOWER:
1318 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
1319 return EINVAL;
1320 ireq->i_val = ic->ic_txpowlimit;
1321 break;
1322 case IEEE80211_IOC_MCASTCIPHER:
1323 ireq->i_val = rsn->rsn_mcastcipher;
1324 break;
1325 case IEEE80211_IOC_MCASTKEYLEN:
1326 ireq->i_val = rsn->rsn_mcastkeylen;
1327 break;
1328 case IEEE80211_IOC_UCASTCIPHERS:
1329 ireq->i_val = 0;
1330 for (m = 0x1; m != 0; m <<= 1)
1331 if (rsn->rsn_ucastcipherset & m)
1332 ireq->i_val |= 1<<cap2cipher(m);
1333 break;
1334 case IEEE80211_IOC_UCASTCIPHER:
1335 ireq->i_val = rsn->rsn_ucastcipher;
1336 break;
1337 case IEEE80211_IOC_UCASTKEYLEN:
1338 ireq->i_val = rsn->rsn_ucastkeylen;
1339 break;
1340 case IEEE80211_IOC_KEYMGTALGS:
1341 ireq->i_val = rsn->rsn_keymgmtset;
1342 break;
1343 case IEEE80211_IOC_RSNCAPS:
1344 ireq->i_val = rsn->rsn_caps;
1345 break;
1346 case IEEE80211_IOC_WPA:
1347 switch (ic->ic_flags & IEEE80211_F_WPA) {
1348 case IEEE80211_F_WPA1:
799 ireq->i_val = 1;
800 break;
1349 ireq->i_val = 1;
1350 break;
801 case IEEE80211_IOC_WEP:
802 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
803 ireq->i_val = IEEE80211_WEP_NOSUP;
804 } else {
805 if (ic->ic_flags & IEEE80211_F_WEPON) {
806 ireq->i_val =
807 IEEE80211_WEP_MIXED;
808 } else {
809 ireq->i_val =
810 IEEE80211_WEP_OFF;
811 }
812 }
1351 case IEEE80211_F_WPA2:
1352 ireq->i_val = 2;
813 break;
1353 break;
814 case IEEE80211_IOC_WEPKEY:
815 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
816 error = EINVAL;
817 break;
818 }
819 kid = (u_int) ireq->i_val;
820 if (kid >= IEEE80211_WEP_NKID) {
821 error = EINVAL;
822 break;
823 }
824 len = (u_int) ic->ic_nw_keys[kid].wk_len;
825 /* NB: only root can read WEP keys */
826 if (suser(curthread) == 0) {
827 bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
828 } else {
829 bzero(tmpkey, len);
830 }
831 ireq->i_len = len;
832 error = copyout(tmpkey, ireq->i_data, len);
1354 case IEEE80211_F_WPA1 | IEEE80211_F_WPA2:
1355 ireq->i_val = 3;
833 break;
1356 break;
834 case IEEE80211_IOC_NUMWEPKEYS:
835 if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
836 error = EINVAL;
837 else
838 ireq->i_val = IEEE80211_WEP_NKID;
1357 default:
1358 ireq->i_val = 0;
839 break;
1359 break;
840 case IEEE80211_IOC_WEPTXKEY:
841 if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
842 error = EINVAL;
843 else
844 ireq->i_val = ic->ic_wep_txkey;
1360 }
1361 break;
1362 case IEEE80211_IOC_CHANLIST:
1363 error = ieee80211_ioctl_getchanlist(ic, ireq);
1364 break;
1365 case IEEE80211_IOC_ROAMING:
1366 ireq->i_val = ic->ic_roaming;
1367 break;
1368 case IEEE80211_IOC_PRIVACY:
1369 ireq->i_val = (ic->ic_flags & IEEE80211_F_PRIVACY) != 0;
1370 break;
1371 case IEEE80211_IOC_DROPUNENCRYPTED:
1372 ireq->i_val = (ic->ic_flags & IEEE80211_F_DROPUNENC) != 0;
1373 break;
1374 case IEEE80211_IOC_COUNTERMEASURES:
1375 ireq->i_val = (ic->ic_flags & IEEE80211_F_COUNTERM) != 0;
1376 break;
1377 case IEEE80211_IOC_DRIVER_CAPS:
1378 ireq->i_val = ic->ic_caps>>16;
1379 ireq->i_len = ic->ic_caps&0xffff;
1380 break;
1381 case IEEE80211_IOC_WME:
1382 ireq->i_val = (ic->ic_flags & IEEE80211_F_WME) != 0;
1383 break;
1384 case IEEE80211_IOC_HIDESSID:
1385 ireq->i_val = (ic->ic_flags & IEEE80211_F_HIDESSID) != 0;
1386 break;
1387 case IEEE80211_IOC_APBRIDGE:
1388 ireq->i_val = (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0;
1389 break;
1390 case IEEE80211_IOC_OPTIE:
1391 if (ic->ic_opt_ie == NULL)
1392 return EINVAL;
1393 /* NB: truncate, caller can check length */
1394 if (ireq->i_len > ic->ic_opt_ie_len)
1395 ireq->i_len = ic->ic_opt_ie_len;
1396 error = copyout(ic->ic_opt_ie, ireq->i_data, ireq->i_len);
1397 break;
1398 case IEEE80211_IOC_WPAKEY:
1399 error = ieee80211_ioctl_getkey(ic, ireq);
1400 break;
1401 case IEEE80211_IOC_CHANINFO:
1402 error = ieee80211_ioctl_getchaninfo(ic, ireq);
1403 break;
1404 case IEEE80211_IOC_BSSID:
1405 if (ireq->i_len != IEEE80211_ADDR_LEN)
1406 return EINVAL;
1407 error = copyout(ic->ic_state == IEEE80211_S_RUN ?
1408 ic->ic_bss->ni_bssid :
1409 ic->ic_des_bssid,
1410 ireq->i_data, ireq->i_len);
1411 break;
1412 case IEEE80211_IOC_WPAIE:
1413 error = ieee80211_ioctl_getwpaie(ic, ireq);
1414 break;
1415 case IEEE80211_IOC_SCAN_RESULTS:
1416 error = ieee80211_ioctl_getscanresults(ic, ireq);
1417 break;
1418 case IEEE80211_IOC_STA_STATS:
1419 error = ieee80211_ioctl_getstastats(ic, ireq);
1420 break;
1421 case IEEE80211_IOC_TXPOWMAX:
1422 ireq->i_val = ic->ic_bss->ni_txpower;
1423 break;
1424 case IEEE80211_IOC_STA_TXPOW:
1425 error = ieee80211_ioctl_getstatxpow(ic, ireq);
1426 break;
1427 case IEEE80211_IOC_STA_INFO:
1428 error = ieee80211_ioctl_getstainfo(ic, ireq);
1429 break;
1430 case IEEE80211_IOC_WME_CWMIN: /* WME: CWmin */
1431 case IEEE80211_IOC_WME_CWMAX: /* WME: CWmax */
1432 case IEEE80211_IOC_WME_AIFS: /* WME: AIFS */
1433 case IEEE80211_IOC_WME_TXOPLIMIT: /* WME: txops limit */
1434 case IEEE80211_IOC_WME_ACM: /* WME: ACM (bss only) */
1435 case IEEE80211_IOC_WME_ACKPOLICY: /* WME: ACK policy (bss only) */
1436 error = ieee80211_ioctl_getwmeparam(ic, ireq);
1437 break;
1438 case IEEE80211_IOC_DTIM_PERIOD:
1439 ireq->i_val = ic->ic_dtim_period;
1440 break;
1441 case IEEE80211_IOC_BEACON_INTERVAL:
1442 /* NB: get from ic_bss for station mode */
1443 ireq->i_val = ic->ic_bss->ni_intval;
1444 break;
1445 default:
1446 error = EINVAL;
1447 break;
1448 }
1449 return error;
1450}
1451
1452static int
1453ieee80211_ioctl_setoptie(struct ieee80211com *ic, struct ieee80211req *ireq)
1454{
1455 int error;
1456 void *ie;
1457
1458 /*
1459 * NB: Doing this for ap operation could be useful (e.g. for
1460 * WPA and/or WME) except that it typically is worthless
1461 * without being able to intervene when processing
1462 * association response frames--so disallow it for now.
1463 */
1464 if (ic->ic_opmode != IEEE80211_M_STA)
1465 return EINVAL;
1466 if (ireq->i_len > IEEE80211_MAX_OPT_IE)
1467 return EINVAL;
1468 /* NB: data.length is validated by the wireless extensions code */
1469 MALLOC(ie, void *, ireq->i_len, M_DEVBUF, M_WAITOK);
1470 if (ie == NULL)
1471 return ENOMEM;
1472 error = copyin(ireq->i_data, ie, ireq->i_len);
1473 /* XXX sanity check data? */
1474 if (ic->ic_opt_ie != NULL)
1475 FREE(ic->ic_opt_ie, M_DEVBUF);
1476 ic->ic_opt_ie = ie;
1477 ic->ic_opt_ie_len = ireq->i_len;
1478 return 0;
1479}
1480
1481static int
1482ieee80211_ioctl_setkey(struct ieee80211com *ic, struct ieee80211req *ireq)
1483{
1484 struct ieee80211req_key ik;
1485 struct ieee80211_node *ni;
1486 struct ieee80211_key *wk;
1487 u_int16_t kid;
1488 int error;
1489
1490 if (ireq->i_len != sizeof(ik))
1491 return EINVAL;
1492 error = copyin(ireq->i_data, &ik, sizeof(ik));
1493 if (error)
1494 return error;
1495 /* NB: cipher support is verified by ieee80211_crypt_newkey */
1496 /* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */
1497 if (ik.ik_keylen > sizeof(ik.ik_keydata))
1498 return E2BIG;
1499 kid = ik.ik_keyix;
1500 if (kid == IEEE80211_KEYIX_NONE) {
1501 /* XXX unicast keys currently must be tx/rx */
1502 if (ik.ik_flags != (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))
1503 return EINVAL;
1504 if (ic->ic_opmode == IEEE80211_M_STA) {
1505 ni = ic->ic_bss;
1506 if (!IEEE80211_ADDR_EQ(ik.ik_macaddr, ni->ni_bssid))
1507 return EADDRNOTAVAIL;
1508 } else {
1509 if (ic->ic_sta == NULL)
1510 return EINVAL;
1511 ni = ieee80211_find_node(ic->ic_sta, ik.ik_macaddr);
1512 if (ni == NULL)
1513 return ENOENT;
1514 }
1515 wk = &ni->ni_ucastkey;
1516 } else {
1517 if (kid >= IEEE80211_WEP_NKID)
1518 return EINVAL;
1519 wk = &ic->ic_nw_keys[kid];
1520 ni = NULL;
1521 }
1522 error = 0;
1523 ieee80211_key_update_begin(ic);
1524 if (ieee80211_crypto_newkey(ic, ik.ik_type, wk)) {
1525 wk->wk_keylen = ik.ik_keylen;
1526 /* NB: MIC presence is implied by cipher type */
1527 if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
1528 wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
1529 wk->wk_keyrsc = ik.ik_keyrsc;
1530 wk->wk_keytsc = 0; /* new key, reset */
1531 wk->wk_flags |=
1532 ik.ik_flags & (IEEE80211_KEY_XMIT|IEEE80211_KEY_RECV);
1533 memset(wk->wk_key, 0, sizeof(wk->wk_key));
1534 memcpy(wk->wk_key, ik.ik_keydata, ik.ik_keylen);
1535 if (!ieee80211_crypto_setkey(ic, wk,
1536 ni != NULL ? ni->ni_macaddr : ik.ik_macaddr))
1537 error = EIO;
1538 else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT))
1539 ic->ic_def_txkey = kid;
1540 } else
1541 error = ENXIO;
1542 ieee80211_key_update_end(ic);
1543 if (ni != NULL)
1544 ieee80211_free_node(ni);
1545 return error;
1546}
1547
1548static int
1549ieee80211_ioctl_delkey(struct ieee80211com *ic, struct ieee80211req *ireq)
1550{
1551 struct ieee80211req_del_key dk;
1552 int kid, error;
1553
1554 if (ireq->i_len != sizeof(dk))
1555 return EINVAL;
1556 error = copyin(ireq->i_data, &dk, sizeof(dk));
1557 if (error)
1558 return error;
1559 kid = dk.idk_keyix;
1560 /* XXX u_int8_t -> u_int16_t */
1561 if (dk.idk_keyix == (u_int8_t) IEEE80211_KEYIX_NONE) {
1562 struct ieee80211_node *ni;
1563
1564 if (ic->ic_sta == NULL)
1565 return EINVAL;
1566 ni = ieee80211_find_node(ic->ic_sta, dk.idk_macaddr);
1567 if (ni == NULL)
1568 return EINVAL; /* XXX */
1569 /* XXX error return */
1570 ieee80211_crypto_delkey(ic, &ni->ni_ucastkey);
1571 ieee80211_free_node(ni);
1572 } else {
1573 if (kid >= IEEE80211_WEP_NKID)
1574 return EINVAL;
1575 /* XXX error return */
1576 ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[kid]);
1577 }
1578 return 0;
1579}
1580
1581static void
1582domlme(void *arg, struct ieee80211_node *ni)
1583{
1584 struct ieee80211com *ic = ni->ni_ic;
1585 struct ieee80211req_mlme *mlme = arg;
1586
1587 if (ni->ni_associd != 0) {
1588 IEEE80211_SEND_MGMT(ic, ni,
1589 mlme->im_op == IEEE80211_MLME_DEAUTH ?
1590 IEEE80211_FC0_SUBTYPE_DEAUTH :
1591 IEEE80211_FC0_SUBTYPE_DISASSOC,
1592 mlme->im_reason);
1593 }
1594 ieee80211_node_leave(ic, ni);
1595}
1596
1597static int
1598ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq)
1599{
1600 struct ieee80211req_mlme mlme;
1601 struct ieee80211_node *ni;
1602 int error;
1603
1604 if (ireq->i_len != sizeof(mlme))
1605 return EINVAL;
1606 error = copyin(ireq->i_data, &mlme, sizeof(mlme));
1607 if (error)
1608 return error;
1609 switch (mlme.im_op) {
1610 case IEEE80211_MLME_ASSOC:
1611 if (ic->ic_opmode != IEEE80211_M_STA)
1612 return EINVAL;
1613 /* XXX must be in S_SCAN state? */
1614
1615 if (ic->ic_des_esslen != 0) {
1616 /*
1617 * Desired ssid specified; must match both bssid and
1618 * ssid to distinguish ap advertising multiple ssid's.
1619 */
1620 ni = ieee80211_find_node_with_ssid(&ic->ic_scan,
1621 mlme.im_macaddr,
1622 ic->ic_des_esslen, ic->ic_des_essid);
1623 } else {
1624 /*
1625 * Normal case; just match bssid.
1626 */
1627 ni = ieee80211_find_node(&ic->ic_scan, mlme.im_macaddr);
1628 }
1629 if (ni == NULL)
1630 return EINVAL;
1631 if (!ieee80211_sta_join(ic, ni)) {
1632 ieee80211_free_node(ni);
1633 return EINVAL;
1634 }
1635 break;
1636 case IEEE80211_MLME_DISASSOC:
1637 case IEEE80211_MLME_DEAUTH:
1638 switch (ic->ic_opmode) {
1639 case IEEE80211_M_STA:
1640 /* XXX not quite right */
1641 ieee80211_new_state(ic, IEEE80211_S_INIT,
1642 mlme.im_reason);
845 break;
1643 break;
846 case IEEE80211_IOC_AUTHMODE:
847 ireq->i_val = IEEE80211_AUTH_OPEN;
1644 case IEEE80211_M_HOSTAP:
1645 /* NB: the broadcast address means do 'em all */
1646 if (!IEEE80211_ADDR_EQ(mlme.im_macaddr, ic->ic_ifp->if_broadcastaddr)) {
1647 if (ic->ic_sta == NULL ||
1648 (ni = ieee80211_find_node(ic->ic_sta,
1649 mlme.im_macaddr)) == NULL)
1650 return EINVAL;
1651 domlme(&mlme, ni);
1652 ieee80211_free_node(ni);
1653 } else {
1654 if (ic->ic_sta != NULL)
1655 ieee80211_iterate_nodes(ic->ic_sta,
1656 domlme, &mlme);
1657 }
848 break;
1658 break;
849 case IEEE80211_IOC_CHANNEL:
850 switch (ic->ic_state) {
851 case IEEE80211_S_INIT:
852 case IEEE80211_S_SCAN:
853 if (ic->ic_opmode == IEEE80211_M_STA)
854 chan = ic->ic_des_chan;
855 else
856 chan = ic->ic_ibss_chan;
857 break;
858 default:
859 chan = ic->ic_bss->ni_chan;
860 break;
1659 default:
1660 return EINVAL;
1661 }
1662 break;
1663 case IEEE80211_MLME_AUTHORIZE:
1664 case IEEE80211_MLME_UNAUTHORIZE:
1665 if (ic->ic_opmode != IEEE80211_M_HOSTAP)
1666 return EINVAL;
1667 if (ic->ic_sta == NULL)
1668 return EINVAL;
1669 ni = ieee80211_find_node(ic->ic_sta, mlme.im_macaddr);
1670 if (ni == NULL)
1671 return EINVAL;
1672 if (mlme.im_op == IEEE80211_MLME_AUTHORIZE)
1673 ieee80211_node_authorize(ic, ni);
1674 else
1675 ieee80211_node_unauthorize(ic, ni);
1676 ieee80211_free_node(ni);
1677 break;
1678 default:
1679 return EINVAL;
1680 }
1681 return 0;
1682}
1683
1684static int
1685ieee80211_ioctl_macmac(struct ieee80211com *ic, struct ieee80211req *ireq)
1686{
1687 u_int8_t mac[IEEE80211_ADDR_LEN];
1688 const struct ieee80211_aclator *acl = ic->ic_acl;
1689 int error;
1690
1691 if (ireq->i_len != sizeof(mac))
1692 return EINVAL;
1693 error = copyin(ireq->i_data, mac, ireq->i_len);
1694 if (error)
1695 return error;
1696 if (acl == NULL) {
1697 acl = ieee80211_aclator_get("mac");
1698 if (acl == NULL || !acl->iac_attach(ic))
1699 return EINVAL;
1700 ic->ic_acl = acl;
1701 }
1702 if (ireq->i_type == IEEE80211_IOC_ADDMAC)
1703 acl->iac_add(ic, mac);
1704 else
1705 acl->iac_remove(ic, mac);
1706 return 0;
1707}
1708
1709static int
1710ieee80211_ioctl_maccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
1711{
1712 const struct ieee80211_aclator *acl = ic->ic_acl;
1713
1714 switch (ireq->i_val) {
1715 case IEEE80211_MACCMD_POLICY_OPEN:
1716 case IEEE80211_MACCMD_POLICY_ALLOW:
1717 case IEEE80211_MACCMD_POLICY_DENY:
1718 if (acl == NULL) {
1719 acl = ieee80211_aclator_get("mac");
1720 if (acl == NULL || !acl->iac_attach(ic))
1721 return EINVAL;
1722 ic->ic_acl = acl;
1723 }
1724 acl->iac_setpolicy(ic, ireq->i_val);
1725 break;
1726 case IEEE80211_MACCMD_FLUSH:
1727 if (acl != NULL)
1728 acl->iac_flush(ic);
1729 /* NB: silently ignore when not in use */
1730 break;
1731 case IEEE80211_MACCMD_DETACH:
1732 if (acl != NULL) {
1733 ic->ic_acl = NULL;
1734 acl->iac_detach(ic);
1735 }
1736 break;
1737 default:
1738 return EINVAL;
1739 }
1740 return 0;
1741}
1742
1743static int
1744ieee80211_ioctl_setchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
1745{
1746 struct ieee80211req_chanlist list;
1747 u_char chanlist[IEEE80211_CHAN_BYTES];
1748 int i, j, error;
1749
1750 if (ireq->i_len != sizeof(list))
1751 return EINVAL;
1752 error = copyin(ireq->i_data, &list, sizeof(list));
1753 if (error)
1754 return error;
1755 memset(chanlist, 0, sizeof(chanlist));
1756 /*
1757 * Since channel 0 is not available for DS, channel 1
1758 * is assigned to LSB on WaveLAN.
1759 */
1760 if (ic->ic_phytype == IEEE80211_T_DS)
1761 i = 1;
1762 else
1763 i = 0;
1764 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
1765 /*
1766 * NB: silently discard unavailable channels so users
1767 * can specify 1-255 to get all available channels.
1768 */
1769 if (isset(list.ic_channels, j) && isset(ic->ic_chan_avail, i))
1770 setbit(chanlist, i);
1771 }
1772 if (ic->ic_ibss_chan == NULL ||
1773 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
1774 for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
1775 if (isset(chanlist, i)) {
1776 ic->ic_ibss_chan = &ic->ic_channels[i];
1777 goto found;
861 }
1778 }
862 ireq->i_val = ieee80211_chan2ieee(ic, chan);
1779 return EINVAL; /* no active channels */
1780found:
1781 ;
1782 }
1783 memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
1784 if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
1785 isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
1786 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
1787 return IS_UP_AUTO(ic) ? ENETRESET : 0;
1788}
1789
1790static int
1791ieee80211_ioctl_setstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
1792{
1793 struct ieee80211_node *ni;
1794 struct ieee80211req_sta_txpow txpow;
1795 int error;
1796
1797 if (ireq->i_len != sizeof(txpow))
1798 return EINVAL;
1799 error = copyin(ireq->i_data, &txpow, sizeof(txpow));
1800 if (error != 0)
1801 return error;
1802 if (ic->ic_sta == NULL)
1803 return EINVAL;
1804 ni = ieee80211_find_node(ic->ic_sta, txpow.it_macaddr);
1805 if (ni == NULL)
1806 return EINVAL; /* XXX */
1807 ni->ni_txpower = txpow.it_txpow;
1808 ieee80211_free_node(ni);
1809 return error;
1810}
1811
1812static int
1813ieee80211_ioctl_setwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
1814{
1815 struct ieee80211_wme_state *wme = &ic->ic_wme;
1816 struct wmeParams *wmep, *chanp;
1817 int isbss, ac;
1818
1819 if ((ic->ic_caps & IEEE80211_C_WME) == 0)
1820 return EINVAL;
1821
1822 isbss = (ireq->i_len & IEEE80211_WMEPARAM_BSS);
1823 ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
1824 if (ac >= WME_NUM_AC)
1825 ac = WME_AC_BE;
1826 if (isbss) {
1827 chanp = &wme->wme_bssChanParams.cap_wmeParams[ac];
1828 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1829 } else {
1830 chanp = &wme->wme_chanParams.cap_wmeParams[ac];
1831 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1832 }
1833 switch (ireq->i_type) {
1834 case IEEE80211_IOC_WME_CWMIN: /* WME: CWmin */
1835 if (isbss) {
1836 wmep->wmep_logcwmin = ireq->i_val;
1837 if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1838 chanp->wmep_logcwmin = ireq->i_val;
1839 } else {
1840 wmep->wmep_logcwmin = chanp->wmep_logcwmin =
1841 ireq->i_val;
1842 }
1843 break;
1844 case IEEE80211_IOC_WME_CWMAX: /* WME: CWmax */
1845 if (isbss) {
1846 wmep->wmep_logcwmax = ireq->i_val;
1847 if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1848 chanp->wmep_logcwmax = ireq->i_val;
1849 } else {
1850 wmep->wmep_logcwmax = chanp->wmep_logcwmax =
1851 ireq->i_val;
1852 }
1853 break;
1854 case IEEE80211_IOC_WME_AIFS: /* WME: AIFS */
1855 if (isbss) {
1856 wmep->wmep_aifsn = ireq->i_val;
1857 if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1858 chanp->wmep_aifsn = ireq->i_val;
1859 } else {
1860 wmep->wmep_aifsn = chanp->wmep_aifsn = ireq->i_val;
1861 }
1862 break;
1863 case IEEE80211_IOC_WME_TXOPLIMIT: /* WME: txops limit */
1864 if (isbss) {
1865 wmep->wmep_txopLimit = ireq->i_val;
1866 if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1867 chanp->wmep_txopLimit = ireq->i_val;
1868 } else {
1869 wmep->wmep_txopLimit = chanp->wmep_txopLimit =
1870 ireq->i_val;
1871 }
1872 break;
1873 case IEEE80211_IOC_WME_ACM: /* WME: ACM (bss only) */
1874 wmep->wmep_acm = ireq->i_val;
1875 if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1876 chanp->wmep_acm = ireq->i_val;
1877 break;
1878 case IEEE80211_IOC_WME_ACKPOLICY: /* WME: ACK policy (!bss only)*/
1879 wmep->wmep_noackPolicy = chanp->wmep_noackPolicy =
1880 (ireq->i_val) == 0;
1881 break;
1882 }
1883 ieee80211_wme_updateparams(ic);
1884 return 0;
1885}
1886
1887static int
1888cipher2cap(int cipher)
1889{
1890 switch (cipher) {
1891 case IEEE80211_CIPHER_WEP: return IEEE80211_C_WEP;
1892 case IEEE80211_CIPHER_AES_OCB: return IEEE80211_C_AES;
1893 case IEEE80211_CIPHER_AES_CCM: return IEEE80211_C_AES_CCM;
1894 case IEEE80211_CIPHER_CKIP: return IEEE80211_C_CKIP;
1895 case IEEE80211_CIPHER_TKIP: return IEEE80211_C_TKIP;
1896 }
1897 return 0;
1898}
1899
1900static int
1901ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
1902{
1903 static const u_int8_t zerobssid[IEEE80211_ADDR_LEN];
1904 struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
1905 int error;
1906 const struct ieee80211_authenticator *auth;
1907 u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
1908 char tmpssid[IEEE80211_NWID_LEN];
1909 u_int8_t tmpbssid[IEEE80211_ADDR_LEN];
1910 struct ieee80211_key *k;
1911 int j, caps;
1912 u_int kid;
1913
1914 error = 0;
1915 switch (ireq->i_type) {
1916 case IEEE80211_IOC_SSID:
1917 if (ireq->i_val != 0 ||
1918 ireq->i_len > IEEE80211_NWID_LEN)
1919 return EINVAL;
1920 error = copyin(ireq->i_data, tmpssid, ireq->i_len);
1921 if (error)
863 break;
1922 break;
864 case IEEE80211_IOC_POWERSAVE:
865 if (ic->ic_flags & IEEE80211_F_PMGTON)
866 ireq->i_val = IEEE80211_POWERSAVE_ON;
867 else
868 ireq->i_val = IEEE80211_POWERSAVE_OFF;
1923 memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
1924 ic->ic_des_esslen = ireq->i_len;
1925 memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
1926 error = ENETRESET;
1927 break;
1928 case IEEE80211_IOC_WEP:
1929 switch (ireq->i_val) {
1930 case IEEE80211_WEP_OFF:
1931 ic->ic_flags &= ~IEEE80211_F_PRIVACY;
1932 ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
869 break;
1933 break;
870 case IEEE80211_IOC_POWERSAVESLEEP:
871 ireq->i_val = ic->ic_lintval;
1934 case IEEE80211_WEP_ON:
1935 ic->ic_flags |= IEEE80211_F_PRIVACY;
1936 ic->ic_flags |= IEEE80211_F_DROPUNENC;
872 break;
1937 break;
873 case IEEE80211_IOC_RTSTHRESHOLD:
874 ireq->i_val = ic->ic_rtsthreshold;
1938 case IEEE80211_WEP_MIXED:
1939 ic->ic_flags |= IEEE80211_F_PRIVACY;
1940 ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
875 break;
1941 break;
876 case IEEE80211_IOC_PROTMODE:
877 ireq->i_val = ic->ic_protmode;
1942 }
1943 error = ENETRESET;
1944 break;
1945 case IEEE80211_IOC_WEPKEY:
1946 kid = (u_int) ireq->i_val;
1947 if (kid >= IEEE80211_WEP_NKID)
1948 return EINVAL;
1949 k = &ic->ic_nw_keys[kid];
1950 if (ireq->i_len == 0) {
1951 /* zero-len =>'s delete any existing key */
1952 (void) ieee80211_crypto_delkey(ic, k);
878 break;
1953 break;
879 case IEEE80211_IOC_TXPOWER:
880 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
1954 }
1955 if (ireq->i_len > sizeof(tmpkey))
1956 return EINVAL;
1957 memset(tmpkey, 0, sizeof(tmpkey));
1958 error = copyin(ireq->i_data, tmpkey, ireq->i_len);
1959 if (error)
1960 break;
1961 ieee80211_key_update_begin(ic);
1962 if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP, k)) {
1963 k->wk_keylen = ireq->i_len;
1964 k->wk_flags |=
1965 IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
1966 memcpy(k->wk_key, tmpkey, sizeof(tmpkey));
1967 if (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
881 error = EINVAL;
1968 error = EINVAL;
882 else
883 ireq->i_val = ic->ic_txpower;
1969 } else
1970 error = EINVAL;
1971 ieee80211_key_update_end(ic);
1972 break;
1973 case IEEE80211_IOC_WEPTXKEY:
1974 kid = (u_int) ireq->i_val;
1975 if (kid >= IEEE80211_WEP_NKID)
1976 return EINVAL;
1977 ic->ic_def_txkey = kid;
1978 error = ERESTART; /* push to hardware */
1979 break;
1980 case IEEE80211_IOC_AUTHMODE:
1981 switch (ireq->i_val) {
1982 case IEEE80211_AUTH_WPA:
1983 case IEEE80211_AUTH_8021X: /* 802.1x */
1984 case IEEE80211_AUTH_OPEN: /* open */
1985 case IEEE80211_AUTH_SHARED: /* shared-key */
1986 case IEEE80211_AUTH_AUTO: /* auto */
1987 auth = ieee80211_authenticator_get(ireq->i_val);
1988 if (auth == NULL)
1989 return EINVAL;
884 break;
885 default:
1990 break;
1991 default:
886 error = EINVAL;
1992 return EINVAL;
1993 }
1994 switch (ireq->i_val) {
1995 case IEEE80211_AUTH_WPA: /* WPA w/ 802.1x */
1996 ic->ic_flags |= IEEE80211_F_PRIVACY;
1997 ireq->i_val = IEEE80211_AUTH_8021X;
887 break;
1998 break;
1999 case IEEE80211_AUTH_OPEN: /* open */
2000 ic->ic_flags &= ~(IEEE80211_F_WPA|IEEE80211_F_PRIVACY);
2001 break;
2002 case IEEE80211_AUTH_SHARED: /* shared-key */
2003 case IEEE80211_AUTH_8021X: /* 802.1x */
2004 ic->ic_flags &= ~IEEE80211_F_WPA;
2005 /* both require a key so mark the PRIVACY capability */
2006 ic->ic_flags |= IEEE80211_F_PRIVACY;
2007 break;
2008 case IEEE80211_AUTH_AUTO: /* auto */
2009 ic->ic_flags &= ~IEEE80211_F_WPA;
2010 /* XXX PRIVACY handling? */
2011 /* XXX what's the right way to do this? */
2012 break;
888 }
2013 }
2014 /* NB: authenticator attach/detach happens on state change */
2015 ic->ic_bss->ni_authmode = ireq->i_val;
2016 /* XXX mixed/mode/usage? */
2017 ic->ic_auth = auth;
2018 error = ENETRESET;
889 break;
2019 break;
890 case SIOCS80211:
891 error = suser(curthread);
892 if (error)
893 break;
894 ireq = (struct ieee80211req *) data;
895 switch (ireq->i_type) {
896 case IEEE80211_IOC_SSID:
897 if (ireq->i_val != 0 ||
898 ireq->i_len > IEEE80211_NWID_LEN) {
899 error = EINVAL;
900 break;
901 }
902 error = copyin(ireq->i_data, tmpssid, ireq->i_len);
903 if (error)
904 break;
905 memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
906 ic->ic_des_esslen = ireq->i_len;
907 memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
2020 case IEEE80211_IOC_CHANNEL:
2021 /* XXX 0xffff overflows 16-bit signed */
2022 if (ireq->i_val == 0 ||
2023 ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
2024 ic->ic_des_chan = IEEE80211_CHAN_ANYC;
2025 else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
2026 isclr(ic->ic_chan_active, ireq->i_val)) {
2027 return EINVAL;
2028 } else
2029 ic->ic_ibss_chan = ic->ic_des_chan =
2030 &ic->ic_channels[ireq->i_val];
2031 switch (ic->ic_state) {
2032 case IEEE80211_S_INIT:
2033 case IEEE80211_S_SCAN:
908 error = ENETRESET;
909 break;
2034 error = ENETRESET;
2035 break;
910 case IEEE80211_IOC_WEP:
2036 default:
911 /*
2037 /*
912 * These cards only support one mode so
913 * we just turn wep on if what ever is
914 * passed in is not OFF.
2038 * If the desired channel has changed (to something
2039 * other than any) and we're not already scanning,
2040 * then kick the state machine.
915 */
2041 */
916 if (ireq->i_val == IEEE80211_WEP_OFF) {
917 ic->ic_flags &= ~IEEE80211_F_WEPON;
918 } else {
919 ic->ic_flags |= IEEE80211_F_WEPON;
920 }
921 error = ENETRESET;
2042 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
2043 ic->ic_bss->ni_chan != ic->ic_des_chan &&
2044 (ic->ic_flags & IEEE80211_F_SCAN) == 0)
2045 error = ENETRESET;
922 break;
2046 break;
923 case IEEE80211_IOC_WEPKEY:
924 if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
925 error = EINVAL;
926 break;
2047 }
2048 if (error == ENETRESET && ic->ic_opmode == IEEE80211_M_MONITOR)
2049 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2050 break;
2051 case IEEE80211_IOC_POWERSAVE:
2052 switch (ireq->i_val) {
2053 case IEEE80211_POWERSAVE_OFF:
2054 if (ic->ic_flags & IEEE80211_F_PMGTON) {
2055 ic->ic_flags &= ~IEEE80211_F_PMGTON;
2056 error = ENETRESET;
927 }
2057 }
928 kid = (u_int) ireq->i_val;
929 if (kid >= IEEE80211_WEP_NKID) {
930 error = EINVAL;
931 break;
932 }
933 if (ireq->i_len > sizeof(tmpkey)) {
934 error = EINVAL;
935 break;
936 }
937 memset(tmpkey, 0, sizeof(tmpkey));
938 error = copyin(ireq->i_data, tmpkey, ireq->i_len);
939 if (error)
940 break;
941 memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey,
942 sizeof(tmpkey));
943 ic->ic_nw_keys[kid].wk_len = ireq->i_len;
944 error = ENETRESET;
945 break;
2058 break;
946 case IEEE80211_IOC_WEPTXKEY:
947 kid = (u_int) ireq->i_val;
948 if (kid >= IEEE80211_WEP_NKID) {
2059 case IEEE80211_POWERSAVE_ON:
2060 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
949 error = EINVAL;
2061 error = EINVAL;
950 break;
951 }
952 ic->ic_wep_txkey = kid;
953 error = ENETRESET;
954 break;
955#if 0
956 case IEEE80211_IOC_AUTHMODE:
957 sc->wi_authmode = ireq->i_val;
958 break;
959#endif
960 case IEEE80211_IOC_CHANNEL:
961 /* XXX 0xffff overflows 16-bit signed */
962 if (ireq->i_val == 0 ||
963 ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
964 ic->ic_des_chan = IEEE80211_CHAN_ANYC;
965 else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
966 isclr(ic->ic_chan_active, ireq->i_val)) {
967 error = EINVAL;
968 break;
969 } else
970 ic->ic_ibss_chan = ic->ic_des_chan =
971 &ic->ic_channels[ireq->i_val];
972 switch (ic->ic_state) {
973 case IEEE80211_S_INIT:
974 case IEEE80211_S_SCAN:
2062 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
2063 ic->ic_flags |= IEEE80211_F_PMGTON;
975 error = ENETRESET;
2064 error = ENETRESET;
976 break;
977 default:
978 if (ic->ic_opmode == IEEE80211_M_STA) {
979 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
980 ic->ic_bss->ni_chan != ic->ic_des_chan)
981 error = ENETRESET;
982 } else {
983 if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
984 error = ENETRESET;
985 }
986 break;
987 }
988 break;
2065 }
2066 break;
989 case IEEE80211_IOC_POWERSAVE:
990 switch (ireq->i_val) {
991 case IEEE80211_POWERSAVE_OFF:
992 if (ic->ic_flags & IEEE80211_F_PMGTON) {
993 ic->ic_flags &= ~IEEE80211_F_PMGTON;
994 error = ENETRESET;
995 }
996 break;
997 case IEEE80211_POWERSAVE_ON:
998 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
999 error = EINVAL;
1000 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
1001 ic->ic_flags |= IEEE80211_F_PMGTON;
1002 error = ENETRESET;
1003 }
1004 break;
1005 default:
1006 error = EINVAL;
1007 break;
1008 }
2067 default:
2068 error = EINVAL;
1009 break;
2069 break;
1010 case IEEE80211_IOC_POWERSAVESLEEP:
1011 if (ireq->i_val < 0) {
1012 error = EINVAL;
1013 break;
1014 }
1015 ic->ic_lintval = ireq->i_val;
1016 error = ENETRESET;
2070 }
2071 break;
2072 case IEEE80211_IOC_POWERSAVESLEEP:
2073 if (ireq->i_val < 0)
2074 return EINVAL;
2075 ic->ic_lintval = ireq->i_val;
2076 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2077 break;
2078 case IEEE80211_IOC_RTSTHRESHOLD:
2079 if (!(IEEE80211_RTS_MIN < ireq->i_val &&
2080 ireq->i_val < IEEE80211_RTS_MAX))
2081 return EINVAL;
2082 ic->ic_rtsthreshold = ireq->i_val;
2083 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2084 break;
2085 case IEEE80211_IOC_PROTMODE:
2086 if (ireq->i_val > IEEE80211_PROT_RTSCTS)
2087 return EINVAL;
2088 ic->ic_protmode = ireq->i_val;
2089 /* NB: if not operating in 11g this can wait */
2090 if (ic->ic_curmode == IEEE80211_MODE_11G)
2091 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2092 break;
2093 case IEEE80211_IOC_TXPOWER:
2094 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
2095 return EINVAL;
2096 if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
2097 ireq->i_val < IEEE80211_TXPOWER_MAX))
2098 return EINVAL;
2099 ic->ic_txpowlimit = ireq->i_val;
2100 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2101 break;
2102 case IEEE80211_IOC_ROAMING:
2103 if (!(IEEE80211_ROAMING_DEVICE <= ireq->i_val &&
2104 ireq->i_val <= IEEE80211_ROAMING_MANUAL))
2105 return EINVAL;
2106 ic->ic_roaming = ireq->i_val;
2107 /* XXXX reset? */
2108 break;
2109 case IEEE80211_IOC_PRIVACY:
2110 if (ireq->i_val) {
2111 /* XXX check for key state? */
2112 ic->ic_flags |= IEEE80211_F_PRIVACY;
2113 } else
2114 ic->ic_flags &= ~IEEE80211_F_PRIVACY;
2115 break;
2116 case IEEE80211_IOC_DROPUNENCRYPTED:
2117 if (ireq->i_val)
2118 ic->ic_flags |= IEEE80211_F_DROPUNENC;
2119 else
2120 ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
2121 break;
2122 case IEEE80211_IOC_WPAKEY:
2123 error = ieee80211_ioctl_setkey(ic, ireq);
2124 break;
2125 case IEEE80211_IOC_DELKEY:
2126 error = ieee80211_ioctl_delkey(ic, ireq);
2127 break;
2128 case IEEE80211_IOC_MLME:
2129 error = ieee80211_ioctl_setmlme(ic, ireq);
2130 break;
2131 case IEEE80211_IOC_OPTIE:
2132 error = ieee80211_ioctl_setoptie(ic, ireq);
2133 break;
2134 case IEEE80211_IOC_COUNTERMEASURES:
2135 if (ireq->i_val) {
2136 if ((ic->ic_flags & IEEE80211_F_WPA) == 0)
2137 return EINVAL;
2138 ic->ic_flags |= IEEE80211_F_COUNTERM;
2139 } else
2140 ic->ic_flags &= ~IEEE80211_F_COUNTERM;
2141 break;
2142 case IEEE80211_IOC_WPA:
2143 if (ireq->i_val > 3)
2144 return EINVAL;
2145 /* XXX verify ciphers available */
2146 ic->ic_flags &= ~IEEE80211_F_WPA;
2147 switch (ireq->i_val) {
2148 case 1:
2149 ic->ic_flags |= IEEE80211_F_WPA1;
1017 break;
2150 break;
1018 case IEEE80211_IOC_RTSTHRESHOLD:
1019 if (!(IEEE80211_RTS_MIN < ireq->i_val &&
1020 ireq->i_val < IEEE80211_RTS_MAX)) {
1021 error = EINVAL;
1022 break;
1023 }
1024 ic->ic_rtsthreshold = ireq->i_val;
1025 error = ENETRESET;
2151 case 2:
2152 ic->ic_flags |= IEEE80211_F_WPA2;
1026 break;
2153 break;
1027 case IEEE80211_IOC_PROTMODE:
1028 if (ireq->i_val > IEEE80211_PROT_RTSCTS) {
1029 error = EINVAL;
1030 break;
1031 }
1032 ic->ic_protmode = ireq->i_val;
1033 /* NB: if not operating in 11g this can wait */
1034 if (ic->ic_curmode == IEEE80211_MODE_11G)
1035 error = ENETRESET;
2154 case 3:
2155 ic->ic_flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2;
1036 break;
2156 break;
1037 case IEEE80211_IOC_TXPOWER:
1038 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
1039 error = EINVAL;
1040 break;
1041 }
1042 if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
1043 ireq->i_val < IEEE80211_TXPOWER_MAX)) {
1044 error = EINVAL;
1045 break;
1046 }
1047 ic->ic_txpower = ireq->i_val;
1048 error = ENETRESET;
2157 }
2158 error = ENETRESET; /* XXX? */
2159 break;
2160 case IEEE80211_IOC_WME:
2161 if (ireq->i_val) {
2162 if ((ic->ic_caps & IEEE80211_C_WME) == 0)
2163 return EINVAL;
2164 ic->ic_flags |= IEEE80211_F_WME;
2165 } else
2166 ic->ic_flags &= ~IEEE80211_F_WME;
2167 error = ENETRESET; /* XXX maybe not for station? */
2168 break;
2169 case IEEE80211_IOC_HIDESSID:
2170 if (ireq->i_val)
2171 ic->ic_flags |= IEEE80211_F_HIDESSID;
2172 else
2173 ic->ic_flags &= ~IEEE80211_F_HIDESSID;
2174 error = ENETRESET;
2175 break;
2176 case IEEE80211_IOC_APBRIDGE:
2177 if (ireq->i_val == 0)
2178 ic->ic_flags |= IEEE80211_F_NOBRIDGE;
2179 else
2180 ic->ic_flags &= ~IEEE80211_F_NOBRIDGE;
2181 break;
2182 case IEEE80211_IOC_MCASTCIPHER:
2183 if ((ic->ic_caps & cipher2cap(ireq->i_val)) == 0 &&
2184 !ieee80211_crypto_available(ireq->i_val))
2185 return EINVAL;
2186 rsn->rsn_mcastcipher = ireq->i_val;
2187 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2188 break;
2189 case IEEE80211_IOC_MCASTKEYLEN:
2190 if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
2191 return EINVAL;
2192 /* XXX no way to verify driver capability */
2193 rsn->rsn_mcastkeylen = ireq->i_val;
2194 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2195 break;
2196 case IEEE80211_IOC_UCASTCIPHERS:
2197 /*
2198 * Convert user-specified cipher set to the set
2199 * we can support (via hardware or software).
2200 * NB: this logic intentionally ignores unknown and
2201 * unsupported ciphers so folks can specify 0xff or
2202 * similar and get all available ciphers.
2203 */
2204 caps = 0;
2205 for (j = 1; j < 32; j++) /* NB: skip WEP */
2206 if ((ireq->i_val & (1<<j)) &&
2207 ((ic->ic_caps & cipher2cap(j)) ||
2208 ieee80211_crypto_available(j)))
2209 caps |= 1<<j;
2210 if (caps == 0) /* nothing available */
2211 return EINVAL;
2212 /* XXX verify ciphers ok for unicast use? */
2213 /* XXX disallow if running as it'll have no effect */
2214 rsn->rsn_ucastcipherset = caps;
2215 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2216 break;
2217 case IEEE80211_IOC_UCASTCIPHER:
2218 if ((rsn->rsn_ucastcipherset & cipher2cap(ireq->i_val)) == 0)
2219 return EINVAL;
2220 rsn->rsn_ucastcipher = ireq->i_val;
2221 break;
2222 case IEEE80211_IOC_UCASTKEYLEN:
2223 if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
2224 return EINVAL;
2225 /* XXX no way to verify driver capability */
2226 rsn->rsn_ucastkeylen = ireq->i_val;
2227 break;
2228 case IEEE80211_IOC_DRIVER_CAPS:
2229 /* NB: for testing */
2230 ic->ic_caps = (((u_int16_t) ireq->i_val) << 16) |
2231 ((u_int16_t) ireq->i_len);
2232 break;
2233 case IEEE80211_IOC_KEYMGTALGS:
2234 /* XXX check */
2235 rsn->rsn_keymgmtset = ireq->i_val;
2236 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2237 break;
2238 case IEEE80211_IOC_RSNCAPS:
2239 /* XXX check */
2240 rsn->rsn_caps = ireq->i_val;
2241 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2242 break;
2243 case IEEE80211_IOC_BSSID:
2244 /* NB: should only be set when in STA mode */
2245 if (ic->ic_opmode != IEEE80211_M_STA)
2246 return EINVAL;
2247 if (ireq->i_len != sizeof(tmpbssid))
2248 return EINVAL;
2249 error = copyin(ireq->i_data, tmpbssid, ireq->i_len);
2250 if (error)
1049 break;
2251 break;
1050 default:
1051 error = EINVAL;
2252 IEEE80211_ADDR_COPY(ic->ic_des_bssid, tmpbssid);
2253 if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid))
2254 ic->ic_flags &= ~IEEE80211_F_DESBSSID;
2255 else
2256 ic->ic_flags |= IEEE80211_F_DESBSSID;
2257 error = ENETRESET;
2258 break;
2259 case IEEE80211_IOC_CHANLIST:
2260 error = ieee80211_ioctl_setchanlist(ic, ireq);
2261 break;
2262 case IEEE80211_IOC_SCAN_REQ:
2263 if (ic->ic_opmode == IEEE80211_M_HOSTAP) /* XXX ignore */
1052 break;
2264 break;
1053 }
2265 error = ieee80211_setupscan(ic, ic->ic_chan_avail);
2266 if (error == 0) /* XXX background scan */
2267 error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
1054 break;
2268 break;
2269 case IEEE80211_IOC_ADDMAC:
2270 case IEEE80211_IOC_DELMAC:
2271 error = ieee80211_ioctl_macmac(ic, ireq);
2272 break;
2273 case IEEE80211_IOC_MACCMD:
2274 error = ieee80211_ioctl_maccmd(ic, ireq);
2275 break;
2276 case IEEE80211_IOC_STA_TXPOW:
2277 error = ieee80211_ioctl_setstatxpow(ic, ireq);
2278 break;
2279 case IEEE80211_IOC_WME_CWMIN: /* WME: CWmin */
2280 case IEEE80211_IOC_WME_CWMAX: /* WME: CWmax */
2281 case IEEE80211_IOC_WME_AIFS: /* WME: AIFS */
2282 case IEEE80211_IOC_WME_TXOPLIMIT: /* WME: txops limit */
2283 case IEEE80211_IOC_WME_ACM: /* WME: ACM (bss only) */
2284 case IEEE80211_IOC_WME_ACKPOLICY: /* WME: ACK policy (bss only) */
2285 error = ieee80211_ioctl_setwmeparam(ic, ireq);
2286 break;
2287 case IEEE80211_IOC_DTIM_PERIOD:
2288 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
2289 ic->ic_opmode != IEEE80211_M_IBSS)
2290 return EINVAL;
2291 if (IEEE80211_DTIM_MIN <= ireq->i_val &&
2292 ireq->i_val <= IEEE80211_DTIM_MAX) {
2293 ic->ic_dtim_period = ireq->i_val;
2294 error = ENETRESET; /* requires restart */
2295 } else
2296 error = EINVAL;
2297 break;
2298 case IEEE80211_IOC_BEACON_INTERVAL:
2299 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
2300 ic->ic_opmode != IEEE80211_M_IBSS)
2301 return EINVAL;
2302 if (IEEE80211_BINTVAL_MIN <= ireq->i_val &&
2303 ireq->i_val <= IEEE80211_BINTVAL_MAX) {
2304 ic->ic_lintval = ireq->i_val;
2305 error = ENETRESET; /* requires restart */
2306 } else
2307 error = EINVAL;
2308 break;
2309 default:
2310 error = EINVAL;
2311 break;
2312 }
2313 if (error == ENETRESET && !IS_UP_AUTO(ic))
2314 error = 0;
2315 return error;
2316}
2317
2318int
2319ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, caddr_t data)
2320{
2321 struct ifnet *ifp = ic->ic_ifp;
2322 int error = 0;
2323 struct ifreq *ifr;
2324 struct ifaddr *ifa; /* XXX */
2325
2326 switch (cmd) {
2327 case SIOCSIFMEDIA:
2328 case SIOCGIFMEDIA:
2329 error = ifmedia_ioctl(ifp, (struct ifreq *) data,
2330 &ic->ic_media, cmd);
2331 break;
2332 case SIOCG80211:
2333 error = ieee80211_ioctl_get80211(ic, cmd,
2334 (struct ieee80211req *) data);
2335 break;
2336 case SIOCS80211:
2337 error = suser(curthread);
2338 if (error == 0)
2339 error = ieee80211_ioctl_set80211(ic, cmd,
2340 (struct ieee80211req *) data);
2341 break;
1055 case SIOCGIFGENERIC:
2342 case SIOCGIFGENERIC:
1056 error = ieee80211_cfgget(ifp, cmd, data);
2343 error = ieee80211_cfgget(ic, cmd, data);
1057 break;
1058 case SIOCSIFGENERIC:
1059 error = suser(curthread);
1060 if (error)
1061 break;
2344 break;
2345 case SIOCSIFGENERIC:
2346 error = suser(curthread);
2347 if (error)
2348 break;
1062 error = ieee80211_cfgset(ifp, cmd, data);
2349 error = ieee80211_cfgset(ic, cmd, data);
1063 break;
1064 case SIOCG80211STATS:
1065 ifr = (struct ifreq *)data;
1066 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
1067 break;
1068 case SIOCSIFMTU:
1069 ifr = (struct ifreq *)data;
1070 if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&

--- 56 unchanged lines hidden ---
2350 break;
2351 case SIOCG80211STATS:
2352 ifr = (struct ifreq *)data;
2353 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
2354 break;
2355 case SIOCSIFMTU:
2356 ifr = (struct ifreq *)data;
2357 if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&

--- 56 unchanged lines hidden ---