]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net80211/ieee80211_ioctl.c
This commit was generated by cvs2svn to compensate for changes in r171537,
[FreeBSD/FreeBSD.git] / sys / net80211 / ieee80211_ioctl.c
1 /*-
2  * Copyright (c) 2001 Atsushi Onoe
3  * Copyright (c) 2002-2007 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  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include "opt_compat.h"
31
32 /*
33  * IEEE 802.11 ioctl support (FreeBSD-specific)
34  */
35
36 #include "opt_inet.h"
37 #include "opt_ipx.h"
38
39 #include <sys/endian.h>
40 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/priv.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_dl.h>
49 #include <net/if_media.h>
50 #include <net/ethernet.h>
51
52 #ifdef INET
53 #include <netinet/in.h>
54 #include <netinet/if_ether.h>
55 #endif
56
57 #ifdef IPX
58 #include <netipx/ipx.h>
59 #include <netipx/ipx_if.h>
60 #endif
61
62 #include <net80211/ieee80211_var.h>
63 #include <net80211/ieee80211_ioctl.h>
64
65 #define IS_UP(_ic) \
66         (((_ic)->ic_ifp->if_flags & IFF_UP) &&                  \
67             ((_ic)->ic_ifp->if_drv_flags & IFF_DRV_RUNNING))
68 #define IS_UP_AUTO(_ic) \
69         (IS_UP(_ic) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO)
70 #define RESCAN  1
71
72 static struct ieee80211_channel *findchannel(struct ieee80211com *,
73                 int ieee, int mode);
74
75 static int
76 cap2cipher(int flag)
77 {
78         switch (flag) {
79         case IEEE80211_C_WEP:           return IEEE80211_CIPHER_WEP;
80         case IEEE80211_C_AES:           return IEEE80211_CIPHER_AES_OCB;
81         case IEEE80211_C_AES_CCM:       return IEEE80211_CIPHER_AES_CCM;
82         case IEEE80211_C_CKIP:          return IEEE80211_CIPHER_CKIP;
83         case IEEE80211_C_TKIP:          return IEEE80211_CIPHER_TKIP;
84         }
85         return -1;
86 }
87
88 static int
89 ieee80211_ioctl_getkey(struct ieee80211com *ic, struct ieee80211req *ireq)
90 {
91         struct ieee80211_node *ni;
92         struct ieee80211req_key ik;
93         struct ieee80211_key *wk;
94         const struct ieee80211_cipher *cip;
95         u_int kid;
96         int error;
97
98         if (ireq->i_len != sizeof(ik))
99                 return EINVAL;
100         error = copyin(ireq->i_data, &ik, sizeof(ik));
101         if (error)
102                 return error;
103         kid = ik.ik_keyix;
104         if (kid == IEEE80211_KEYIX_NONE) {
105                 ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
106                 if (ni == NULL)
107                         return EINVAL;          /* XXX */
108                 wk = &ni->ni_ucastkey;
109         } else {
110                 if (kid >= IEEE80211_WEP_NKID)
111                         return EINVAL;
112                 wk = &ic->ic_nw_keys[kid];
113                 IEEE80211_ADDR_COPY(&ik.ik_macaddr, ic->ic_bss->ni_macaddr);
114                 ni = NULL;
115         }
116         cip = wk->wk_cipher;
117         ik.ik_type = cip->ic_cipher;
118         ik.ik_keylen = wk->wk_keylen;
119         ik.ik_flags = wk->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
120         if (wk->wk_keyix == ic->ic_def_txkey)
121                 ik.ik_flags |= IEEE80211_KEY_DEFAULT;
122         if (priv_check(curthread, PRIV_NET80211_GETKEY) == 0) {
123                 /* NB: only root can read key data */
124                 ik.ik_keyrsc = wk->wk_keyrsc;
125                 ik.ik_keytsc = wk->wk_keytsc;
126                 memcpy(ik.ik_keydata, wk->wk_key, wk->wk_keylen);
127                 if (cip->ic_cipher == IEEE80211_CIPHER_TKIP) {
128                         memcpy(ik.ik_keydata+wk->wk_keylen,
129                                 wk->wk_key + IEEE80211_KEYBUF_SIZE,
130                                 IEEE80211_MICBUF_SIZE);
131                         ik.ik_keylen += IEEE80211_MICBUF_SIZE;
132                 }
133         } else {
134                 ik.ik_keyrsc = 0;
135                 ik.ik_keytsc = 0;
136                 memset(ik.ik_keydata, 0, sizeof(ik.ik_keydata));
137         }
138         if (ni != NULL)
139                 ieee80211_free_node(ni);
140         return copyout(&ik, ireq->i_data, sizeof(ik));
141 }
142
143 static int
144 ieee80211_ioctl_getchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
145 {
146
147         if (sizeof(ic->ic_chan_active) < ireq->i_len)
148                 ireq->i_len = sizeof(ic->ic_chan_active);
149         return copyout(&ic->ic_chan_active, ireq->i_data, ireq->i_len);
150 }
151
152 static int
153 ieee80211_ioctl_getchaninfo(struct ieee80211com *ic, struct ieee80211req *ireq)
154 {
155         int space;
156
157         space = __offsetof(struct ieee80211req_chaninfo,
158                         ic_chans[ic->ic_nchans]);
159         if (space > ireq->i_len)
160                 space = ireq->i_len;
161         /* XXX assumes compatible layout */
162         return copyout(&ic->ic_nchans, ireq->i_data, space);
163 }
164
165 static int
166 ieee80211_ioctl_getwpaie(struct ieee80211com *ic, struct ieee80211req *ireq, int req)
167 {
168         struct ieee80211_node *ni;
169         struct ieee80211req_wpaie2 wpaie;
170         int error;
171
172         if (ireq->i_len < IEEE80211_ADDR_LEN)
173                 return EINVAL;
174         error = copyin(ireq->i_data, wpaie.wpa_macaddr, IEEE80211_ADDR_LEN);
175         if (error != 0)
176                 return error;
177         ni = ieee80211_find_node(&ic->ic_sta, wpaie.wpa_macaddr);
178         if (ni == NULL)
179                 return ENOENT;          /* XXX */
180         memset(wpaie.wpa_ie, 0, sizeof(wpaie.wpa_ie));
181         if (ni->ni_wpa_ie != NULL) {
182                 int ielen = ni->ni_wpa_ie[1] + 2;
183                 if (ielen > sizeof(wpaie.wpa_ie))
184                         ielen = sizeof(wpaie.wpa_ie);
185                 memcpy(wpaie.wpa_ie, ni->ni_wpa_ie, ielen);
186         }
187         if (req == IEEE80211_IOC_WPAIE2) {
188                 memset(wpaie.rsn_ie, 0, sizeof(wpaie.rsn_ie));
189                 if (ni->ni_rsn_ie != NULL) {
190                         int ielen = ni->ni_rsn_ie[1] + 2;
191                         if (ielen > sizeof(wpaie.rsn_ie))
192                                 ielen = sizeof(wpaie.rsn_ie);
193                         memcpy(wpaie.rsn_ie, ni->ni_rsn_ie, ielen);
194                 }
195                 if (ireq->i_len > sizeof(struct ieee80211req_wpaie2))
196                         ireq->i_len = sizeof(struct ieee80211req_wpaie2);
197         } else {
198                 /* compatibility op, may overwrite wpa ie */
199                 /* XXX check ic_flags? */
200                 if (ni->ni_rsn_ie != NULL) {
201                         int ielen = ni->ni_rsn_ie[1] + 2;
202                         if (ielen > sizeof(wpaie.wpa_ie))
203                                 ielen = sizeof(wpaie.wpa_ie);
204                         memcpy(wpaie.wpa_ie, ni->ni_rsn_ie, ielen);
205                 }
206                 if (ireq->i_len > sizeof(struct ieee80211req_wpaie))
207                         ireq->i_len = sizeof(struct ieee80211req_wpaie);
208         }
209         ieee80211_free_node(ni);
210         return copyout(&wpaie, ireq->i_data, ireq->i_len);
211 }
212
213 static int
214 ieee80211_ioctl_getstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
215 {
216         struct ieee80211_node *ni;
217         uint8_t macaddr[IEEE80211_ADDR_LEN];
218         const int off = __offsetof(struct ieee80211req_sta_stats, is_stats);
219         int error;
220
221         if (ireq->i_len < off)
222                 return EINVAL;
223         error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
224         if (error != 0)
225                 return error;
226         ni = ieee80211_find_node(&ic->ic_sta, macaddr);
227         if (ni == NULL)
228                 return EINVAL;
229         if (ireq->i_len > sizeof(struct ieee80211req_sta_stats))
230                 ireq->i_len = sizeof(struct ieee80211req_sta_stats);
231         /* NB: copy out only the statistics */
232         error = copyout(&ni->ni_stats, (uint8_t *) ireq->i_data + off,
233                         ireq->i_len - off);
234         ieee80211_free_node(ni);
235         return error;
236 }
237
238 static __inline uint8_t *
239 copyie(uint8_t *cp, const uint8_t *ie)
240 {
241         if (ie != NULL) {
242                 memcpy(cp, ie, 2+ie[1]);
243                 cp += 2+ie[1];
244         }
245         return cp;
246 }
247
248 #ifdef COMPAT_FREEBSD6
249 #define IEEE80211_IOC_SCAN_RESULTS_OLD  24
250
251 struct scan_result_old {
252         uint16_t        isr_len;                /* length (mult of 4) */
253         uint16_t        isr_freq;               /* MHz */
254         uint16_t        isr_flags;              /* channel flags */
255         uint8_t         isr_noise;
256         uint8_t         isr_rssi;
257         uint8_t         isr_intval;             /* beacon interval */
258         uint8_t         isr_capinfo;            /* capabilities */
259         uint8_t         isr_erp;                /* ERP element */
260         uint8_t         isr_bssid[IEEE80211_ADDR_LEN];
261         uint8_t         isr_nrates;
262         uint8_t         isr_rates[IEEE80211_RATE_MAXSIZE];
263         uint8_t         isr_ssid_len;           /* SSID length */
264         uint8_t         isr_ie_len;             /* IE length */
265         uint8_t         isr_pad[5];
266         /* variable length SSID followed by IE data */
267 };
268
269 struct oscanreq {
270         struct scan_result_old *sr;
271         size_t space;
272 };
273
274 static size_t
275 old_scan_space(const struct ieee80211_scan_entry *se, int *ielen)
276 {
277         size_t len;
278
279         *ielen = 0;
280         if (se->se_wpa_ie != NULL)
281                 *ielen += 2+se->se_wpa_ie[1];
282         if (se->se_wme_ie != NULL)
283                 *ielen += 2+se->se_wme_ie[1];
284         /*
285          * NB: ie's can be no more than 255 bytes and the max 802.11
286          * packet is <3Kbytes so we are sure this doesn't overflow
287          * 16-bits; if this is a concern we can drop the ie's.
288          */
289         len = sizeof(struct scan_result_old) + se->se_ssid[1] + *ielen;
290         return roundup(len, sizeof(uint32_t));
291 }
292
293 static void
294 old_get_scan_space(void *arg, const struct ieee80211_scan_entry *se)
295 {
296         struct oscanreq *req = arg;
297         int ielen;
298
299         req->space += old_scan_space(se, &ielen);
300 }
301
302 static void
303 old_get_scan_result(void *arg, const struct ieee80211_scan_entry *se)
304 {
305         struct oscanreq *req = arg;
306         struct scan_result_old *sr;
307         int ielen, len, nr, nxr;
308         uint8_t *cp;
309
310         len = old_scan_space(se, &ielen);
311         if (len > req->space)
312                 return;
313
314         sr = req->sr;
315         memset(sr, 0, sizeof(*sr));
316         sr->isr_ssid_len = se->se_ssid[1];
317         /* NB: beware of overflow, isr_ie_len is 8 bits */
318         sr->isr_ie_len = (ielen > 255 ? 0 : ielen);
319         sr->isr_len = len;
320         sr->isr_freq = se->se_chan->ic_freq;
321         sr->isr_flags = se->se_chan->ic_flags;
322         sr->isr_rssi = se->se_rssi;
323         sr->isr_noise = se->se_noise;
324         sr->isr_intval = se->se_intval;
325         sr->isr_capinfo = se->se_capinfo;
326         sr->isr_erp = se->se_erp;
327         IEEE80211_ADDR_COPY(sr->isr_bssid, se->se_bssid);
328         nr = min(se->se_rates[1], IEEE80211_RATE_MAXSIZE);
329         memcpy(sr->isr_rates, se->se_rates+2, nr);
330         nxr = min(se->se_xrates[1], IEEE80211_RATE_MAXSIZE - nr);
331         memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
332         sr->isr_nrates = nr + nxr;
333
334         cp = (uint8_t *)(sr+1);
335         memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
336         cp += sr->isr_ssid_len;
337         if (sr->isr_ie_len) {
338                 cp = copyie(cp, se->se_wpa_ie);
339                 cp = copyie(cp, se->se_wme_ie);
340         }
341
342         req->space -= len;
343         req->sr = (struct scan_result_old *)(((uint8_t *)sr) + len);
344 }
345
346 static int
347 old_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq)
348 {
349         struct oscanreq req;
350         int error;
351
352         if (ireq->i_len < sizeof(struct scan_result_old))
353                 return EFAULT;
354
355         error = 0;
356         req.space = 0;
357         ieee80211_scan_iterate(ic, old_get_scan_space, &req);
358         if (req.space > ireq->i_len)
359                 req.space = ireq->i_len;
360         if (req.space > 0) {
361                 size_t space;
362                 void *p;
363
364                 space = req.space;
365                 /* XXX M_WAITOK after driver lock released */
366                 MALLOC(p, void *, space, M_TEMP, M_NOWAIT | M_ZERO);
367                 if (p == NULL)
368                         return ENOMEM;
369                 req.sr = p;
370                 ieee80211_scan_iterate(ic, old_get_scan_result, &req);
371                 ireq->i_len = space - req.space;
372                 error = copyout(p, ireq->i_data, ireq->i_len);
373                 FREE(p, M_TEMP);
374         } else
375                 ireq->i_len = 0;
376
377         return error;
378 }
379 #endif /* COMPAT_FREEBSD6 */
380
381 struct scanreq {
382         struct ieee80211req_scan_result *sr;
383         size_t space;
384 };
385
386 static size_t
387 scan_space(const struct ieee80211_scan_entry *se, int *ielen)
388 {
389         size_t len;
390
391         *ielen = 0;
392         if (se->se_wpa_ie != NULL)
393                 *ielen += 2+se->se_wpa_ie[1];
394         if (se->se_rsn_ie != NULL)
395                 *ielen += 2+se->se_rsn_ie[1];
396         if (se->se_wme_ie != NULL)
397                 *ielen += 2+se->se_wme_ie[1];
398         if (se->se_ath_ie != NULL)
399                 *ielen += 2+se->se_ath_ie[1];
400         /*
401          * NB: ie's can be no more than 255 bytes and the max 802.11
402          * packet is <3Kbytes so we are sure this doesn't overflow
403          * 16-bits; if this is a concern we can drop the ie's.
404          */
405         len = sizeof(struct ieee80211req_scan_result) + se->se_ssid[1] + *ielen;
406         return roundup(len, sizeof(uint32_t));
407 }
408
409 static void
410 get_scan_space(void *arg, const struct ieee80211_scan_entry *se)
411 {
412         struct scanreq *req = arg;
413         int ielen;
414
415         req->space += scan_space(se, &ielen);
416 }
417
418 static void
419 get_scan_result(void *arg, const struct ieee80211_scan_entry *se)
420 {
421         struct scanreq *req = arg;
422         struct ieee80211req_scan_result *sr;
423         int ielen, len, nr, nxr;
424         uint8_t *cp;
425
426         len = scan_space(se, &ielen);
427         if (len > req->space)
428                 return;
429
430         sr = req->sr;
431         KASSERT(len <= 65535 && ielen <= 65535,
432             ("len %u ssid %u ie %u", len, se->se_ssid[1], ielen));
433         sr->isr_ie_off = sizeof(struct ieee80211req_scan_result);
434         sr->isr_ie_len = ielen;
435         sr->isr_len = len;
436         sr->isr_freq = se->se_chan->ic_freq;
437         sr->isr_flags = se->se_chan->ic_flags;
438         sr->isr_rssi = se->se_rssi;
439         sr->isr_noise = se->se_noise;
440         sr->isr_intval = se->se_intval;
441         sr->isr_capinfo = se->se_capinfo;
442         sr->isr_erp = se->se_erp;
443         IEEE80211_ADDR_COPY(sr->isr_bssid, se->se_bssid);
444         nr = min(se->se_rates[1], IEEE80211_RATE_MAXSIZE);
445         memcpy(sr->isr_rates, se->se_rates+2, nr);
446         nxr = min(se->se_xrates[1], IEEE80211_RATE_MAXSIZE - nr);
447         memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
448         sr->isr_nrates = nr + nxr;
449
450         sr->isr_ssid_len = se->se_ssid[1];
451         cp = ((uint8_t *)sr) + sr->isr_ie_off;
452         memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
453
454         if (ielen) {
455                 cp += sr->isr_ssid_len;
456                 cp = copyie(cp, se->se_wpa_ie);
457                 cp = copyie(cp, se->se_rsn_ie);
458                 cp = copyie(cp, se->se_wme_ie);
459                 cp = copyie(cp, se->se_ath_ie);
460                 cp = copyie(cp, se->se_htcap_ie);
461         }
462
463         req->space -= len;
464         req->sr = (struct ieee80211req_scan_result *)(((uint8_t *)sr) + len);
465 }
466
467 static int
468 ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq)
469 {
470         struct scanreq req;
471         int error;
472
473         if (ireq->i_len < sizeof(struct ieee80211req_scan_result))
474                 return EFAULT;
475
476         error = 0;
477         req.space = 0;
478         ieee80211_scan_iterate(ic, get_scan_space, &req);
479         if (req.space > ireq->i_len)
480                 req.space = ireq->i_len;
481         if (req.space > 0) {
482                 size_t space;
483                 void *p;
484
485                 space = req.space;
486                 /* XXX M_WAITOK after driver lock released */
487                 MALLOC(p, void *, space, M_TEMP, M_NOWAIT | M_ZERO);
488                 if (p == NULL)
489                         return ENOMEM;
490                 req.sr = p;
491                 ieee80211_scan_iterate(ic, get_scan_result, &req);
492                 ireq->i_len = space - req.space;
493                 error = copyout(p, ireq->i_data, ireq->i_len);
494                 FREE(p, M_TEMP);
495         } else
496                 ireq->i_len = 0;
497
498         return error;
499 }
500
501 struct stainforeq {
502         struct ieee80211com *ic;
503         struct ieee80211req_sta_info *si;
504         size_t  space;
505 };
506
507 static size_t
508 sta_space(const struct ieee80211_node *ni, size_t *ielen)
509 {
510         *ielen = 0;
511         if (ni->ni_wpa_ie != NULL)
512                 *ielen += 2+ni->ni_wpa_ie[1];
513         if (ni->ni_rsn_ie != NULL)
514                 *ielen += 2+ni->ni_rsn_ie[1];
515         if (ni->ni_wme_ie != NULL)
516                 *ielen += 2+ni->ni_wme_ie[1];
517         if (ni->ni_ath_ie != NULL)
518                 *ielen += 2+ni->ni_ath_ie[1];
519         return roundup(sizeof(struct ieee80211req_sta_info) + *ielen,
520                       sizeof(uint32_t));
521 }
522
523 static void
524 get_sta_space(void *arg, struct ieee80211_node *ni)
525 {
526         struct stainforeq *req = arg;
527         struct ieee80211com *ic = ni->ni_ic;
528         size_t ielen;
529
530         if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
531             ni->ni_associd == 0)        /* only associated stations */
532                 return;
533         req->space += sta_space(ni, &ielen);
534 }
535
536 static void
537 get_sta_info(void *arg, struct ieee80211_node *ni)
538 {
539         struct stainforeq *req = arg;
540         struct ieee80211com *ic = ni->ni_ic;
541         struct ieee80211req_sta_info *si;
542         size_t ielen, len;
543         uint8_t *cp;
544
545         if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
546             ni->ni_associd == 0)        /* only associated stations */
547                 return;
548         if (ni->ni_chan == IEEE80211_CHAN_ANYC) /* XXX bogus entry */
549                 return;
550         len = sta_space(ni, &ielen);
551         if (len > req->space)
552                 return;
553         si = req->si;
554         si->isi_len = len;
555         si->isi_ie_off = sizeof(struct ieee80211req_sta_info);
556         si->isi_ie_len = ielen;
557         si->isi_freq = ni->ni_chan->ic_freq;
558         si->isi_flags = ni->ni_chan->ic_flags;
559         si->isi_state = ni->ni_flags;
560         si->isi_authmode = ni->ni_authmode;
561         ic->ic_node_getsignal(ni, &si->isi_rssi, &si->isi_noise);
562         si->isi_noise = 0;              /* XXX */
563         si->isi_capinfo = ni->ni_capinfo;
564         si->isi_erp = ni->ni_erp;
565         IEEE80211_ADDR_COPY(si->isi_macaddr, ni->ni_macaddr);
566         si->isi_nrates = ni->ni_rates.rs_nrates;
567         if (si->isi_nrates > 15)
568                 si->isi_nrates = 15;
569         memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates);
570         si->isi_txrate = ni->ni_txrate;
571         si->isi_ie_len = ielen;
572         si->isi_associd = ni->ni_associd;
573         si->isi_txpower = ni->ni_txpower;
574         si->isi_vlan = ni->ni_vlan;
575         if (ni->ni_flags & IEEE80211_NODE_QOS) {
576                 memcpy(si->isi_txseqs, ni->ni_txseqs, sizeof(ni->ni_txseqs));
577                 memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs));
578         } else {
579                 si->isi_txseqs[0] = ni->ni_txseqs[IEEE80211_NONQOS_TID];
580                 si->isi_rxseqs[0] = ni->ni_rxseqs[IEEE80211_NONQOS_TID];
581         }
582         /* NB: leave all cases in case we relax ni_associd == 0 check */
583         if (ieee80211_node_is_authorized(ni))
584                 si->isi_inact = ic->ic_inact_run;
585         else if (ni->ni_associd != 0)
586                 si->isi_inact = ic->ic_inact_auth;
587         else
588                 si->isi_inact = ic->ic_inact_init;
589         si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
590
591         if (ielen) {
592                 cp = ((uint8_t *)si) + si->isi_ie_off;
593                 cp = copyie(cp, ni->ni_wpa_ie);
594                 cp = copyie(cp, ni->ni_rsn_ie);
595                 cp = copyie(cp, ni->ni_wme_ie);
596                 cp = copyie(cp, ni->ni_ath_ie);
597         }
598
599         req->si = (struct ieee80211req_sta_info *)(((uint8_t *)si) + len);
600         req->space -= len;
601 }
602
603 static int
604 getstainfo_common(struct ieee80211com *ic, struct ieee80211req *ireq,
605         struct ieee80211_node *ni, int off)
606 {
607         struct stainforeq req;
608         size_t space;
609         void *p;
610         int error;
611
612         error = 0;
613         req.space = 0;
614         if (ni == NULL)
615                 ieee80211_iterate_nodes(&ic->ic_sta, get_sta_space, &req);
616         else
617                 get_sta_space(&req, ni);
618         if (req.space > ireq->i_len)
619                 req.space = ireq->i_len;
620         if (req.space > 0) {
621                 space = req.space;
622                 /* XXX M_WAITOK after driver lock released */
623                 MALLOC(p, void *, space, M_TEMP, M_NOWAIT);
624                 if (p == NULL) {
625                         error = ENOMEM;
626                         goto bad;
627                 }
628                 req.si = p;
629                 if (ni == NULL)
630                         ieee80211_iterate_nodes(&ic->ic_sta, get_sta_info, &req);
631                 else
632                         get_sta_info(&req, ni);
633                 ireq->i_len = space - req.space;
634                 error = copyout(p, (uint8_t *) ireq->i_data+off, ireq->i_len);
635                 FREE(p, M_TEMP);
636         } else
637                 ireq->i_len = 0;
638 bad:
639         if (ni != NULL)
640                 ieee80211_free_node(ni);
641         return error;
642 }
643
644 static int
645 ieee80211_ioctl_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
646 {
647         uint8_t macaddr[IEEE80211_ADDR_LEN];
648         const int off = __offsetof(struct ieee80211req_sta_req, info);
649         struct ieee80211_node *ni;
650         int error;
651
652         if (ireq->i_len < sizeof(struct ieee80211req_sta_req))
653                 return EFAULT;
654         error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
655         if (error != 0)
656                 return error;
657         if (IEEE80211_ADDR_EQ(macaddr, ic->ic_ifp->if_broadcastaddr)) {
658                 ni = NULL;
659         } else {
660                 ni = ieee80211_find_node(&ic->ic_sta, macaddr);
661                 if (ni == NULL)
662                         return EINVAL;
663         }
664         return getstainfo_common(ic, ireq, ni, off);
665 }
666
667 #ifdef COMPAT_FREEBSD6
668 #define IEEE80211_IOC_STA_INFO_OLD      45
669
670 static int
671 old_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
672 {
673         if (ireq->i_len < sizeof(struct ieee80211req_sta_info))
674                 return EFAULT;
675         return getstainfo_common(ic, ireq, NULL, 0);
676 }
677 #endif /* COMPAT_FREEBSD6 */
678
679 static int
680 ieee80211_ioctl_getstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
681 {
682         struct ieee80211_node *ni;
683         struct ieee80211req_sta_txpow txpow;
684         int error;
685
686         if (ireq->i_len != sizeof(txpow))
687                 return EINVAL;
688         error = copyin(ireq->i_data, &txpow, sizeof(txpow));
689         if (error != 0)
690                 return error;
691         ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
692         if (ni == NULL)
693                 return EINVAL;          /* XXX */
694         txpow.it_txpow = ni->ni_txpower;
695         error = copyout(&txpow, ireq->i_data, sizeof(txpow));
696         ieee80211_free_node(ni);
697         return error;
698 }
699
700 static int
701 ieee80211_ioctl_getwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
702 {
703         struct ieee80211_wme_state *wme = &ic->ic_wme;
704         struct wmeParams *wmep;
705         int ac;
706
707         if ((ic->ic_caps & IEEE80211_C_WME) == 0)
708                 return EINVAL;
709
710         ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
711         if (ac >= WME_NUM_AC)
712                 ac = WME_AC_BE;
713         if (ireq->i_len & IEEE80211_WMEPARAM_BSS)
714                 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
715         else
716                 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
717         switch (ireq->i_type) {
718         case IEEE80211_IOC_WME_CWMIN:           /* WME: CWmin */
719                 ireq->i_val = wmep->wmep_logcwmin;
720                 break;
721         case IEEE80211_IOC_WME_CWMAX:           /* WME: CWmax */
722                 ireq->i_val = wmep->wmep_logcwmax;
723                 break;
724         case IEEE80211_IOC_WME_AIFS:            /* WME: AIFS */
725                 ireq->i_val = wmep->wmep_aifsn;
726                 break;
727         case IEEE80211_IOC_WME_TXOPLIMIT:       /* WME: txops limit */
728                 ireq->i_val = wmep->wmep_txopLimit;
729                 break;
730         case IEEE80211_IOC_WME_ACM:             /* WME: ACM (bss only) */
731                 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
732                 ireq->i_val = wmep->wmep_acm;
733                 break;
734         case IEEE80211_IOC_WME_ACKPOLICY:       /* WME: ACK policy (!bss only)*/
735                 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
736                 ireq->i_val = !wmep->wmep_noackPolicy;
737                 break;
738         }
739         return 0;
740 }
741
742 static int
743 ieee80211_ioctl_getmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
744 {
745         const struct ieee80211_aclator *acl = ic->ic_acl;
746
747         return (acl == NULL ? EINVAL : acl->iac_getioctl(ic, ireq));
748 }
749
750 /*
751  * Return the current ``state'' of an Atheros capbility.
752  * If associated in station mode report the negotiated
753  * setting. Otherwise report the current setting.
754  */
755 static int
756 getathcap(struct ieee80211com *ic, int cap)
757 {
758         if (ic->ic_opmode == IEEE80211_M_STA && ic->ic_state == IEEE80211_S_RUN)
759                 return IEEE80211_ATH_CAP(ic, ic->ic_bss, cap) != 0;
760         else
761                 return (ic->ic_flags & cap) != 0;
762 }
763
764 static int
765 ieee80211_ioctl_getcurchan(struct ieee80211com *ic, struct ieee80211req *ireq)
766 {
767         if (ireq->i_len != sizeof(struct ieee80211_channel))
768                 return EINVAL;
769         return copyout(ic->ic_curchan, ireq->i_data, sizeof(*ic->ic_curchan));
770 }
771
772 /*
773  * When building the kernel with -O2 on the i386 architecture, gcc
774  * seems to want to inline this function into ieee80211_ioctl()
775  * (which is the only routine that calls it). When this happens,
776  * ieee80211_ioctl() ends up consuming an additional 2K of stack
777  * space. (Exactly why it needs so much is unclear.) The problem
778  * is that it's possible for ieee80211_ioctl() to invoke other
779  * routines (including driver init functions) which could then find
780  * themselves perilously close to exhausting the stack.
781  *
782  * To avoid this, we deliberately prevent gcc from inlining this
783  * routine. Another way to avoid this is to use less agressive
784  * optimization when compiling this file (i.e. -O instead of -O2)
785  * but special-casing the compilation of this one module in the
786  * build system would be awkward.
787  */
788 #ifdef __GNUC__
789 __attribute__ ((noinline))
790 #endif
791 static int
792 ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
793 {
794         const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
795         int error = 0;
796         u_int kid, len, m;
797         uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
798         char tmpssid[IEEE80211_NWID_LEN];
799
800         switch (ireq->i_type) {
801         case IEEE80211_IOC_SSID:
802                 switch (ic->ic_state) {
803                 case IEEE80211_S_INIT:
804                 case IEEE80211_S_SCAN:
805                         ireq->i_len = ic->ic_des_ssid[0].len;
806                         memcpy(tmpssid, ic->ic_des_ssid[0].ssid, ireq->i_len);
807                         break;
808                 default:
809                         ireq->i_len = ic->ic_bss->ni_esslen;
810                         memcpy(tmpssid, ic->ic_bss->ni_essid,
811                                 ireq->i_len);
812                         break;
813                 }
814                 error = copyout(tmpssid, ireq->i_data, ireq->i_len);
815                 break;
816         case IEEE80211_IOC_NUMSSIDS:
817                 ireq->i_val = 1;
818                 break;
819         case IEEE80211_IOC_WEP:
820                 if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0)
821                         ireq->i_val = IEEE80211_WEP_OFF;
822                 else if (ic->ic_flags & IEEE80211_F_DROPUNENC)
823                         ireq->i_val = IEEE80211_WEP_ON;
824                 else
825                         ireq->i_val = IEEE80211_WEP_MIXED;
826                 break;
827         case IEEE80211_IOC_WEPKEY:
828                 kid = (u_int) ireq->i_val;
829                 if (kid >= IEEE80211_WEP_NKID)
830                         return EINVAL;
831                 len = (u_int) ic->ic_nw_keys[kid].wk_keylen;
832                 /* NB: only root can read WEP keys */
833                 if (priv_check(curthread, PRIV_NET80211_GETKEY) == 0) {
834                         bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
835                 } else {
836                         bzero(tmpkey, len);
837                 }
838                 ireq->i_len = len;
839                 error = copyout(tmpkey, ireq->i_data, len);
840                 break;
841         case IEEE80211_IOC_NUMWEPKEYS:
842                 ireq->i_val = IEEE80211_WEP_NKID;
843                 break;
844         case IEEE80211_IOC_WEPTXKEY:
845                 ireq->i_val = ic->ic_def_txkey;
846                 break;
847         case IEEE80211_IOC_AUTHMODE:
848                 if (ic->ic_flags & IEEE80211_F_WPA)
849                         ireq->i_val = IEEE80211_AUTH_WPA;
850                 else
851                         ireq->i_val = ic->ic_bss->ni_authmode;
852                 break;
853         case IEEE80211_IOC_CHANNEL:
854                 ireq->i_val = ieee80211_chan2ieee(ic, ic->ic_curchan);
855                 break;
856         case IEEE80211_IOC_POWERSAVE:
857                 if (ic->ic_flags & IEEE80211_F_PMGTON)
858                         ireq->i_val = IEEE80211_POWERSAVE_ON;
859                 else
860                         ireq->i_val = IEEE80211_POWERSAVE_OFF;
861                 break;
862         case IEEE80211_IOC_POWERSAVESLEEP:
863                 ireq->i_val = ic->ic_lintval;
864                 break;
865         case IEEE80211_IOC_RTSTHRESHOLD:
866                 ireq->i_val = ic->ic_rtsthreshold;
867                 break;
868         case IEEE80211_IOC_PROTMODE:
869                 ireq->i_val = ic->ic_protmode;
870                 break;
871         case IEEE80211_IOC_TXPOWER:
872                 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
873                         return EINVAL;
874                 ireq->i_val = ic->ic_txpowlimit;
875                 break;
876         case IEEE80211_IOC_MCASTCIPHER:
877                 ireq->i_val = rsn->rsn_mcastcipher;
878                 break;
879         case IEEE80211_IOC_MCASTKEYLEN:
880                 ireq->i_val = rsn->rsn_mcastkeylen;
881                 break;
882         case IEEE80211_IOC_UCASTCIPHERS:
883                 ireq->i_val = 0;
884                 for (m = 0x1; m != 0; m <<= 1)
885                         if (rsn->rsn_ucastcipherset & m)
886                                 ireq->i_val |= 1<<cap2cipher(m);
887                 break;
888         case IEEE80211_IOC_UCASTCIPHER:
889                 ireq->i_val = rsn->rsn_ucastcipher;
890                 break;
891         case IEEE80211_IOC_UCASTKEYLEN:
892                 ireq->i_val = rsn->rsn_ucastkeylen;
893                 break;
894         case IEEE80211_IOC_KEYMGTALGS:
895                 ireq->i_val = rsn->rsn_keymgmtset;
896                 break;
897         case IEEE80211_IOC_RSNCAPS:
898                 ireq->i_val = rsn->rsn_caps;
899                 break;
900         case IEEE80211_IOC_WPA:
901                 switch (ic->ic_flags & IEEE80211_F_WPA) {
902                 case IEEE80211_F_WPA1:
903                         ireq->i_val = 1;
904                         break;
905                 case IEEE80211_F_WPA2:
906                         ireq->i_val = 2;
907                         break;
908                 case IEEE80211_F_WPA1 | IEEE80211_F_WPA2:
909                         ireq->i_val = 3;
910                         break;
911                 default:
912                         ireq->i_val = 0;
913                         break;
914                 }
915                 break;
916         case IEEE80211_IOC_CHANLIST:
917                 error = ieee80211_ioctl_getchanlist(ic, ireq);
918                 break;
919         case IEEE80211_IOC_ROAMING:
920                 ireq->i_val = ic->ic_roaming;
921                 break;
922         case IEEE80211_IOC_PRIVACY:
923                 ireq->i_val = (ic->ic_flags & IEEE80211_F_PRIVACY) != 0;
924                 break;
925         case IEEE80211_IOC_DROPUNENCRYPTED:
926                 ireq->i_val = (ic->ic_flags & IEEE80211_F_DROPUNENC) != 0;
927                 break;
928         case IEEE80211_IOC_COUNTERMEASURES:
929                 ireq->i_val = (ic->ic_flags & IEEE80211_F_COUNTERM) != 0;
930                 break;
931         case IEEE80211_IOC_DRIVER_CAPS:
932                 ireq->i_val = ic->ic_caps>>16;
933                 ireq->i_len = ic->ic_caps&0xffff;
934                 break;
935         case IEEE80211_IOC_WME:
936                 ireq->i_val = (ic->ic_flags & IEEE80211_F_WME) != 0;
937                 break;
938         case IEEE80211_IOC_HIDESSID:
939                 ireq->i_val = (ic->ic_flags & IEEE80211_F_HIDESSID) != 0;
940                 break;
941         case IEEE80211_IOC_APBRIDGE:
942                 ireq->i_val = (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0;
943                 break;
944         case IEEE80211_IOC_OPTIE:
945                 if (ic->ic_opt_ie == NULL)
946                         return EINVAL;
947                 /* NB: truncate, caller can check length */
948                 if (ireq->i_len > ic->ic_opt_ie_len)
949                         ireq->i_len = ic->ic_opt_ie_len;
950                 error = copyout(ic->ic_opt_ie, ireq->i_data, ireq->i_len);
951                 break;
952         case IEEE80211_IOC_WPAKEY:
953                 error = ieee80211_ioctl_getkey(ic, ireq);
954                 break;
955         case IEEE80211_IOC_CHANINFO:
956                 error = ieee80211_ioctl_getchaninfo(ic, ireq);
957                 break;
958         case IEEE80211_IOC_BSSID:
959                 if (ireq->i_len != IEEE80211_ADDR_LEN)
960                         return EINVAL;
961                 error = copyout(ic->ic_state == IEEE80211_S_RUN ?
962                                         ic->ic_bss->ni_bssid :
963                                         ic->ic_des_bssid,
964                                 ireq->i_data, ireq->i_len);
965                 break;
966         case IEEE80211_IOC_WPAIE:
967                 error = ieee80211_ioctl_getwpaie(ic, ireq, ireq->i_type);
968                 break;
969         case IEEE80211_IOC_WPAIE2:
970                 error = ieee80211_ioctl_getwpaie(ic, ireq, ireq->i_type);
971                 break;
972 #ifdef COMPAT_FREEBSD6
973         case IEEE80211_IOC_SCAN_RESULTS_OLD:
974                 error = old_getscanresults(ic, ireq);
975                 break;
976 #endif
977         case IEEE80211_IOC_SCAN_RESULTS:
978                 error = ieee80211_ioctl_getscanresults(ic, ireq);
979                 break;
980         case IEEE80211_IOC_STA_STATS:
981                 error = ieee80211_ioctl_getstastats(ic, ireq);
982                 break;
983         case IEEE80211_IOC_TXPOWMAX:
984                 ireq->i_val = ic->ic_bss->ni_txpower;
985                 break;
986         case IEEE80211_IOC_STA_TXPOW:
987                 error = ieee80211_ioctl_getstatxpow(ic, ireq);
988                 break;
989 #ifdef COMPAT_FREEBSD6
990         case IEEE80211_IOC_STA_INFO_OLD:
991                 error = old_getstainfo(ic, ireq);
992                 break;
993 #endif
994         case IEEE80211_IOC_STA_INFO:
995                 error = ieee80211_ioctl_getstainfo(ic, ireq);
996                 break;
997         case IEEE80211_IOC_WME_CWMIN:           /* WME: CWmin */
998         case IEEE80211_IOC_WME_CWMAX:           /* WME: CWmax */
999         case IEEE80211_IOC_WME_AIFS:            /* WME: AIFS */
1000         case IEEE80211_IOC_WME_TXOPLIMIT:       /* WME: txops limit */
1001         case IEEE80211_IOC_WME_ACM:             /* WME: ACM (bss only) */
1002         case IEEE80211_IOC_WME_ACKPOLICY:       /* WME: ACK policy (bss only) */
1003                 error = ieee80211_ioctl_getwmeparam(ic, ireq);
1004                 break;
1005         case IEEE80211_IOC_DTIM_PERIOD:
1006                 ireq->i_val = ic->ic_dtim_period;
1007                 break;
1008         case IEEE80211_IOC_BEACON_INTERVAL:
1009                 /* NB: get from ic_bss for station mode */
1010                 ireq->i_val = ic->ic_bss->ni_intval;
1011                 break;
1012         case IEEE80211_IOC_PUREG:
1013                 ireq->i_val = (ic->ic_flags & IEEE80211_F_PUREG) != 0;
1014                 break;
1015         case IEEE80211_IOC_FF:
1016                 ireq->i_val = getathcap(ic, IEEE80211_F_FF);
1017                 break;
1018         case IEEE80211_IOC_TURBOP:
1019                 ireq->i_val = getathcap(ic, IEEE80211_F_TURBOP);
1020                 break;
1021         case IEEE80211_IOC_BGSCAN:
1022                 ireq->i_val = (ic->ic_flags & IEEE80211_F_BGSCAN) != 0;
1023                 break;
1024         case IEEE80211_IOC_BGSCAN_IDLE:
1025                 ireq->i_val = ic->ic_bgscanidle*hz/1000;        /* ms */
1026                 break;
1027         case IEEE80211_IOC_BGSCAN_INTERVAL:
1028                 ireq->i_val = ic->ic_bgscanintvl/hz;            /* seconds */
1029                 break;
1030         case IEEE80211_IOC_SCANVALID:
1031                 ireq->i_val = ic->ic_scanvalid/hz;              /* seconds */
1032                 break;
1033         case IEEE80211_IOC_ROAM_RSSI_11A:
1034                 ireq->i_val = ic->ic_roam.rssi11a;
1035                 break;
1036         case IEEE80211_IOC_ROAM_RSSI_11B:
1037                 ireq->i_val = ic->ic_roam.rssi11bOnly;
1038                 break;
1039         case IEEE80211_IOC_ROAM_RSSI_11G:
1040                 ireq->i_val = ic->ic_roam.rssi11b;
1041                 break;
1042         case IEEE80211_IOC_ROAM_RATE_11A:
1043                 ireq->i_val = ic->ic_roam.rate11a;
1044                 break;
1045         case IEEE80211_IOC_ROAM_RATE_11B:
1046                 ireq->i_val = ic->ic_roam.rate11bOnly;
1047                 break;
1048         case IEEE80211_IOC_ROAM_RATE_11G:
1049                 ireq->i_val = ic->ic_roam.rate11b;
1050                 break;
1051         case IEEE80211_IOC_MCAST_RATE:
1052                 ireq->i_val = ic->ic_mcast_rate;
1053                 break;
1054         case IEEE80211_IOC_FRAGTHRESHOLD:
1055                 ireq->i_val = ic->ic_fragthreshold;
1056                 break;
1057         case IEEE80211_IOC_MACCMD:
1058                 error = ieee80211_ioctl_getmaccmd(ic, ireq);
1059                 break;
1060         case IEEE80211_IOC_BURST:
1061                 ireq->i_val = (ic->ic_flags & IEEE80211_F_BURST) != 0;
1062                 break;
1063         case IEEE80211_IOC_BMISSTHRESHOLD:
1064                 ireq->i_val = ic->ic_bmissthreshold;
1065                 break;
1066         case IEEE80211_IOC_CURCHAN:
1067                 error = ieee80211_ioctl_getcurchan(ic, ireq);
1068                 break;
1069         case IEEE80211_IOC_SHORTGI:
1070                 ireq->i_val = 0;
1071                 if (ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI20)
1072                         ireq->i_val |= IEEE80211_HTCAP_SHORTGI20;
1073                 if (ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI40)
1074                         ireq->i_val |= IEEE80211_HTCAP_SHORTGI40;
1075                 break;
1076         case IEEE80211_IOC_AMPDU:
1077                 ireq->i_val = 0;
1078                 if (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_TX)
1079                         ireq->i_val |= 1;
1080                 if (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_RX)
1081                         ireq->i_val |= 2;
1082                 break;
1083         case IEEE80211_IOC_AMPDU_LIMIT:
1084                 ireq->i_val = ic->ic_ampdu_limit;       /* XXX truncation? */
1085                 break;
1086         case IEEE80211_IOC_AMPDU_DENSITY:
1087                 ireq->i_val = ic->ic_ampdu_density;
1088                 break;
1089         case IEEE80211_IOC_AMSDU:
1090                 ireq->i_val = 0;
1091                 if (ic->ic_flags_ext & IEEE80211_FEXT_AMSDU_TX)
1092                         ireq->i_val |= 1;
1093                 if (ic->ic_flags_ext & IEEE80211_FEXT_AMSDU_RX)
1094                         ireq->i_val |= 2;
1095                 break;
1096         case IEEE80211_IOC_AMSDU_LIMIT:
1097                 ireq->i_val = ic->ic_amsdu_limit;       /* XXX truncation? */
1098                 break;
1099         case IEEE80211_IOC_PUREN:
1100                 ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_PUREN) != 0;
1101                 break;
1102         case IEEE80211_IOC_DOTH:
1103                 ireq->i_val = (ic->ic_flags & IEEE80211_F_DOTH) != 0;
1104                 break;
1105         case IEEE80211_IOC_HTCOMPAT:
1106                 ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) != 0;
1107                 break;
1108         default:
1109                 error = EINVAL;
1110                 break;
1111         }
1112         return error;
1113 }
1114
1115 static int
1116 ieee80211_ioctl_setoptie(struct ieee80211com *ic, struct ieee80211req *ireq)
1117 {
1118         int error;
1119         void *ie, *oie;
1120
1121         /*
1122          * NB: Doing this for ap operation could be useful (e.g. for
1123          *     WPA and/or WME) except that it typically is worthless
1124          *     without being able to intervene when processing
1125          *     association response frames--so disallow it for now.
1126          */
1127         if (ic->ic_opmode != IEEE80211_M_STA)
1128                 return EINVAL;
1129         if (ireq->i_len > IEEE80211_MAX_OPT_IE)
1130                 return EINVAL;
1131         /* NB: data.length is validated by the wireless extensions code */
1132         /* XXX M_WAITOK after driver lock released */
1133         if (ireq->i_len > 0) {
1134                 MALLOC(ie, void *, ireq->i_len, M_DEVBUF, M_NOWAIT);
1135                 if (ie == NULL)
1136                         return ENOMEM;
1137                 error = copyin(ireq->i_data, ie, ireq->i_len);
1138                 if (error) {
1139                         FREE(ie, M_DEVBUF);
1140                         return error;
1141                 }
1142         } else {
1143                 ie = NULL;
1144                 ireq->i_len = 0;
1145         }
1146         /* XXX sanity check data? */
1147         oie = ic->ic_opt_ie;
1148         ic->ic_opt_ie = ie;
1149         ic->ic_opt_ie_len = ireq->i_len;
1150         if (oie != NULL)
1151                 FREE(oie, M_DEVBUF);
1152         return 0;
1153 }
1154
1155 static int
1156 ieee80211_ioctl_setkey(struct ieee80211com *ic, struct ieee80211req *ireq)
1157 {
1158         struct ieee80211req_key ik;
1159         struct ieee80211_node *ni;
1160         struct ieee80211_key *wk;
1161         uint16_t kid;
1162         int error;
1163
1164         if (ireq->i_len != sizeof(ik))
1165                 return EINVAL;
1166         error = copyin(ireq->i_data, &ik, sizeof(ik));
1167         if (error)
1168                 return error;
1169         /* NB: cipher support is verified by ieee80211_crypt_newkey */
1170         /* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */
1171         if (ik.ik_keylen > sizeof(ik.ik_keydata))
1172                 return E2BIG;
1173         kid = ik.ik_keyix;
1174         if (kid == IEEE80211_KEYIX_NONE) {
1175                 /* XXX unicast keys currently must be tx/rx */
1176                 if (ik.ik_flags != (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))
1177                         return EINVAL;
1178                 if (ic->ic_opmode == IEEE80211_M_STA) {
1179                         ni = ieee80211_ref_node(ic->ic_bss);
1180                         if (!IEEE80211_ADDR_EQ(ik.ik_macaddr, ni->ni_bssid)) {
1181                                 ieee80211_free_node(ni);
1182                                 return EADDRNOTAVAIL;
1183                         }
1184                 } else {
1185                         ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
1186                         if (ni == NULL)
1187                                 return ENOENT;
1188                 }
1189                 wk = &ni->ni_ucastkey;
1190         } else {
1191                 if (kid >= IEEE80211_WEP_NKID)
1192                         return EINVAL;
1193                 wk = &ic->ic_nw_keys[kid];
1194                 /*
1195                  * Global slots start off w/o any assigned key index.
1196                  * Force one here for consistency with IEEE80211_IOC_WEPKEY.
1197                  */
1198                 if (wk->wk_keyix == IEEE80211_KEYIX_NONE)
1199                         wk->wk_keyix = kid;
1200                 ni = NULL;
1201         }
1202         error = 0;
1203         ieee80211_key_update_begin(ic);
1204         if (ieee80211_crypto_newkey(ic, ik.ik_type, ik.ik_flags, wk)) {
1205                 wk->wk_keylen = ik.ik_keylen;
1206                 /* NB: MIC presence is implied by cipher type */
1207                 if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
1208                         wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
1209                 wk->wk_keyrsc = ik.ik_keyrsc;
1210                 wk->wk_keytsc = 0;                      /* new key, reset */
1211                 memset(wk->wk_key, 0, sizeof(wk->wk_key));
1212                 memcpy(wk->wk_key, ik.ik_keydata, ik.ik_keylen);
1213                 if (!ieee80211_crypto_setkey(ic, wk,
1214                     ni != NULL ? ni->ni_macaddr : ik.ik_macaddr))
1215                         error = EIO;
1216                 else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT))
1217                         ic->ic_def_txkey = kid;
1218         } else
1219                 error = ENXIO;
1220         ieee80211_key_update_end(ic);
1221         if (ni != NULL)
1222                 ieee80211_free_node(ni);
1223         return error;
1224 }
1225
1226 static int
1227 ieee80211_ioctl_delkey(struct ieee80211com *ic, struct ieee80211req *ireq)
1228 {
1229         struct ieee80211req_del_key dk;
1230         int kid, error;
1231
1232         if (ireq->i_len != sizeof(dk))
1233                 return EINVAL;
1234         error = copyin(ireq->i_data, &dk, sizeof(dk));
1235         if (error)
1236                 return error;
1237         kid = dk.idk_keyix;
1238         /* XXX uint8_t -> uint16_t */
1239         if (dk.idk_keyix == (uint8_t) IEEE80211_KEYIX_NONE) {
1240                 struct ieee80211_node *ni;
1241
1242                 if (ic->ic_opmode == IEEE80211_M_STA) {
1243                         ni = ieee80211_ref_node(ic->ic_bss);
1244                         if (!IEEE80211_ADDR_EQ(dk.idk_macaddr, ni->ni_bssid)) {
1245                                 ieee80211_free_node(ni);
1246                                 return EADDRNOTAVAIL;
1247                         }
1248                 } else {
1249                         ni = ieee80211_find_node(&ic->ic_sta, dk.idk_macaddr);
1250                         if (ni == NULL)
1251                                 return ENOENT;
1252                 }
1253                 /* XXX error return */
1254                 ieee80211_node_delucastkey(ni);
1255                 ieee80211_free_node(ni);
1256         } else {
1257                 if (kid >= IEEE80211_WEP_NKID)
1258                         return EINVAL;
1259                 /* XXX error return */
1260                 ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[kid]);
1261         }
1262         return 0;
1263 }
1264
1265 static void
1266 domlme(void *arg, struct ieee80211_node *ni)
1267 {
1268         struct ieee80211com *ic = ni->ni_ic;
1269         struct ieee80211req_mlme *mlme = arg;
1270
1271         if (ni->ni_associd != 0) {
1272                 IEEE80211_SEND_MGMT(ic, ni,
1273                         mlme->im_op == IEEE80211_MLME_DEAUTH ?
1274                                 IEEE80211_FC0_SUBTYPE_DEAUTH :
1275                                 IEEE80211_FC0_SUBTYPE_DISASSOC,
1276                         mlme->im_reason);
1277         }
1278         ieee80211_node_leave(ic, ni);
1279 }
1280
1281 struct scanlookup {
1282         const uint8_t *mac;
1283         int esslen;
1284         const uint8_t *essid;
1285         const struct ieee80211_scan_entry *se;
1286 };
1287
1288 /*
1289  * Match mac address and any ssid.
1290  */
1291 static void
1292 mlmelookup(void *arg, const struct ieee80211_scan_entry *se)
1293 {
1294         struct scanlookup *look = arg;
1295
1296         if (!IEEE80211_ADDR_EQ(look->mac, se->se_macaddr))
1297                 return;
1298         if (look->esslen != 0) {
1299                 if (se->se_ssid[1] != look->esslen)
1300                         return;
1301                 if (memcmp(look->essid, se->se_ssid+2, look->esslen))
1302                         return;
1303         }
1304         look->se = se;
1305 }
1306
1307 static int
1308 ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq)
1309 {
1310         struct ieee80211req_mlme mlme;
1311         struct ieee80211_node *ni;
1312         int error;
1313
1314         if (ireq->i_len != sizeof(mlme))
1315                 return EINVAL;
1316         error = copyin(ireq->i_data, &mlme, sizeof(mlme));
1317         if (error)
1318                 return error;
1319         switch (mlme.im_op) {
1320         case IEEE80211_MLME_ASSOC:
1321                 /* XXX ibss/ahdemo */
1322                 if (ic->ic_opmode == IEEE80211_M_STA) {
1323                         struct scanlookup lookup;
1324
1325                         lookup.se = NULL;
1326                         lookup.mac = mlme.im_macaddr;
1327                         /* XXX use revised api w/ explicit ssid */
1328                         lookup.esslen = ic->ic_des_ssid[0].len;
1329                         lookup.essid = ic->ic_des_ssid[0].ssid;
1330                         ieee80211_scan_iterate(ic, mlmelookup, &lookup);
1331                         if (lookup.se != NULL &&
1332                             ieee80211_sta_join(ic, lookup.se))
1333                                 return 0;
1334                 }
1335                 return EINVAL;
1336         case IEEE80211_MLME_DISASSOC:
1337         case IEEE80211_MLME_DEAUTH:
1338                 switch (ic->ic_opmode) {
1339                 case IEEE80211_M_STA:
1340                         /* XXX not quite right */
1341                         ieee80211_new_state(ic, IEEE80211_S_INIT,
1342                                 mlme.im_reason);
1343                         break;
1344                 case IEEE80211_M_HOSTAP:
1345                         /* NB: the broadcast address means do 'em all */
1346                         if (!IEEE80211_ADDR_EQ(mlme.im_macaddr, ic->ic_ifp->if_broadcastaddr)) {
1347                                 if ((ni = ieee80211_find_node(&ic->ic_sta,
1348                                                 mlme.im_macaddr)) == NULL)
1349                                         return EINVAL;
1350                                 domlme(&mlme, ni);
1351                                 ieee80211_free_node(ni);
1352                         } else {
1353                                 ieee80211_iterate_nodes(&ic->ic_sta,
1354                                                 domlme, &mlme);
1355                         }
1356                         break;
1357                 default:
1358                         return EINVAL;
1359                 }
1360                 break;
1361         case IEEE80211_MLME_AUTHORIZE:
1362         case IEEE80211_MLME_UNAUTHORIZE:
1363                 if (ic->ic_opmode != IEEE80211_M_HOSTAP)
1364                         return EINVAL;
1365                 ni = ieee80211_find_node(&ic->ic_sta, mlme.im_macaddr);
1366                 if (ni == NULL)
1367                         return EINVAL;
1368                 if (mlme.im_op == IEEE80211_MLME_AUTHORIZE)
1369                         ieee80211_node_authorize(ni);
1370                 else
1371                         ieee80211_node_unauthorize(ni);
1372                 ieee80211_free_node(ni);
1373                 break;
1374         default:
1375                 return EINVAL;
1376         }
1377         return 0;
1378 }
1379
1380 static int
1381 ieee80211_ioctl_macmac(struct ieee80211com *ic, struct ieee80211req *ireq)
1382 {
1383         uint8_t mac[IEEE80211_ADDR_LEN];
1384         const struct ieee80211_aclator *acl = ic->ic_acl;
1385         int error;
1386
1387         if (ireq->i_len != sizeof(mac))
1388                 return EINVAL;
1389         error = copyin(ireq->i_data, mac, ireq->i_len);
1390         if (error)
1391                 return error;
1392         if (acl == NULL) {
1393                 acl = ieee80211_aclator_get("mac");
1394                 if (acl == NULL || !acl->iac_attach(ic))
1395                         return EINVAL;
1396                 ic->ic_acl = acl;
1397         }
1398         if (ireq->i_type == IEEE80211_IOC_ADDMAC)
1399                 acl->iac_add(ic, mac);
1400         else
1401                 acl->iac_remove(ic, mac);
1402         return 0;
1403 }
1404
1405 static int
1406 ieee80211_ioctl_setmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
1407 {
1408         const struct ieee80211_aclator *acl = ic->ic_acl;
1409
1410         switch (ireq->i_val) {
1411         case IEEE80211_MACCMD_POLICY_OPEN:
1412         case IEEE80211_MACCMD_POLICY_ALLOW:
1413         case IEEE80211_MACCMD_POLICY_DENY:
1414                 if (acl == NULL) {
1415                         acl = ieee80211_aclator_get("mac");
1416                         if (acl == NULL || !acl->iac_attach(ic))
1417                                 return EINVAL;
1418                         ic->ic_acl = acl;
1419                 }
1420                 acl->iac_setpolicy(ic, ireq->i_val);
1421                 break;
1422         case IEEE80211_MACCMD_FLUSH:
1423                 if (acl != NULL)
1424                         acl->iac_flush(ic);
1425                 /* NB: silently ignore when not in use */
1426                 break;
1427         case IEEE80211_MACCMD_DETACH:
1428                 if (acl != NULL) {
1429                         ic->ic_acl = NULL;
1430                         acl->iac_detach(ic);
1431                 }
1432                 break;
1433         default:
1434                 if (acl == NULL)
1435                         return EINVAL;
1436                 else
1437                         return acl->iac_setioctl(ic, ireq);
1438         }
1439         return 0;
1440 }
1441
1442 static int
1443 ieee80211_ioctl_setchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
1444 {
1445         struct ieee80211req_chanlist list;
1446         u_char chanlist[IEEE80211_CHAN_BYTES];
1447         int i, j, nchan, error;
1448
1449         if (ireq->i_len != sizeof(list))
1450                 return EINVAL;
1451         error = copyin(ireq->i_data, &list, sizeof(list));
1452         if (error)
1453                 return error;
1454         memset(chanlist, 0, sizeof(chanlist));
1455         /*
1456          * Since channel 0 is not available for DS, channel 1
1457          * is assigned to LSB on WaveLAN.
1458          */
1459         if (ic->ic_phytype == IEEE80211_T_DS)
1460                 i = 1;
1461         else
1462                 i = 0;
1463         nchan = 0;
1464         for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
1465                 /*
1466                  * NB: silently discard unavailable channels so users
1467                  *     can specify 1-255 to get all available channels.
1468                  */
1469                 if (isset(list.ic_channels, j) && isset(ic->ic_chan_avail, i)) {
1470                         setbit(chanlist, i);
1471                         nchan++;
1472                 }
1473         }
1474         if (nchan == 0)
1475                 return EINVAL;
1476         if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&    /* XXX */
1477             isclr(chanlist, ic->ic_bsschan->ic_ieee))
1478                 ic->ic_bsschan = IEEE80211_CHAN_ANYC;
1479         memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
1480         return IS_UP_AUTO(ic) ? ieee80211_init(ic, RESCAN) : 0;
1481 }
1482
1483 static int
1484 ieee80211_ioctl_setstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
1485 {
1486         struct ieee80211_node *ni;
1487         uint8_t macaddr[IEEE80211_ADDR_LEN];
1488         int error;
1489
1490         /*
1491          * NB: we could copyin ieee80211req_sta_stats so apps
1492          *     could make selective changes but that's overkill;
1493          *     just clear all stats for now.
1494          */
1495         if (ireq->i_len < IEEE80211_ADDR_LEN)
1496                 return EINVAL;
1497         error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
1498         if (error != 0)
1499                 return error;
1500         ni = ieee80211_find_node(&ic->ic_sta, macaddr);
1501         if (ni == NULL)
1502                 return EINVAL;          /* XXX */
1503         memset(&ni->ni_stats, 0, sizeof(ni->ni_stats));
1504         ieee80211_free_node(ni);
1505         return 0;
1506 }
1507
1508 static int
1509 ieee80211_ioctl_setstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
1510 {
1511         struct ieee80211_node *ni;
1512         struct ieee80211req_sta_txpow txpow;
1513         int error;
1514
1515         if (ireq->i_len != sizeof(txpow))
1516                 return EINVAL;
1517         error = copyin(ireq->i_data, &txpow, sizeof(txpow));
1518         if (error != 0)
1519                 return error;
1520         ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
1521         if (ni == NULL)
1522                 return EINVAL;          /* XXX */
1523         ni->ni_txpower = txpow.it_txpow;
1524         ieee80211_free_node(ni);
1525         return error;
1526 }
1527
1528 static int
1529 ieee80211_ioctl_setwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
1530 {
1531         struct ieee80211_wme_state *wme = &ic->ic_wme;
1532         struct wmeParams *wmep, *chanp;
1533         int isbss, ac;
1534
1535         if ((ic->ic_caps & IEEE80211_C_WME) == 0)
1536                 return EINVAL;
1537
1538         isbss = (ireq->i_len & IEEE80211_WMEPARAM_BSS);
1539         ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
1540         if (ac >= WME_NUM_AC)
1541                 ac = WME_AC_BE;
1542         if (isbss) {
1543                 chanp = &wme->wme_bssChanParams.cap_wmeParams[ac];
1544                 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1545         } else {
1546                 chanp = &wme->wme_chanParams.cap_wmeParams[ac];
1547                 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1548         }
1549         switch (ireq->i_type) {
1550         case IEEE80211_IOC_WME_CWMIN:           /* WME: CWmin */
1551                 if (isbss) {
1552                         wmep->wmep_logcwmin = ireq->i_val;
1553                         if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1554                                 chanp->wmep_logcwmin = ireq->i_val;
1555                 } else {
1556                         wmep->wmep_logcwmin = chanp->wmep_logcwmin =
1557                                 ireq->i_val;
1558                 }
1559                 break;
1560         case IEEE80211_IOC_WME_CWMAX:           /* WME: CWmax */
1561                 if (isbss) {
1562                         wmep->wmep_logcwmax = ireq->i_val;
1563                         if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1564                                 chanp->wmep_logcwmax = ireq->i_val;
1565                 } else {
1566                         wmep->wmep_logcwmax = chanp->wmep_logcwmax =
1567                                 ireq->i_val;
1568                 }
1569                 break;
1570         case IEEE80211_IOC_WME_AIFS:            /* WME: AIFS */
1571                 if (isbss) {
1572                         wmep->wmep_aifsn = ireq->i_val;
1573                         if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1574                                 chanp->wmep_aifsn = ireq->i_val;
1575                 } else {
1576                         wmep->wmep_aifsn = chanp->wmep_aifsn = ireq->i_val;
1577                 }
1578                 break;
1579         case IEEE80211_IOC_WME_TXOPLIMIT:       /* WME: txops limit */
1580                 if (isbss) {
1581                         wmep->wmep_txopLimit = ireq->i_val;
1582                         if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1583                                 chanp->wmep_txopLimit = ireq->i_val;
1584                 } else {
1585                         wmep->wmep_txopLimit = chanp->wmep_txopLimit =
1586                                 ireq->i_val;
1587                 }
1588                 break;
1589         case IEEE80211_IOC_WME_ACM:             /* WME: ACM (bss only) */
1590                 wmep->wmep_acm = ireq->i_val;
1591                 if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1592                         chanp->wmep_acm = ireq->i_val;
1593                 break;
1594         case IEEE80211_IOC_WME_ACKPOLICY:       /* WME: ACK policy (!bss only)*/
1595                 wmep->wmep_noackPolicy = chanp->wmep_noackPolicy =
1596                         (ireq->i_val) == 0;
1597                 break;
1598         }
1599         ieee80211_wme_updateparams(ic);
1600         return 0;
1601 }
1602
1603 static int
1604 cipher2cap(int cipher)
1605 {
1606         switch (cipher) {
1607         case IEEE80211_CIPHER_WEP:      return IEEE80211_C_WEP;
1608         case IEEE80211_CIPHER_AES_OCB:  return IEEE80211_C_AES;
1609         case IEEE80211_CIPHER_AES_CCM:  return IEEE80211_C_AES_CCM;
1610         case IEEE80211_CIPHER_CKIP:     return IEEE80211_C_CKIP;
1611         case IEEE80211_CIPHER_TKIP:     return IEEE80211_C_TKIP;
1612         }
1613         return 0;
1614 }
1615
1616 static int
1617 find11gchannel(struct ieee80211com *ic, int start, int freq)
1618 {
1619         const struct ieee80211_channel *c;
1620         int i;
1621
1622         for (i = start+1; i < ic->ic_nchans; i++) {
1623                 c = &ic->ic_channels[i];
1624                 if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
1625                         return 1;
1626         }
1627         /* NB: should not be needed but in case things are mis-sorted */
1628         for (i = 0; i < start; i++) {
1629                 c = &ic->ic_channels[i];
1630                 if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
1631                         return 1;
1632         }
1633         return 0;
1634 }
1635
1636 static struct ieee80211_channel *
1637 findchannel(struct ieee80211com *ic, int ieee, int mode)
1638 {
1639         static const u_int chanflags[IEEE80211_MODE_MAX] = {
1640                 0,                      /* IEEE80211_MODE_AUTO */
1641                 IEEE80211_CHAN_A,       /* IEEE80211_MODE_11A */
1642                 IEEE80211_CHAN_B,       /* IEEE80211_MODE_11B */
1643                 IEEE80211_CHAN_G,       /* IEEE80211_MODE_11G */
1644                 IEEE80211_CHAN_FHSS,    /* IEEE80211_MODE_FH */
1645                 IEEE80211_CHAN_108A,    /* IEEE80211_MODE_TURBO_A */
1646                 IEEE80211_CHAN_108G,    /* IEEE80211_MODE_TURBO_G */
1647                 IEEE80211_CHAN_STURBO,  /* IEEE80211_MODE_STURBO_A */
1648                 /* NB: handled specially below */
1649                 IEEE80211_CHAN_A,       /* IEEE80211_MODE_11NA */
1650                 IEEE80211_CHAN_G,       /* IEEE80211_MODE_11NG */
1651         };
1652         u_int modeflags;
1653         int i;
1654
1655         KASSERT(mode < IEEE80211_MODE_MAX, ("bad mode %u", mode));
1656         modeflags = chanflags[mode];
1657         KASSERT(modeflags != 0 || mode == IEEE80211_MODE_AUTO,
1658             ("no chanflags for mode %u", mode));
1659         for (i = 0; i < ic->ic_nchans; i++) {
1660                 struct ieee80211_channel *c = &ic->ic_channels[i];
1661
1662                 if (c->ic_ieee != ieee)
1663                         continue;
1664                 if (mode == IEEE80211_MODE_AUTO) {
1665                         /* ignore turbo channels for autoselect */
1666                         if (IEEE80211_IS_CHAN_TURBO(c))
1667                                 continue;
1668                         /*
1669                          * XXX special-case 11b/g channels so we
1670                          *     always select the g channel if both
1671                          *     are present.
1672                          * XXX prefer HT to non-HT?
1673                          */
1674                         if (!IEEE80211_IS_CHAN_B(c) ||
1675                             !find11gchannel(ic, i, c->ic_freq))
1676                                 return c;
1677                 } else {
1678                         /* must check HT specially */
1679                         if ((mode == IEEE80211_MODE_11NA ||
1680                             mode == IEEE80211_MODE_11NG) &&
1681                             !IEEE80211_IS_CHAN_HT(c))
1682                                 continue;
1683                         if ((c->ic_flags & modeflags) == modeflags)
1684                                 return c;
1685                 }
1686         }
1687         return NULL;
1688 }
1689
1690 /*
1691  * Check the specified against any desired mode (aka netband).
1692  * This is only used (presently) when operating in hostap mode
1693  * to enforce consistency.
1694  */
1695 static int
1696 check_mode_consistency(const struct ieee80211_channel *c, int mode)
1697 {
1698         KASSERT(c != IEEE80211_CHAN_ANYC, ("oops, no channel"));
1699
1700         switch (mode) {
1701         case IEEE80211_MODE_11B:
1702                 return (IEEE80211_IS_CHAN_B(c));
1703         case IEEE80211_MODE_11G:
1704                 return (IEEE80211_IS_CHAN_ANYG(c) && !IEEE80211_IS_CHAN_HT(c));
1705         case IEEE80211_MODE_11A:
1706                 return (IEEE80211_IS_CHAN_A(c) && !IEEE80211_IS_CHAN_HT(c));
1707         case IEEE80211_MODE_STURBO_A:
1708                 return (IEEE80211_IS_CHAN_STURBO(c));
1709         case IEEE80211_MODE_11NA:
1710                 return (IEEE80211_IS_CHAN_HTA(c));
1711         case IEEE80211_MODE_11NG:
1712                 return (IEEE80211_IS_CHAN_HTG(c));
1713         }
1714         return 1;
1715
1716 }
1717
1718 /*
1719  * Common code to set the current channel.  If the device
1720  * is up and running this may result in an immediate channel
1721  * change or a kick of the state machine.
1722  */
1723 static int
1724 setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c)
1725 {
1726         int error;
1727
1728         if (c != IEEE80211_CHAN_ANYC) {
1729                 if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1730                     !check_mode_consistency(c, ic->ic_des_mode))
1731                         return EINVAL;
1732                 if (ic->ic_state == IEEE80211_S_RUN && c == ic->ic_curchan)
1733                         return 0;       /* NB: nothing to do */
1734         }
1735         ic->ic_des_chan = c;
1736
1737         error = 0;
1738         if ((ic->ic_opmode == IEEE80211_M_MONITOR ||
1739             ic->ic_opmode == IEEE80211_M_WDS) &&
1740             ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
1741                 /*
1742                  * Monitor and wds modes can switch directly.
1743                  */
1744                 ic->ic_curchan = ic->ic_des_chan;
1745                 if (ic->ic_state == IEEE80211_S_RUN)
1746                         ic->ic_set_channel(ic);
1747         } else {
1748                 /*
1749                  * Need to go through the state machine in case we
1750                  * need to reassociate or the like.  The state machine
1751                  * will pickup the desired channel and avoid scanning.
1752                  */
1753                 if (IS_UP_AUTO(ic))
1754                         error = ieee80211_init(ic, RESCAN);
1755                 else if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
1756                         /*
1757                          * When not up+running and a real channel has
1758                          * been specified fix the current channel so
1759                          * there is immediate feedback; e.g. via ifconfig.
1760                          */
1761                         ic->ic_curchan = ic->ic_des_chan;
1762                 }
1763         }
1764         return error;
1765 }
1766
1767 /*
1768  * Old api for setting the current channel; this is
1769  * deprecated because channel numbers are ambiguous.
1770  */
1771 static int
1772 ieee80211_ioctl_setchannel(struct ieee80211com *ic,
1773         const struct ieee80211req *ireq)
1774 {
1775         struct ieee80211_channel *c;
1776
1777         /* XXX 0xffff overflows 16-bit signed */
1778         if (ireq->i_val == 0 ||
1779             ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) {
1780                 c = IEEE80211_CHAN_ANYC;
1781         } else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX) {
1782                 return EINVAL;
1783         } else {
1784                 struct ieee80211_channel *c2;
1785
1786                 c = findchannel(ic, ireq->i_val, ic->ic_des_mode);
1787                 if (c == NULL) {
1788                         c = findchannel(ic, ireq->i_val,
1789                                 IEEE80211_MODE_AUTO);
1790                         if (c == NULL)
1791                                 return EINVAL;
1792                 }
1793                 /*
1794                  * Fine tune channel selection based on desired mode:
1795                  *   if 11b is requested, find the 11b version of any
1796                  *      11g channel returned,
1797                  *   if static turbo, find the turbo version of any
1798                  *      11a channel return,
1799                  *   if 11na is requested, find the ht version of any
1800                  *      11a channel returned,
1801                  *   if 11ng is requested, find the ht version of any
1802                  *      11g channel returned,
1803                  *   otherwise we should be ok with what we've got.
1804                  */
1805                 switch (ic->ic_des_mode) {
1806                 case IEEE80211_MODE_11B:
1807                         if (IEEE80211_IS_CHAN_ANYG(c)) {
1808                                 c2 = findchannel(ic, ireq->i_val,
1809                                         IEEE80211_MODE_11B);
1810                                 /* NB: should not happen, =>'s 11g w/o 11b */
1811                                 if (c2 != NULL)
1812                                         c = c2;
1813                         }
1814                         break;
1815                 case IEEE80211_MODE_TURBO_A:
1816                         if (IEEE80211_IS_CHAN_A(c)) {
1817                                 c2 = findchannel(ic, ireq->i_val,
1818                                         IEEE80211_MODE_TURBO_A);
1819                                 if (c2 != NULL)
1820                                         c = c2;
1821                         }
1822                         break;
1823                 case IEEE80211_MODE_11NA:
1824                         if (IEEE80211_IS_CHAN_A(c)) {
1825                                 c2 = findchannel(ic, ireq->i_val,
1826                                         IEEE80211_MODE_11NA);
1827                                 if (c2 != NULL)
1828                                         c = c2;
1829                         }
1830                         break;
1831                 case IEEE80211_MODE_11NG:
1832                         if (IEEE80211_IS_CHAN_ANYG(c)) {
1833                                 c2 = findchannel(ic, ireq->i_val,
1834                                         IEEE80211_MODE_11NG);
1835                                 if (c2 != NULL)
1836                                         c = c2;
1837                         }
1838                         break;
1839                 default:                /* NB: no static turboG */
1840                         break;
1841                 }
1842         }
1843         return setcurchan(ic, c);
1844 }
1845
1846 /*
1847  * New/current api for setting the current channel; a complete
1848  * channel description is provide so there is no ambiguity in
1849  * identifying the channel.
1850  */
1851 static int
1852 ieee80211_ioctl_setcurchan(struct ieee80211com *ic,
1853         const struct ieee80211req *ireq)
1854 {
1855         struct ieee80211_channel chan, *c;
1856         int error;
1857
1858         if (ireq->i_len != sizeof(chan))
1859                 return EINVAL;
1860         error = copyin(ireq->i_data, &chan, sizeof(chan));
1861         if (error != 0)
1862                 return error;
1863         /* XXX 0xffff overflows 16-bit signed */
1864         if (chan.ic_freq == 0 || chan.ic_freq == IEEE80211_CHAN_ANY) {
1865                 c = IEEE80211_CHAN_ANYC;
1866         } else {
1867                 c = ieee80211_find_channel(ic, chan.ic_freq, chan.ic_flags);
1868                 if (c == NULL)
1869                         return EINVAL;
1870         }
1871         return setcurchan(ic, c);
1872 }
1873
1874 static int
1875 ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
1876 {
1877         static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
1878         struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
1879         int error;
1880         const struct ieee80211_authenticator *auth;
1881         uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
1882         char tmpssid[IEEE80211_NWID_LEN];
1883         uint8_t tmpbssid[IEEE80211_ADDR_LEN];
1884         struct ieee80211_key *k;
1885         int j, caps;
1886         u_int kid;
1887
1888         error = 0;
1889         switch (ireq->i_type) {
1890         case IEEE80211_IOC_SSID:
1891                 if (ireq->i_val != 0 ||
1892                     ireq->i_len > IEEE80211_NWID_LEN)
1893                         return EINVAL;
1894                 error = copyin(ireq->i_data, tmpssid, ireq->i_len);
1895                 if (error)
1896                         break;
1897                 memset(ic->ic_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
1898                 ic->ic_des_ssid[0].len = ireq->i_len;
1899                 memcpy(ic->ic_des_ssid[0].ssid, tmpssid, ireq->i_len);
1900                 ic->ic_des_nssid = (ireq->i_len > 0);
1901                 if (IS_UP_AUTO(ic))
1902                         error = ieee80211_init(ic, RESCAN);
1903                 break;
1904         case IEEE80211_IOC_WEP:
1905                 switch (ireq->i_val) {
1906                 case IEEE80211_WEP_OFF:
1907                         ic->ic_flags &= ~IEEE80211_F_PRIVACY;
1908                         ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
1909                         break;
1910                 case IEEE80211_WEP_ON:
1911                         ic->ic_flags |= IEEE80211_F_PRIVACY;
1912                         ic->ic_flags |= IEEE80211_F_DROPUNENC;
1913                         break;
1914                 case IEEE80211_WEP_MIXED:
1915                         ic->ic_flags |= IEEE80211_F_PRIVACY;
1916                         ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
1917                         break;
1918                 }
1919                 if (IS_UP_AUTO(ic))
1920                         error = ieee80211_init(ic, RESCAN);
1921                 break;
1922         case IEEE80211_IOC_WEPKEY:
1923                 kid = (u_int) ireq->i_val;
1924                 if (kid >= IEEE80211_WEP_NKID)
1925                         return EINVAL;
1926                 k = &ic->ic_nw_keys[kid];
1927                 if (ireq->i_len == 0) {
1928                         /* zero-len =>'s delete any existing key */
1929                         (void) ieee80211_crypto_delkey(ic, k);
1930                         break;
1931                 }
1932                 if (ireq->i_len > sizeof(tmpkey))
1933                         return EINVAL;
1934                 memset(tmpkey, 0, sizeof(tmpkey));
1935                 error = copyin(ireq->i_data, tmpkey, ireq->i_len);
1936                 if (error)
1937                         break;
1938                 ieee80211_key_update_begin(ic);
1939                 k->wk_keyix = kid;      /* NB: force fixed key id */
1940                 if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
1941                     IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
1942                         k->wk_keylen = ireq->i_len;
1943                         memcpy(k->wk_key, tmpkey, sizeof(tmpkey));
1944                         if  (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
1945                                 error = EINVAL;
1946                 } else
1947                         error = EINVAL;
1948                 ieee80211_key_update_end(ic);
1949                 break;
1950         case IEEE80211_IOC_WEPTXKEY:
1951                 kid = (u_int) ireq->i_val;
1952                 if (kid >= IEEE80211_WEP_NKID &&
1953                     (uint16_t) kid != IEEE80211_KEYIX_NONE)
1954                         return EINVAL;
1955                 ic->ic_def_txkey = kid;
1956                 break;
1957         case IEEE80211_IOC_AUTHMODE:
1958                 switch (ireq->i_val) {
1959                 case IEEE80211_AUTH_WPA:
1960                 case IEEE80211_AUTH_8021X:      /* 802.1x */
1961                 case IEEE80211_AUTH_OPEN:       /* open */
1962                 case IEEE80211_AUTH_SHARED:     /* shared-key */
1963                 case IEEE80211_AUTH_AUTO:       /* auto */
1964                         auth = ieee80211_authenticator_get(ireq->i_val);
1965                         if (auth == NULL)
1966                                 return EINVAL;
1967                         break;
1968                 default:
1969                         return EINVAL;
1970                 }
1971                 switch (ireq->i_val) {
1972                 case IEEE80211_AUTH_WPA:        /* WPA w/ 802.1x */
1973                         ic->ic_flags |= IEEE80211_F_PRIVACY;
1974                         ireq->i_val = IEEE80211_AUTH_8021X;
1975                         break;
1976                 case IEEE80211_AUTH_OPEN:       /* open */
1977                         ic->ic_flags &= ~(IEEE80211_F_WPA|IEEE80211_F_PRIVACY);
1978                         break;
1979                 case IEEE80211_AUTH_SHARED:     /* shared-key */
1980                 case IEEE80211_AUTH_8021X:      /* 802.1x */
1981                         ic->ic_flags &= ~IEEE80211_F_WPA;
1982                         /* both require a key so mark the PRIVACY capability */
1983                         ic->ic_flags |= IEEE80211_F_PRIVACY;
1984                         break;
1985                 case IEEE80211_AUTH_AUTO:       /* auto */
1986                         ic->ic_flags &= ~IEEE80211_F_WPA;
1987                         /* XXX PRIVACY handling? */
1988                         /* XXX what's the right way to do this? */
1989                         break;
1990                 }
1991                 /* NB: authenticator attach/detach happens on state change */
1992                 ic->ic_bss->ni_authmode = ireq->i_val;
1993                 /* XXX mixed/mode/usage? */
1994                 ic->ic_auth = auth;
1995                 if (IS_UP_AUTO(ic))
1996                         error = ieee80211_init(ic, RESCAN);
1997                 break;
1998         case IEEE80211_IOC_CHANNEL:
1999                 error = ieee80211_ioctl_setchannel(ic, ireq);
2000                 break;
2001         case IEEE80211_IOC_POWERSAVE:
2002                 switch (ireq->i_val) {
2003                 case IEEE80211_POWERSAVE_OFF:
2004                         if (ic->ic_flags & IEEE80211_F_PMGTON) {
2005                                 ic->ic_flags &= ~IEEE80211_F_PMGTON;
2006                                 error = ENETRESET;
2007                         }
2008                         break;
2009                 case IEEE80211_POWERSAVE_ON:
2010                         if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
2011                                 error = EINVAL;
2012                         else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
2013                                 ic->ic_flags |= IEEE80211_F_PMGTON;
2014                                 error = ENETRESET;
2015                         }
2016                         break;
2017                 default:
2018                         error = EINVAL;
2019                         break;
2020                 }
2021                 if (error == ENETRESET) {
2022                         /*
2023                          * Switching in+out of power save mode
2024                          * should not require a state change.
2025                          */
2026                         error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2027                 }
2028                 break;
2029         case IEEE80211_IOC_POWERSAVESLEEP:
2030                 if (ireq->i_val < 0)
2031                         return EINVAL;
2032                 ic->ic_lintval = ireq->i_val;
2033                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2034                 break;
2035         case IEEE80211_IOC_RTSTHRESHOLD:
2036                 if (!(IEEE80211_RTS_MIN <= ireq->i_val &&
2037                       ireq->i_val <= IEEE80211_RTS_MAX))
2038                         return EINVAL;
2039                 ic->ic_rtsthreshold = ireq->i_val;
2040                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2041                 break;
2042         case IEEE80211_IOC_PROTMODE:
2043                 if (ireq->i_val > IEEE80211_PROT_RTSCTS)
2044                         return EINVAL;
2045                 ic->ic_protmode = ireq->i_val;
2046                 /* NB: if not operating in 11g this can wait */
2047                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2048                     IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
2049                         error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2050                 break;
2051         case IEEE80211_IOC_TXPOWER:
2052                 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
2053                         return EINVAL;
2054                 if (!(IEEE80211_TXPOWER_MIN <= ireq->i_val &&
2055                       ireq->i_val <= IEEE80211_TXPOWER_MAX))
2056                         return EINVAL;
2057                 ic->ic_txpowlimit = ireq->i_val;
2058                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2059                 break;
2060         case IEEE80211_IOC_ROAMING:
2061                 if (!(IEEE80211_ROAMING_DEVICE <= ireq->i_val &&
2062                     ireq->i_val <= IEEE80211_ROAMING_MANUAL))
2063                         return EINVAL;
2064                 ic->ic_roaming = ireq->i_val;
2065                 /* XXXX reset? */
2066                 break;
2067         case IEEE80211_IOC_PRIVACY:
2068                 if (ireq->i_val) {
2069                         /* XXX check for key state? */
2070                         ic->ic_flags |= IEEE80211_F_PRIVACY;
2071                 } else
2072                         ic->ic_flags &= ~IEEE80211_F_PRIVACY;
2073                 break;
2074         case IEEE80211_IOC_DROPUNENCRYPTED:
2075                 if (ireq->i_val)
2076                         ic->ic_flags |= IEEE80211_F_DROPUNENC;
2077                 else
2078                         ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
2079                 break;
2080         case IEEE80211_IOC_WPAKEY:
2081                 error = ieee80211_ioctl_setkey(ic, ireq);
2082                 break;
2083         case IEEE80211_IOC_DELKEY:
2084                 error = ieee80211_ioctl_delkey(ic, ireq);
2085                 break;
2086         case IEEE80211_IOC_MLME:
2087                 error = ieee80211_ioctl_setmlme(ic, ireq);
2088                 break;
2089         case IEEE80211_IOC_OPTIE:
2090                 error = ieee80211_ioctl_setoptie(ic, ireq);
2091                 break;
2092         case IEEE80211_IOC_COUNTERMEASURES:
2093                 if (ireq->i_val) {
2094                         if ((ic->ic_flags & IEEE80211_F_WPA) == 0)
2095                                 return EINVAL;
2096                         ic->ic_flags |= IEEE80211_F_COUNTERM;
2097                 } else
2098                         ic->ic_flags &= ~IEEE80211_F_COUNTERM;
2099                 break;
2100         case IEEE80211_IOC_WPA:
2101                 if (ireq->i_val > 3)
2102                         return EINVAL;
2103                 /* XXX verify ciphers available */
2104                 ic->ic_flags &= ~IEEE80211_F_WPA;
2105                 switch (ireq->i_val) {
2106                 case 1:
2107                         ic->ic_flags |= IEEE80211_F_WPA1;
2108                         break;
2109                 case 2:
2110                         ic->ic_flags |= IEEE80211_F_WPA2;
2111                         break;
2112                 case 3:
2113                         ic->ic_flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2;
2114                         break;
2115                 }
2116                 error = ENETRESET;
2117                 break;
2118         case IEEE80211_IOC_WME:
2119                 if (ireq->i_val) {
2120                         if ((ic->ic_caps & IEEE80211_C_WME) == 0)
2121                                 return EINVAL;
2122                         ic->ic_flags |= IEEE80211_F_WME;
2123                 } else
2124                         ic->ic_flags &= ~IEEE80211_F_WME;
2125                 if (IS_UP_AUTO(ic))
2126                         error = ieee80211_init(ic, 0);
2127                 break;
2128         case IEEE80211_IOC_HIDESSID:
2129                 if (ireq->i_val)
2130                         ic->ic_flags |= IEEE80211_F_HIDESSID;
2131                 else
2132                         ic->ic_flags &= ~IEEE80211_F_HIDESSID;
2133                 error = ENETRESET;
2134                 break;
2135         case IEEE80211_IOC_APBRIDGE:
2136                 if (ireq->i_val == 0)
2137                         ic->ic_flags |= IEEE80211_F_NOBRIDGE;
2138                 else
2139                         ic->ic_flags &= ~IEEE80211_F_NOBRIDGE;
2140                 break;
2141         case IEEE80211_IOC_MCASTCIPHER:
2142                 if ((ic->ic_caps & cipher2cap(ireq->i_val)) == 0 &&
2143                     !ieee80211_crypto_available(ireq->i_val))
2144                         return EINVAL;
2145                 rsn->rsn_mcastcipher = ireq->i_val;
2146                 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2147                 break;
2148         case IEEE80211_IOC_MCASTKEYLEN:
2149                 if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
2150                         return EINVAL;
2151                 /* XXX no way to verify driver capability */
2152                 rsn->rsn_mcastkeylen = ireq->i_val;
2153                 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2154                 break;
2155         case IEEE80211_IOC_UCASTCIPHERS:
2156                 /*
2157                  * Convert user-specified cipher set to the set
2158                  * we can support (via hardware or software).
2159                  * NB: this logic intentionally ignores unknown and
2160                  * unsupported ciphers so folks can specify 0xff or
2161                  * similar and get all available ciphers.
2162                  */
2163                 caps = 0;
2164                 for (j = 1; j < 32; j++)        /* NB: skip WEP */
2165                         if ((ireq->i_val & (1<<j)) &&
2166                             ((ic->ic_caps & cipher2cap(j)) ||
2167                              ieee80211_crypto_available(j)))
2168                                 caps |= 1<<j;
2169                 if (caps == 0)                  /* nothing available */
2170                         return EINVAL;
2171                 /* XXX verify ciphers ok for unicast use? */
2172                 /* XXX disallow if running as it'll have no effect */
2173                 rsn->rsn_ucastcipherset = caps;
2174                 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2175                 break;
2176         case IEEE80211_IOC_UCASTCIPHER:
2177                 if ((rsn->rsn_ucastcipherset & cipher2cap(ireq->i_val)) == 0)
2178                         return EINVAL;
2179                 rsn->rsn_ucastcipher = ireq->i_val;
2180                 break;
2181         case IEEE80211_IOC_UCASTKEYLEN:
2182                 if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
2183                         return EINVAL;
2184                 /* XXX no way to verify driver capability */
2185                 rsn->rsn_ucastkeylen = ireq->i_val;
2186                 break;
2187         case IEEE80211_IOC_DRIVER_CAPS:
2188                 /* NB: for testing */
2189                 ic->ic_caps = (((uint16_t) ireq->i_val) << 16) |
2190                                ((uint16_t) ireq->i_len);
2191                 break;
2192         case IEEE80211_IOC_KEYMGTALGS:
2193                 /* XXX check */
2194                 rsn->rsn_keymgmtset = ireq->i_val;
2195                 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2196                 break;
2197         case IEEE80211_IOC_RSNCAPS:
2198                 /* XXX check */
2199                 rsn->rsn_caps = ireq->i_val;
2200                 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2201                 break;
2202         case IEEE80211_IOC_BSSID:
2203                 if (ireq->i_len != sizeof(tmpbssid))
2204                         return EINVAL;
2205                 error = copyin(ireq->i_data, tmpbssid, ireq->i_len);
2206                 if (error)
2207                         break;
2208                 IEEE80211_ADDR_COPY(ic->ic_des_bssid, tmpbssid);
2209                 if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid))
2210                         ic->ic_flags &= ~IEEE80211_F_DESBSSID;
2211                 else
2212                         ic->ic_flags |= IEEE80211_F_DESBSSID;
2213                 if (IS_UP_AUTO(ic))
2214                         error = ieee80211_init(ic, RESCAN);
2215                 break;
2216         case IEEE80211_IOC_CHANLIST:
2217                 error = ieee80211_ioctl_setchanlist(ic, ireq);
2218                 break;
2219         case IEEE80211_IOC_SCAN_REQ:
2220                 if (!IS_UP(ic))
2221                         return EINVAL;
2222                 (void) ieee80211_start_scan(ic,
2223                         IEEE80211_SCAN_ACTIVE |
2224                         IEEE80211_SCAN_NOPICK |
2225                         IEEE80211_SCAN_ONCE, IEEE80211_SCAN_FOREVER,
2226                         /* XXX use ioctl params */
2227                         ic->ic_des_nssid, ic->ic_des_ssid);
2228                 break;
2229         case IEEE80211_IOC_ADDMAC:
2230         case IEEE80211_IOC_DELMAC:
2231                 error = ieee80211_ioctl_macmac(ic, ireq);
2232                 break;
2233         case IEEE80211_IOC_MACCMD:
2234                 error = ieee80211_ioctl_setmaccmd(ic, ireq);
2235                 break;
2236         case IEEE80211_IOC_STA_STATS:
2237                 error = ieee80211_ioctl_setstastats(ic, ireq);
2238                 break;
2239         case IEEE80211_IOC_STA_TXPOW:
2240                 error = ieee80211_ioctl_setstatxpow(ic, ireq);
2241                 break;
2242         case IEEE80211_IOC_WME_CWMIN:           /* WME: CWmin */
2243         case IEEE80211_IOC_WME_CWMAX:           /* WME: CWmax */
2244         case IEEE80211_IOC_WME_AIFS:            /* WME: AIFS */
2245         case IEEE80211_IOC_WME_TXOPLIMIT:       /* WME: txops limit */
2246         case IEEE80211_IOC_WME_ACM:             /* WME: ACM (bss only) */
2247         case IEEE80211_IOC_WME_ACKPOLICY:       /* WME: ACK policy (bss only) */
2248                 error = ieee80211_ioctl_setwmeparam(ic, ireq);
2249                 break;
2250         case IEEE80211_IOC_DTIM_PERIOD:
2251                 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
2252                     ic->ic_opmode != IEEE80211_M_IBSS)
2253                         return EINVAL;
2254                 if (IEEE80211_DTIM_MIN <= ireq->i_val &&
2255                     ireq->i_val <= IEEE80211_DTIM_MAX) {
2256                         ic->ic_dtim_period = ireq->i_val;
2257                         error = ENETRESET;              /* requires restart */
2258                 } else
2259                         error = EINVAL;
2260                 break;
2261         case IEEE80211_IOC_BEACON_INTERVAL:
2262                 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
2263                     ic->ic_opmode != IEEE80211_M_IBSS)
2264                         return EINVAL;
2265                 if (IEEE80211_BINTVAL_MIN <= ireq->i_val &&
2266                     ireq->i_val <= IEEE80211_BINTVAL_MAX) {
2267                         ic->ic_bintval = ireq->i_val;
2268                         error = ENETRESET;              /* requires restart */
2269                 } else
2270                         error = EINVAL;
2271                 break;
2272         case IEEE80211_IOC_PUREG:
2273                 if (ireq->i_val)
2274                         ic->ic_flags |= IEEE80211_F_PUREG;
2275                 else
2276                         ic->ic_flags &= ~IEEE80211_F_PUREG;
2277                 /* NB: reset only if we're operating on an 11g channel */
2278                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2279                     IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
2280                         error = ENETRESET;
2281                 break;
2282         case IEEE80211_IOC_FF:
2283                 if (ireq->i_val) {
2284                         if ((ic->ic_caps & IEEE80211_C_FF) == 0)
2285                                 return EINVAL;
2286                         ic->ic_flags |= IEEE80211_F_FF;
2287                 } else
2288                         ic->ic_flags &= ~IEEE80211_F_FF;
2289                 error = ENETRESET;
2290                 break;
2291         case IEEE80211_IOC_TURBOP:
2292                 if (ireq->i_val) {
2293                         if ((ic->ic_caps & IEEE80211_C_TURBOP) == 0)
2294                                 return EINVAL;
2295                         ic->ic_flags |= IEEE80211_F_TURBOP;
2296                 } else
2297                         ic->ic_flags &= ~IEEE80211_F_TURBOP;
2298                 error = ENETRESET;
2299                 break;
2300         case IEEE80211_IOC_BGSCAN:
2301                 if (ireq->i_val) {
2302                         if ((ic->ic_caps & IEEE80211_C_BGSCAN) == 0)
2303                                 return EINVAL;
2304                         ic->ic_flags |= IEEE80211_F_BGSCAN;
2305                 } else
2306                         ic->ic_flags &= ~IEEE80211_F_BGSCAN;
2307                 break;
2308         case IEEE80211_IOC_BGSCAN_IDLE:
2309                 if (ireq->i_val >= IEEE80211_BGSCAN_IDLE_MIN)
2310                         ic->ic_bgscanidle = ireq->i_val*hz/1000;
2311                 else
2312                         error = EINVAL;
2313                 break;
2314         case IEEE80211_IOC_BGSCAN_INTERVAL:
2315                 if (ireq->i_val >= IEEE80211_BGSCAN_INTVAL_MIN)
2316                         ic->ic_bgscanintvl = ireq->i_val*hz;
2317                 else
2318                         error = EINVAL;
2319                 break;
2320         case IEEE80211_IOC_SCANVALID:
2321                 if (ireq->i_val >= IEEE80211_SCAN_VALID_MIN)
2322                         ic->ic_scanvalid = ireq->i_val*hz;
2323                 else
2324                         error = EINVAL;
2325                 break;
2326         case IEEE80211_IOC_ROAM_RSSI_11A:
2327                 ic->ic_roam.rssi11a = ireq->i_val;
2328                 break;
2329         case IEEE80211_IOC_ROAM_RSSI_11B:
2330                 ic->ic_roam.rssi11bOnly = ireq->i_val;
2331                 break;
2332         case IEEE80211_IOC_ROAM_RSSI_11G:
2333                 ic->ic_roam.rssi11b = ireq->i_val;
2334                 break;
2335         case IEEE80211_IOC_ROAM_RATE_11A:
2336                 ic->ic_roam.rate11a = ireq->i_val & IEEE80211_RATE_VAL;
2337                 break;
2338         case IEEE80211_IOC_ROAM_RATE_11B:
2339                 ic->ic_roam.rate11bOnly = ireq->i_val & IEEE80211_RATE_VAL;
2340                 break;
2341         case IEEE80211_IOC_ROAM_RATE_11G:
2342                 ic->ic_roam.rate11b = ireq->i_val & IEEE80211_RATE_VAL;
2343                 break;
2344         case IEEE80211_IOC_MCAST_RATE:
2345                 ic->ic_mcast_rate = ireq->i_val & IEEE80211_RATE_VAL;
2346                 break;
2347         case IEEE80211_IOC_FRAGTHRESHOLD:
2348                 if ((ic->ic_caps & IEEE80211_C_TXFRAG) == 0 &&
2349                     ireq->i_val != IEEE80211_FRAG_MAX)
2350                         return EINVAL;
2351                 if (!(IEEE80211_FRAG_MIN <= ireq->i_val &&
2352                       ireq->i_val <= IEEE80211_FRAG_MAX))
2353                         return EINVAL;
2354                 ic->ic_fragthreshold = ireq->i_val;
2355                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2356                 break;
2357         case IEEE80211_IOC_BURST:
2358                 if (ireq->i_val) {
2359                         if ((ic->ic_caps & IEEE80211_C_BURST) == 0)
2360                                 return EINVAL;
2361                         ic->ic_flags |= IEEE80211_F_BURST;
2362                 } else
2363                         ic->ic_flags &= ~IEEE80211_F_BURST;
2364                 error = ENETRESET;              /* XXX maybe not for station? */
2365                 break;
2366         case IEEE80211_IOC_BMISSTHRESHOLD:
2367                 if (!(IEEE80211_HWBMISS_MIN <= ireq->i_val &&
2368                       ireq->i_val <= IEEE80211_HWBMISS_MAX))
2369                         return EINVAL;
2370                 ic->ic_bmissthreshold = ireq->i_val;
2371                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2372                 break;
2373         case IEEE80211_IOC_CURCHAN:
2374                 error = ieee80211_ioctl_setcurchan(ic, ireq);
2375                 break;
2376         case IEEE80211_IOC_SHORTGI:
2377                 if (ireq->i_val) {
2378 #define IEEE80211_HTCAP_SHORTGI \
2379         (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40)
2380                         if (((ireq->i_val ^ ic->ic_htcaps) & IEEE80211_HTCAP_SHORTGI) != 0)
2381                                 return EINVAL;
2382                         if (ireq->i_val & IEEE80211_HTCAP_SHORTGI20)
2383                                 ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI20;
2384                         if (ireq->i_val & IEEE80211_HTCAP_SHORTGI40)
2385                                 ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI40;
2386 #undef IEEE80211_HTCAP_SHORTGI
2387                 } else
2388                         ic->ic_flags_ext &=
2389                             ~(IEEE80211_FEXT_SHORTGI20 | IEEE80211_FEXT_SHORTGI40);
2390                 /* XXX kick state machine? */
2391                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2392                 break;
2393         case IEEE80211_IOC_AMPDU:
2394                 if (ireq->i_val) {
2395                         if ((ic->ic_htcaps & IEEE80211_HTC_AMPDU) == 0)
2396                                 return EINVAL;
2397                         if (ireq->i_val & 1)
2398                                 ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_TX;
2399                         if (ireq->i_val & 2)
2400                                 ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_RX;
2401                 } else
2402                         ic->ic_flags_ext &=
2403                             ~(IEEE80211_FEXT_AMPDU_TX|IEEE80211_FEXT_AMPDU_RX);
2404                 /* NB: reset only if we're operating on an 11n channel */
2405                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2406                     IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
2407                         error = ENETRESET;
2408                 break;
2409         case IEEE80211_IOC_AMPDU_LIMIT:
2410                 /* XXX validate */
2411                 ic->ic_ampdu_limit = ireq->i_val;
2412                 break;
2413         case IEEE80211_IOC_AMPDU_DENSITY:
2414                 /* XXX validate */
2415                 ic->ic_ampdu_density = ireq->i_val;
2416                 break;
2417         case IEEE80211_IOC_AMSDU:
2418                 if (ireq->i_val) {
2419                         if ((ic->ic_htcaps & IEEE80211_HTC_AMSDU) == 0)
2420                                 return EINVAL;
2421                         if (ireq->i_val & 1)
2422                                 ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_TX;
2423                         if (ireq->i_val & 2)
2424                                 ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_RX;
2425                 } else
2426                         ic->ic_flags_ext &=
2427                             ~(IEEE80211_FEXT_AMSDU_TX|IEEE80211_FEXT_AMSDU_RX);
2428                 /* NB: reset only if we're operating on an 11n channel */
2429                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2430                     IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
2431                         error = ENETRESET;
2432                 break;
2433         case IEEE80211_IOC_AMSDU_LIMIT:
2434                 /* XXX validate */
2435                 ic->ic_amsdu_limit = ireq->i_val;       /* XXX truncation? */
2436                 break;
2437         case IEEE80211_IOC_PUREN:
2438                 if (ireq->i_val) {
2439                         if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) == 0)
2440                                 return EINVAL;
2441                         ic->ic_flags_ext |= IEEE80211_FEXT_PUREN;
2442                 } else
2443                         ic->ic_flags_ext &= ~IEEE80211_FEXT_PUREN;
2444                 /* NB: reset only if we're operating on an 11n channel */
2445                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2446                     IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
2447                         error = ENETRESET;
2448                 break;
2449         case IEEE80211_IOC_DOTH:
2450                 if (ireq->i_val) {
2451 #if 0
2452                         /* XXX no capability */
2453                         if ((ic->ic_caps & IEEE80211_C_DOTH) == 0)
2454                                 return EINVAL;
2455 #endif
2456                         ic->ic_flags |= IEEE80211_F_DOTH;
2457                 } else
2458                         ic->ic_flags &= ~IEEE80211_F_DOTH;
2459                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2460                 break;
2461         case IEEE80211_IOC_HTCOMPAT:
2462                 if (ireq->i_val) {
2463                         if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) == 0)
2464                                 return EINVAL;
2465                         ic->ic_flags_ext |= IEEE80211_FEXT_HTCOMPAT;
2466                 } else
2467                         ic->ic_flags_ext &= ~IEEE80211_FEXT_HTCOMPAT;
2468                 /* NB: reset only if we're operating on an 11n channel */
2469                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2470                     IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
2471                         error = ENETRESET;
2472                 break;
2473         default:
2474                 error = EINVAL;
2475                 break;
2476         }
2477         if (error == ENETRESET)
2478                 error = IS_UP_AUTO(ic) ? ieee80211_init(ic, 0) : 0;
2479         return error;
2480 }
2481
2482 int
2483 ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, caddr_t data)
2484 {
2485         struct ifnet *ifp = ic->ic_ifp;
2486         int error = 0;
2487         struct ifreq *ifr;
2488         struct ifaddr *ifa;                     /* XXX */
2489
2490         switch (cmd) {
2491         case SIOCSIFMEDIA:
2492         case SIOCGIFMEDIA:
2493                 error = ifmedia_ioctl(ifp, (struct ifreq *) data,
2494                                 &ic->ic_media, cmd);
2495                 break;
2496         case SIOCG80211:
2497                 error = ieee80211_ioctl_get80211(ic, cmd,
2498                                 (struct ieee80211req *) data);
2499                 break;
2500         case SIOCS80211:
2501                 error = priv_check(curthread, PRIV_NET80211_MANAGE);
2502                 if (error == 0)
2503                         error = ieee80211_ioctl_set80211(ic, cmd,
2504                                         (struct ieee80211req *) data);
2505                 break;
2506         case SIOCG80211STATS:
2507                 ifr = (struct ifreq *)data;
2508                 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
2509                 break;
2510         case SIOCSIFMTU:
2511                 ifr = (struct ifreq *)data;
2512                 if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
2513                     ifr->ifr_mtu <= IEEE80211_MTU_MAX))
2514                         error = EINVAL;
2515                 else
2516                         ifp->if_mtu = ifr->ifr_mtu;
2517                 break;
2518         case SIOCSIFADDR:
2519                 /*
2520                  * XXX Handle this directly so we can supress if_init calls.
2521                  * XXX This should be done in ether_ioctl but for the moment
2522                  * XXX there are too many other parts of the system that
2523                  * XXX set IFF_UP and so supress if_init being called when
2524                  * XXX it should be.
2525                  */
2526                 ifa = (struct ifaddr *) data;
2527                 switch (ifa->ifa_addr->sa_family) {
2528 #ifdef INET
2529                 case AF_INET:
2530                         if ((ifp->if_flags & IFF_UP) == 0) {
2531                                 ifp->if_flags |= IFF_UP;
2532                                 ifp->if_init(ifp->if_softc);
2533                         }
2534                         arp_ifinit(ifp, ifa);
2535                         break;
2536 #endif
2537 #ifdef IPX
2538                 /*
2539                  * XXX - This code is probably wrong,
2540                  *       but has been copied many times.
2541                  */
2542                 case AF_IPX: {
2543                         struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
2544
2545                         if (ipx_nullhost(*ina))
2546                                 ina->x_host = *(union ipx_host *)
2547                                     IF_LLADDR(ifp);
2548                         else
2549                                 bcopy((caddr_t) ina->x_host.c_host,
2550                                       (caddr_t) IF_LLADDR(ifp),
2551                                       ETHER_ADDR_LEN);
2552                         /* fall thru... */
2553                 }
2554 #endif
2555                 default:
2556                         if ((ifp->if_flags & IFF_UP) == 0) {
2557                                 ifp->if_flags |= IFF_UP;
2558                                 ifp->if_init(ifp->if_softc);
2559                         }
2560                         break;
2561                 }
2562                 break;
2563         default:
2564                 error = ether_ioctl(ifp, cmd, data);
2565                 break;
2566         }
2567         return error;
2568 }