]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net80211/ieee80211_ioctl.c
This commit was generated by cvs2svn to compensate for changes in r172314,
[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         case IEEE80211_IOC_INACTIVITY:
1109                 ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_INACT) != 0;
1110                 break;
1111         default:
1112                 error = EINVAL;
1113                 break;
1114         }
1115         return error;
1116 }
1117
1118 static int
1119 ieee80211_ioctl_setoptie(struct ieee80211com *ic, struct ieee80211req *ireq)
1120 {
1121         int error;
1122         void *ie, *oie;
1123
1124         /*
1125          * NB: Doing this for ap operation could be useful (e.g. for
1126          *     WPA and/or WME) except that it typically is worthless
1127          *     without being able to intervene when processing
1128          *     association response frames--so disallow it for now.
1129          */
1130         if (ic->ic_opmode != IEEE80211_M_STA)
1131                 return EINVAL;
1132         if (ireq->i_len > IEEE80211_MAX_OPT_IE)
1133                 return EINVAL;
1134         /* NB: data.length is validated by the wireless extensions code */
1135         /* XXX M_WAITOK after driver lock released */
1136         if (ireq->i_len > 0) {
1137                 MALLOC(ie, void *, ireq->i_len, M_DEVBUF, M_NOWAIT);
1138                 if (ie == NULL)
1139                         return ENOMEM;
1140                 error = copyin(ireq->i_data, ie, ireq->i_len);
1141                 if (error) {
1142                         FREE(ie, M_DEVBUF);
1143                         return error;
1144                 }
1145         } else {
1146                 ie = NULL;
1147                 ireq->i_len = 0;
1148         }
1149         /* XXX sanity check data? */
1150         oie = ic->ic_opt_ie;
1151         ic->ic_opt_ie = ie;
1152         ic->ic_opt_ie_len = ireq->i_len;
1153         if (oie != NULL)
1154                 FREE(oie, M_DEVBUF);
1155         return 0;
1156 }
1157
1158 static int
1159 ieee80211_ioctl_setkey(struct ieee80211com *ic, struct ieee80211req *ireq)
1160 {
1161         struct ieee80211req_key ik;
1162         struct ieee80211_node *ni;
1163         struct ieee80211_key *wk;
1164         uint16_t kid;
1165         int error;
1166
1167         if (ireq->i_len != sizeof(ik))
1168                 return EINVAL;
1169         error = copyin(ireq->i_data, &ik, sizeof(ik));
1170         if (error)
1171                 return error;
1172         /* NB: cipher support is verified by ieee80211_crypt_newkey */
1173         /* NB: this also checks ik->ik_keylen > sizeof(wk->wk_key) */
1174         if (ik.ik_keylen > sizeof(ik.ik_keydata))
1175                 return E2BIG;
1176         kid = ik.ik_keyix;
1177         if (kid == IEEE80211_KEYIX_NONE) {
1178                 /* XXX unicast keys currently must be tx/rx */
1179                 if (ik.ik_flags != (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))
1180                         return EINVAL;
1181                 if (ic->ic_opmode == IEEE80211_M_STA) {
1182                         ni = ieee80211_ref_node(ic->ic_bss);
1183                         if (!IEEE80211_ADDR_EQ(ik.ik_macaddr, ni->ni_bssid)) {
1184                                 ieee80211_free_node(ni);
1185                                 return EADDRNOTAVAIL;
1186                         }
1187                 } else {
1188                         ni = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
1189                         if (ni == NULL)
1190                                 return ENOENT;
1191                 }
1192                 wk = &ni->ni_ucastkey;
1193         } else {
1194                 if (kid >= IEEE80211_WEP_NKID)
1195                         return EINVAL;
1196                 wk = &ic->ic_nw_keys[kid];
1197                 /*
1198                  * Global slots start off w/o any assigned key index.
1199                  * Force one here for consistency with IEEE80211_IOC_WEPKEY.
1200                  */
1201                 if (wk->wk_keyix == IEEE80211_KEYIX_NONE)
1202                         wk->wk_keyix = kid;
1203                 ni = NULL;
1204         }
1205         error = 0;
1206         ieee80211_key_update_begin(ic);
1207         if (ieee80211_crypto_newkey(ic, ik.ik_type, ik.ik_flags, wk)) {
1208                 wk->wk_keylen = ik.ik_keylen;
1209                 /* NB: MIC presence is implied by cipher type */
1210                 if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
1211                         wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
1212                 wk->wk_keyrsc = ik.ik_keyrsc;
1213                 wk->wk_keytsc = 0;                      /* new key, reset */
1214                 memset(wk->wk_key, 0, sizeof(wk->wk_key));
1215                 memcpy(wk->wk_key, ik.ik_keydata, ik.ik_keylen);
1216                 if (!ieee80211_crypto_setkey(ic, wk,
1217                     ni != NULL ? ni->ni_macaddr : ik.ik_macaddr))
1218                         error = EIO;
1219                 else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT))
1220                         ic->ic_def_txkey = kid;
1221         } else
1222                 error = ENXIO;
1223         ieee80211_key_update_end(ic);
1224         if (ni != NULL)
1225                 ieee80211_free_node(ni);
1226         return error;
1227 }
1228
1229 static int
1230 ieee80211_ioctl_delkey(struct ieee80211com *ic, struct ieee80211req *ireq)
1231 {
1232         struct ieee80211req_del_key dk;
1233         int kid, error;
1234
1235         if (ireq->i_len != sizeof(dk))
1236                 return EINVAL;
1237         error = copyin(ireq->i_data, &dk, sizeof(dk));
1238         if (error)
1239                 return error;
1240         kid = dk.idk_keyix;
1241         /* XXX uint8_t -> uint16_t */
1242         if (dk.idk_keyix == (uint8_t) IEEE80211_KEYIX_NONE) {
1243                 struct ieee80211_node *ni;
1244
1245                 if (ic->ic_opmode == IEEE80211_M_STA) {
1246                         ni = ieee80211_ref_node(ic->ic_bss);
1247                         if (!IEEE80211_ADDR_EQ(dk.idk_macaddr, ni->ni_bssid)) {
1248                                 ieee80211_free_node(ni);
1249                                 return EADDRNOTAVAIL;
1250                         }
1251                 } else {
1252                         ni = ieee80211_find_node(&ic->ic_sta, dk.idk_macaddr);
1253                         if (ni == NULL)
1254                                 return ENOENT;
1255                 }
1256                 /* XXX error return */
1257                 ieee80211_node_delucastkey(ni);
1258                 ieee80211_free_node(ni);
1259         } else {
1260                 if (kid >= IEEE80211_WEP_NKID)
1261                         return EINVAL;
1262                 /* XXX error return */
1263                 ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[kid]);
1264         }
1265         return 0;
1266 }
1267
1268 static void
1269 domlme(void *arg, struct ieee80211_node *ni)
1270 {
1271         struct ieee80211com *ic = ni->ni_ic;
1272         struct ieee80211req_mlme *mlme = arg;
1273
1274         if (ni->ni_associd != 0) {
1275                 IEEE80211_SEND_MGMT(ic, ni,
1276                         mlme->im_op == IEEE80211_MLME_DEAUTH ?
1277                                 IEEE80211_FC0_SUBTYPE_DEAUTH :
1278                                 IEEE80211_FC0_SUBTYPE_DISASSOC,
1279                         mlme->im_reason);
1280         }
1281         ieee80211_node_leave(ic, ni);
1282 }
1283
1284 struct scanlookup {
1285         const uint8_t *mac;
1286         int esslen;
1287         const uint8_t *essid;
1288         const struct ieee80211_scan_entry *se;
1289 };
1290
1291 /*
1292  * Match mac address and any ssid.
1293  */
1294 static void
1295 mlmelookup(void *arg, const struct ieee80211_scan_entry *se)
1296 {
1297         struct scanlookup *look = arg;
1298
1299         if (!IEEE80211_ADDR_EQ(look->mac, se->se_macaddr))
1300                 return;
1301         if (look->esslen != 0) {
1302                 if (se->se_ssid[1] != look->esslen)
1303                         return;
1304                 if (memcmp(look->essid, se->se_ssid+2, look->esslen))
1305                         return;
1306         }
1307         look->se = se;
1308 }
1309
1310 static int
1311 ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq)
1312 {
1313         struct ieee80211req_mlme mlme;
1314         struct ieee80211_node *ni;
1315         int error;
1316
1317         if (ireq->i_len != sizeof(mlme))
1318                 return EINVAL;
1319         error = copyin(ireq->i_data, &mlme, sizeof(mlme));
1320         if (error)
1321                 return error;
1322         switch (mlme.im_op) {
1323         case IEEE80211_MLME_ASSOC:
1324                 /* XXX ibss/ahdemo */
1325                 if (ic->ic_opmode == IEEE80211_M_STA) {
1326                         struct scanlookup lookup;
1327
1328                         lookup.se = NULL;
1329                         lookup.mac = mlme.im_macaddr;
1330                         /* XXX use revised api w/ explicit ssid */
1331                         lookup.esslen = ic->ic_des_ssid[0].len;
1332                         lookup.essid = ic->ic_des_ssid[0].ssid;
1333                         ieee80211_scan_iterate(ic, mlmelookup, &lookup);
1334                         if (lookup.se != NULL &&
1335                             ieee80211_sta_join(ic, lookup.se))
1336                                 return 0;
1337                 }
1338                 return EINVAL;
1339         case IEEE80211_MLME_DISASSOC:
1340         case IEEE80211_MLME_DEAUTH:
1341                 switch (ic->ic_opmode) {
1342                 case IEEE80211_M_STA:
1343                         /* XXX not quite right */
1344                         ieee80211_new_state(ic, IEEE80211_S_INIT,
1345                                 mlme.im_reason);
1346                         break;
1347                 case IEEE80211_M_HOSTAP:
1348                         /* NB: the broadcast address means do 'em all */
1349                         if (!IEEE80211_ADDR_EQ(mlme.im_macaddr, ic->ic_ifp->if_broadcastaddr)) {
1350                                 if ((ni = ieee80211_find_node(&ic->ic_sta,
1351                                                 mlme.im_macaddr)) == NULL)
1352                                         return EINVAL;
1353                                 domlme(&mlme, ni);
1354                                 ieee80211_free_node(ni);
1355                         } else {
1356                                 ieee80211_iterate_nodes(&ic->ic_sta,
1357                                                 domlme, &mlme);
1358                         }
1359                         break;
1360                 default:
1361                         return EINVAL;
1362                 }
1363                 break;
1364         case IEEE80211_MLME_AUTHORIZE:
1365         case IEEE80211_MLME_UNAUTHORIZE:
1366                 if (ic->ic_opmode != IEEE80211_M_HOSTAP)
1367                         return EINVAL;
1368                 ni = ieee80211_find_node(&ic->ic_sta, mlme.im_macaddr);
1369                 if (ni == NULL)
1370                         return EINVAL;
1371                 if (mlme.im_op == IEEE80211_MLME_AUTHORIZE)
1372                         ieee80211_node_authorize(ni);
1373                 else
1374                         ieee80211_node_unauthorize(ni);
1375                 ieee80211_free_node(ni);
1376                 break;
1377         default:
1378                 return EINVAL;
1379         }
1380         return 0;
1381 }
1382
1383 static int
1384 ieee80211_ioctl_macmac(struct ieee80211com *ic, struct ieee80211req *ireq)
1385 {
1386         uint8_t mac[IEEE80211_ADDR_LEN];
1387         const struct ieee80211_aclator *acl = ic->ic_acl;
1388         int error;
1389
1390         if (ireq->i_len != sizeof(mac))
1391                 return EINVAL;
1392         error = copyin(ireq->i_data, mac, ireq->i_len);
1393         if (error)
1394                 return error;
1395         if (acl == NULL) {
1396                 acl = ieee80211_aclator_get("mac");
1397                 if (acl == NULL || !acl->iac_attach(ic))
1398                         return EINVAL;
1399                 ic->ic_acl = acl;
1400         }
1401         if (ireq->i_type == IEEE80211_IOC_ADDMAC)
1402                 acl->iac_add(ic, mac);
1403         else
1404                 acl->iac_remove(ic, mac);
1405         return 0;
1406 }
1407
1408 static int
1409 ieee80211_ioctl_setmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
1410 {
1411         const struct ieee80211_aclator *acl = ic->ic_acl;
1412
1413         switch (ireq->i_val) {
1414         case IEEE80211_MACCMD_POLICY_OPEN:
1415         case IEEE80211_MACCMD_POLICY_ALLOW:
1416         case IEEE80211_MACCMD_POLICY_DENY:
1417                 if (acl == NULL) {
1418                         acl = ieee80211_aclator_get("mac");
1419                         if (acl == NULL || !acl->iac_attach(ic))
1420                                 return EINVAL;
1421                         ic->ic_acl = acl;
1422                 }
1423                 acl->iac_setpolicy(ic, ireq->i_val);
1424                 break;
1425         case IEEE80211_MACCMD_FLUSH:
1426                 if (acl != NULL)
1427                         acl->iac_flush(ic);
1428                 /* NB: silently ignore when not in use */
1429                 break;
1430         case IEEE80211_MACCMD_DETACH:
1431                 if (acl != NULL) {
1432                         ic->ic_acl = NULL;
1433                         acl->iac_detach(ic);
1434                 }
1435                 break;
1436         default:
1437                 if (acl == NULL)
1438                         return EINVAL;
1439                 else
1440                         return acl->iac_setioctl(ic, ireq);
1441         }
1442         return 0;
1443 }
1444
1445 static int
1446 ieee80211_ioctl_setchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
1447 {
1448         struct ieee80211req_chanlist list;
1449         u_char chanlist[IEEE80211_CHAN_BYTES];
1450         int i, j, nchan, error;
1451
1452         if (ireq->i_len != sizeof(list))
1453                 return EINVAL;
1454         error = copyin(ireq->i_data, &list, sizeof(list));
1455         if (error)
1456                 return error;
1457         memset(chanlist, 0, sizeof(chanlist));
1458         /*
1459          * Since channel 0 is not available for DS, channel 1
1460          * is assigned to LSB on WaveLAN.
1461          */
1462         if (ic->ic_phytype == IEEE80211_T_DS)
1463                 i = 1;
1464         else
1465                 i = 0;
1466         nchan = 0;
1467         for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
1468                 /*
1469                  * NB: silently discard unavailable channels so users
1470                  *     can specify 1-255 to get all available channels.
1471                  */
1472                 if (isset(list.ic_channels, j) && isset(ic->ic_chan_avail, i)) {
1473                         setbit(chanlist, i);
1474                         nchan++;
1475                 }
1476         }
1477         if (nchan == 0)
1478                 return EINVAL;
1479         if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&    /* XXX */
1480             isclr(chanlist, ic->ic_bsschan->ic_ieee))
1481                 ic->ic_bsschan = IEEE80211_CHAN_ANYC;
1482         memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
1483         return IS_UP_AUTO(ic) ? ieee80211_init(ic, RESCAN) : 0;
1484 }
1485
1486 static int
1487 ieee80211_ioctl_setstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
1488 {
1489         struct ieee80211_node *ni;
1490         uint8_t macaddr[IEEE80211_ADDR_LEN];
1491         int error;
1492
1493         /*
1494          * NB: we could copyin ieee80211req_sta_stats so apps
1495          *     could make selective changes but that's overkill;
1496          *     just clear all stats for now.
1497          */
1498         if (ireq->i_len < IEEE80211_ADDR_LEN)
1499                 return EINVAL;
1500         error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
1501         if (error != 0)
1502                 return error;
1503         ni = ieee80211_find_node(&ic->ic_sta, macaddr);
1504         if (ni == NULL)
1505                 return EINVAL;          /* XXX */
1506         memset(&ni->ni_stats, 0, sizeof(ni->ni_stats));
1507         ieee80211_free_node(ni);
1508         return 0;
1509 }
1510
1511 static int
1512 ieee80211_ioctl_setstatxpow(struct ieee80211com *ic, struct ieee80211req *ireq)
1513 {
1514         struct ieee80211_node *ni;
1515         struct ieee80211req_sta_txpow txpow;
1516         int error;
1517
1518         if (ireq->i_len != sizeof(txpow))
1519                 return EINVAL;
1520         error = copyin(ireq->i_data, &txpow, sizeof(txpow));
1521         if (error != 0)
1522                 return error;
1523         ni = ieee80211_find_node(&ic->ic_sta, txpow.it_macaddr);
1524         if (ni == NULL)
1525                 return EINVAL;          /* XXX */
1526         ni->ni_txpower = txpow.it_txpow;
1527         ieee80211_free_node(ni);
1528         return error;
1529 }
1530
1531 static int
1532 ieee80211_ioctl_setwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
1533 {
1534         struct ieee80211_wme_state *wme = &ic->ic_wme;
1535         struct wmeParams *wmep, *chanp;
1536         int isbss, ac;
1537
1538         if ((ic->ic_caps & IEEE80211_C_WME) == 0)
1539                 return EINVAL;
1540
1541         isbss = (ireq->i_len & IEEE80211_WMEPARAM_BSS);
1542         ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
1543         if (ac >= WME_NUM_AC)
1544                 ac = WME_AC_BE;
1545         if (isbss) {
1546                 chanp = &wme->wme_bssChanParams.cap_wmeParams[ac];
1547                 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
1548         } else {
1549                 chanp = &wme->wme_chanParams.cap_wmeParams[ac];
1550                 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
1551         }
1552         switch (ireq->i_type) {
1553         case IEEE80211_IOC_WME_CWMIN:           /* WME: CWmin */
1554                 if (isbss) {
1555                         wmep->wmep_logcwmin = ireq->i_val;
1556                         if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1557                                 chanp->wmep_logcwmin = ireq->i_val;
1558                 } else {
1559                         wmep->wmep_logcwmin = chanp->wmep_logcwmin =
1560                                 ireq->i_val;
1561                 }
1562                 break;
1563         case IEEE80211_IOC_WME_CWMAX:           /* WME: CWmax */
1564                 if (isbss) {
1565                         wmep->wmep_logcwmax = ireq->i_val;
1566                         if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1567                                 chanp->wmep_logcwmax = ireq->i_val;
1568                 } else {
1569                         wmep->wmep_logcwmax = chanp->wmep_logcwmax =
1570                                 ireq->i_val;
1571                 }
1572                 break;
1573         case IEEE80211_IOC_WME_AIFS:            /* WME: AIFS */
1574                 if (isbss) {
1575                         wmep->wmep_aifsn = ireq->i_val;
1576                         if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1577                                 chanp->wmep_aifsn = ireq->i_val;
1578                 } else {
1579                         wmep->wmep_aifsn = chanp->wmep_aifsn = ireq->i_val;
1580                 }
1581                 break;
1582         case IEEE80211_IOC_WME_TXOPLIMIT:       /* WME: txops limit */
1583                 if (isbss) {
1584                         wmep->wmep_txopLimit = ireq->i_val;
1585                         if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1586                                 chanp->wmep_txopLimit = ireq->i_val;
1587                 } else {
1588                         wmep->wmep_txopLimit = chanp->wmep_txopLimit =
1589                                 ireq->i_val;
1590                 }
1591                 break;
1592         case IEEE80211_IOC_WME_ACM:             /* WME: ACM (bss only) */
1593                 wmep->wmep_acm = ireq->i_val;
1594                 if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
1595                         chanp->wmep_acm = ireq->i_val;
1596                 break;
1597         case IEEE80211_IOC_WME_ACKPOLICY:       /* WME: ACK policy (!bss only)*/
1598                 wmep->wmep_noackPolicy = chanp->wmep_noackPolicy =
1599                         (ireq->i_val) == 0;
1600                 break;
1601         }
1602         ieee80211_wme_updateparams(ic);
1603         return 0;
1604 }
1605
1606 static int
1607 cipher2cap(int cipher)
1608 {
1609         switch (cipher) {
1610         case IEEE80211_CIPHER_WEP:      return IEEE80211_C_WEP;
1611         case IEEE80211_CIPHER_AES_OCB:  return IEEE80211_C_AES;
1612         case IEEE80211_CIPHER_AES_CCM:  return IEEE80211_C_AES_CCM;
1613         case IEEE80211_CIPHER_CKIP:     return IEEE80211_C_CKIP;
1614         case IEEE80211_CIPHER_TKIP:     return IEEE80211_C_TKIP;
1615         }
1616         return 0;
1617 }
1618
1619 static int
1620 find11gchannel(struct ieee80211com *ic, int start, int freq)
1621 {
1622         const struct ieee80211_channel *c;
1623         int i;
1624
1625         for (i = start+1; i < ic->ic_nchans; i++) {
1626                 c = &ic->ic_channels[i];
1627                 if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
1628                         return 1;
1629         }
1630         /* NB: should not be needed but in case things are mis-sorted */
1631         for (i = 0; i < start; i++) {
1632                 c = &ic->ic_channels[i];
1633                 if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
1634                         return 1;
1635         }
1636         return 0;
1637 }
1638
1639 static struct ieee80211_channel *
1640 findchannel(struct ieee80211com *ic, int ieee, int mode)
1641 {
1642         static const u_int chanflags[IEEE80211_MODE_MAX] = {
1643                 0,                      /* IEEE80211_MODE_AUTO */
1644                 IEEE80211_CHAN_A,       /* IEEE80211_MODE_11A */
1645                 IEEE80211_CHAN_B,       /* IEEE80211_MODE_11B */
1646                 IEEE80211_CHAN_G,       /* IEEE80211_MODE_11G */
1647                 IEEE80211_CHAN_FHSS,    /* IEEE80211_MODE_FH */
1648                 IEEE80211_CHAN_108A,    /* IEEE80211_MODE_TURBO_A */
1649                 IEEE80211_CHAN_108G,    /* IEEE80211_MODE_TURBO_G */
1650                 IEEE80211_CHAN_STURBO,  /* IEEE80211_MODE_STURBO_A */
1651                 /* NB: handled specially below */
1652                 IEEE80211_CHAN_A,       /* IEEE80211_MODE_11NA */
1653                 IEEE80211_CHAN_G,       /* IEEE80211_MODE_11NG */
1654         };
1655         u_int modeflags;
1656         int i;
1657
1658         KASSERT(mode < IEEE80211_MODE_MAX, ("bad mode %u", mode));
1659         modeflags = chanflags[mode];
1660         KASSERT(modeflags != 0 || mode == IEEE80211_MODE_AUTO,
1661             ("no chanflags for mode %u", mode));
1662         for (i = 0; i < ic->ic_nchans; i++) {
1663                 struct ieee80211_channel *c = &ic->ic_channels[i];
1664
1665                 if (c->ic_ieee != ieee)
1666                         continue;
1667                 if (mode == IEEE80211_MODE_AUTO) {
1668                         /* ignore turbo channels for autoselect */
1669                         if (IEEE80211_IS_CHAN_TURBO(c))
1670                                 continue;
1671                         /*
1672                          * XXX special-case 11b/g channels so we
1673                          *     always select the g channel if both
1674                          *     are present.
1675                          * XXX prefer HT to non-HT?
1676                          */
1677                         if (!IEEE80211_IS_CHAN_B(c) ||
1678                             !find11gchannel(ic, i, c->ic_freq))
1679                                 return c;
1680                 } else {
1681                         /* must check HT specially */
1682                         if ((mode == IEEE80211_MODE_11NA ||
1683                             mode == IEEE80211_MODE_11NG) &&
1684                             !IEEE80211_IS_CHAN_HT(c))
1685                                 continue;
1686                         if ((c->ic_flags & modeflags) == modeflags)
1687                                 return c;
1688                 }
1689         }
1690         return NULL;
1691 }
1692
1693 /*
1694  * Check the specified against any desired mode (aka netband).
1695  * This is only used (presently) when operating in hostap mode
1696  * to enforce consistency.
1697  */
1698 static int
1699 check_mode_consistency(const struct ieee80211_channel *c, int mode)
1700 {
1701         KASSERT(c != IEEE80211_CHAN_ANYC, ("oops, no channel"));
1702
1703         switch (mode) {
1704         case IEEE80211_MODE_11B:
1705                 return (IEEE80211_IS_CHAN_B(c));
1706         case IEEE80211_MODE_11G:
1707                 return (IEEE80211_IS_CHAN_ANYG(c) && !IEEE80211_IS_CHAN_HT(c));
1708         case IEEE80211_MODE_11A:
1709                 return (IEEE80211_IS_CHAN_A(c) && !IEEE80211_IS_CHAN_HT(c));
1710         case IEEE80211_MODE_STURBO_A:
1711                 return (IEEE80211_IS_CHAN_STURBO(c));
1712         case IEEE80211_MODE_11NA:
1713                 return (IEEE80211_IS_CHAN_HTA(c));
1714         case IEEE80211_MODE_11NG:
1715                 return (IEEE80211_IS_CHAN_HTG(c));
1716         }
1717         return 1;
1718
1719 }
1720
1721 /*
1722  * Common code to set the current channel.  If the device
1723  * is up and running this may result in an immediate channel
1724  * change or a kick of the state machine.
1725  */
1726 static int
1727 setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c)
1728 {
1729         int error;
1730
1731         if (c != IEEE80211_CHAN_ANYC) {
1732                 if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
1733                     !check_mode_consistency(c, ic->ic_des_mode))
1734                         return EINVAL;
1735                 if (ic->ic_state == IEEE80211_S_RUN && c == ic->ic_curchan)
1736                         return 0;       /* NB: nothing to do */
1737         }
1738         ic->ic_des_chan = c;
1739
1740         error = 0;
1741         if ((ic->ic_opmode == IEEE80211_M_MONITOR ||
1742             ic->ic_opmode == IEEE80211_M_WDS) &&
1743             ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
1744                 /*
1745                  * Monitor and wds modes can switch directly.
1746                  */
1747                 ic->ic_curchan = ic->ic_des_chan;
1748                 if (ic->ic_state == IEEE80211_S_RUN)
1749                         ic->ic_set_channel(ic);
1750         } else {
1751                 /*
1752                  * Need to go through the state machine in case we
1753                  * need to reassociate or the like.  The state machine
1754                  * will pickup the desired channel and avoid scanning.
1755                  */
1756                 if (IS_UP_AUTO(ic))
1757                         error = ieee80211_init(ic, RESCAN);
1758                 else if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
1759                         /*
1760                          * When not up+running and a real channel has
1761                          * been specified fix the current channel so
1762                          * there is immediate feedback; e.g. via ifconfig.
1763                          */
1764                         ic->ic_curchan = ic->ic_des_chan;
1765                 }
1766         }
1767         return error;
1768 }
1769
1770 /*
1771  * Old api for setting the current channel; this is
1772  * deprecated because channel numbers are ambiguous.
1773  */
1774 static int
1775 ieee80211_ioctl_setchannel(struct ieee80211com *ic,
1776         const struct ieee80211req *ireq)
1777 {
1778         struct ieee80211_channel *c;
1779
1780         /* XXX 0xffff overflows 16-bit signed */
1781         if (ireq->i_val == 0 ||
1782             ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) {
1783                 c = IEEE80211_CHAN_ANYC;
1784         } else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX) {
1785                 return EINVAL;
1786         } else {
1787                 struct ieee80211_channel *c2;
1788
1789                 c = findchannel(ic, ireq->i_val, ic->ic_des_mode);
1790                 if (c == NULL) {
1791                         c = findchannel(ic, ireq->i_val,
1792                                 IEEE80211_MODE_AUTO);
1793                         if (c == NULL)
1794                                 return EINVAL;
1795                 }
1796                 /*
1797                  * Fine tune channel selection based on desired mode:
1798                  *   if 11b is requested, find the 11b version of any
1799                  *      11g channel returned,
1800                  *   if static turbo, find the turbo version of any
1801                  *      11a channel return,
1802                  *   if 11na is requested, find the ht version of any
1803                  *      11a channel returned,
1804                  *   if 11ng is requested, find the ht version of any
1805                  *      11g channel returned,
1806                  *   otherwise we should be ok with what we've got.
1807                  */
1808                 switch (ic->ic_des_mode) {
1809                 case IEEE80211_MODE_11B:
1810                         if (IEEE80211_IS_CHAN_ANYG(c)) {
1811                                 c2 = findchannel(ic, ireq->i_val,
1812                                         IEEE80211_MODE_11B);
1813                                 /* NB: should not happen, =>'s 11g w/o 11b */
1814                                 if (c2 != NULL)
1815                                         c = c2;
1816                         }
1817                         break;
1818                 case IEEE80211_MODE_TURBO_A:
1819                         if (IEEE80211_IS_CHAN_A(c)) {
1820                                 c2 = findchannel(ic, ireq->i_val,
1821                                         IEEE80211_MODE_TURBO_A);
1822                                 if (c2 != NULL)
1823                                         c = c2;
1824                         }
1825                         break;
1826                 case IEEE80211_MODE_11NA:
1827                         if (IEEE80211_IS_CHAN_A(c)) {
1828                                 c2 = findchannel(ic, ireq->i_val,
1829                                         IEEE80211_MODE_11NA);
1830                                 if (c2 != NULL)
1831                                         c = c2;
1832                         }
1833                         break;
1834                 case IEEE80211_MODE_11NG:
1835                         if (IEEE80211_IS_CHAN_ANYG(c)) {
1836                                 c2 = findchannel(ic, ireq->i_val,
1837                                         IEEE80211_MODE_11NG);
1838                                 if (c2 != NULL)
1839                                         c = c2;
1840                         }
1841                         break;
1842                 default:                /* NB: no static turboG */
1843                         break;
1844                 }
1845         }
1846         return setcurchan(ic, c);
1847 }
1848
1849 /*
1850  * New/current api for setting the current channel; a complete
1851  * channel description is provide so there is no ambiguity in
1852  * identifying the channel.
1853  */
1854 static int
1855 ieee80211_ioctl_setcurchan(struct ieee80211com *ic,
1856         const struct ieee80211req *ireq)
1857 {
1858         struct ieee80211_channel chan, *c;
1859         int error;
1860
1861         if (ireq->i_len != sizeof(chan))
1862                 return EINVAL;
1863         error = copyin(ireq->i_data, &chan, sizeof(chan));
1864         if (error != 0)
1865                 return error;
1866         /* XXX 0xffff overflows 16-bit signed */
1867         if (chan.ic_freq == 0 || chan.ic_freq == IEEE80211_CHAN_ANY) {
1868                 c = IEEE80211_CHAN_ANYC;
1869         } else {
1870                 c = ieee80211_find_channel(ic, chan.ic_freq, chan.ic_flags);
1871                 if (c == NULL)
1872                         return EINVAL;
1873         }
1874         return setcurchan(ic, c);
1875 }
1876
1877 static int
1878 ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
1879 {
1880         static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
1881         struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
1882         int error;
1883         const struct ieee80211_authenticator *auth;
1884         uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
1885         char tmpssid[IEEE80211_NWID_LEN];
1886         uint8_t tmpbssid[IEEE80211_ADDR_LEN];
1887         struct ieee80211_key *k;
1888         int j, caps;
1889         u_int kid;
1890
1891         error = 0;
1892         switch (ireq->i_type) {
1893         case IEEE80211_IOC_SSID:
1894                 if (ireq->i_val != 0 ||
1895                     ireq->i_len > IEEE80211_NWID_LEN)
1896                         return EINVAL;
1897                 error = copyin(ireq->i_data, tmpssid, ireq->i_len);
1898                 if (error)
1899                         break;
1900                 memset(ic->ic_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
1901                 ic->ic_des_ssid[0].len = ireq->i_len;
1902                 memcpy(ic->ic_des_ssid[0].ssid, tmpssid, ireq->i_len);
1903                 ic->ic_des_nssid = (ireq->i_len > 0);
1904                 if (IS_UP_AUTO(ic))
1905                         error = ieee80211_init(ic, RESCAN);
1906                 break;
1907         case IEEE80211_IOC_WEP:
1908                 switch (ireq->i_val) {
1909                 case IEEE80211_WEP_OFF:
1910                         ic->ic_flags &= ~IEEE80211_F_PRIVACY;
1911                         ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
1912                         break;
1913                 case IEEE80211_WEP_ON:
1914                         ic->ic_flags |= IEEE80211_F_PRIVACY;
1915                         ic->ic_flags |= IEEE80211_F_DROPUNENC;
1916                         break;
1917                 case IEEE80211_WEP_MIXED:
1918                         ic->ic_flags |= IEEE80211_F_PRIVACY;
1919                         ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
1920                         break;
1921                 }
1922                 if (IS_UP_AUTO(ic))
1923                         error = ieee80211_init(ic, RESCAN);
1924                 break;
1925         case IEEE80211_IOC_WEPKEY:
1926                 kid = (u_int) ireq->i_val;
1927                 if (kid >= IEEE80211_WEP_NKID)
1928                         return EINVAL;
1929                 k = &ic->ic_nw_keys[kid];
1930                 if (ireq->i_len == 0) {
1931                         /* zero-len =>'s delete any existing key */
1932                         (void) ieee80211_crypto_delkey(ic, k);
1933                         break;
1934                 }
1935                 if (ireq->i_len > sizeof(tmpkey))
1936                         return EINVAL;
1937                 memset(tmpkey, 0, sizeof(tmpkey));
1938                 error = copyin(ireq->i_data, tmpkey, ireq->i_len);
1939                 if (error)
1940                         break;
1941                 ieee80211_key_update_begin(ic);
1942                 k->wk_keyix = kid;      /* NB: force fixed key id */
1943                 if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
1944                     IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, k)) {
1945                         k->wk_keylen = ireq->i_len;
1946                         memcpy(k->wk_key, tmpkey, sizeof(tmpkey));
1947                         if  (!ieee80211_crypto_setkey(ic, k, ic->ic_myaddr))
1948                                 error = EINVAL;
1949                 } else
1950                         error = EINVAL;
1951                 ieee80211_key_update_end(ic);
1952                 break;
1953         case IEEE80211_IOC_WEPTXKEY:
1954                 kid = (u_int) ireq->i_val;
1955                 if (kid >= IEEE80211_WEP_NKID &&
1956                     (uint16_t) kid != IEEE80211_KEYIX_NONE)
1957                         return EINVAL;
1958                 ic->ic_def_txkey = kid;
1959                 break;
1960         case IEEE80211_IOC_AUTHMODE:
1961                 switch (ireq->i_val) {
1962                 case IEEE80211_AUTH_WPA:
1963                 case IEEE80211_AUTH_8021X:      /* 802.1x */
1964                 case IEEE80211_AUTH_OPEN:       /* open */
1965                 case IEEE80211_AUTH_SHARED:     /* shared-key */
1966                 case IEEE80211_AUTH_AUTO:       /* auto */
1967                         auth = ieee80211_authenticator_get(ireq->i_val);
1968                         if (auth == NULL)
1969                                 return EINVAL;
1970                         break;
1971                 default:
1972                         return EINVAL;
1973                 }
1974                 switch (ireq->i_val) {
1975                 case IEEE80211_AUTH_WPA:        /* WPA w/ 802.1x */
1976                         ic->ic_flags |= IEEE80211_F_PRIVACY;
1977                         ireq->i_val = IEEE80211_AUTH_8021X;
1978                         break;
1979                 case IEEE80211_AUTH_OPEN:       /* open */
1980                         ic->ic_flags &= ~(IEEE80211_F_WPA|IEEE80211_F_PRIVACY);
1981                         break;
1982                 case IEEE80211_AUTH_SHARED:     /* shared-key */
1983                 case IEEE80211_AUTH_8021X:      /* 802.1x */
1984                         ic->ic_flags &= ~IEEE80211_F_WPA;
1985                         /* both require a key so mark the PRIVACY capability */
1986                         ic->ic_flags |= IEEE80211_F_PRIVACY;
1987                         break;
1988                 case IEEE80211_AUTH_AUTO:       /* auto */
1989                         ic->ic_flags &= ~IEEE80211_F_WPA;
1990                         /* XXX PRIVACY handling? */
1991                         /* XXX what's the right way to do this? */
1992                         break;
1993                 }
1994                 /* NB: authenticator attach/detach happens on state change */
1995                 ic->ic_bss->ni_authmode = ireq->i_val;
1996                 /* XXX mixed/mode/usage? */
1997                 ic->ic_auth = auth;
1998                 if (IS_UP_AUTO(ic))
1999                         error = ieee80211_init(ic, RESCAN);
2000                 break;
2001         case IEEE80211_IOC_CHANNEL:
2002                 error = ieee80211_ioctl_setchannel(ic, ireq);
2003                 break;
2004         case IEEE80211_IOC_POWERSAVE:
2005                 switch (ireq->i_val) {
2006                 case IEEE80211_POWERSAVE_OFF:
2007                         if (ic->ic_flags & IEEE80211_F_PMGTON) {
2008                                 ic->ic_flags &= ~IEEE80211_F_PMGTON;
2009                                 error = ENETRESET;
2010                         }
2011                         break;
2012                 case IEEE80211_POWERSAVE_ON:
2013                         if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
2014                                 error = EINVAL;
2015                         else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
2016                                 ic->ic_flags |= IEEE80211_F_PMGTON;
2017                                 error = ENETRESET;
2018                         }
2019                         break;
2020                 default:
2021                         error = EINVAL;
2022                         break;
2023                 }
2024                 if (error == ENETRESET) {
2025                         /*
2026                          * Switching in+out of power save mode
2027                          * should not require a state change.
2028                          */
2029                         error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2030                 }
2031                 break;
2032         case IEEE80211_IOC_POWERSAVESLEEP:
2033                 if (ireq->i_val < 0)
2034                         return EINVAL;
2035                 ic->ic_lintval = ireq->i_val;
2036                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2037                 break;
2038         case IEEE80211_IOC_RTSTHRESHOLD:
2039                 if (!(IEEE80211_RTS_MIN <= ireq->i_val &&
2040                       ireq->i_val <= IEEE80211_RTS_MAX))
2041                         return EINVAL;
2042                 ic->ic_rtsthreshold = ireq->i_val;
2043                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2044                 break;
2045         case IEEE80211_IOC_PROTMODE:
2046                 if (ireq->i_val > IEEE80211_PROT_RTSCTS)
2047                         return EINVAL;
2048                 ic->ic_protmode = ireq->i_val;
2049                 /* NB: if not operating in 11g this can wait */
2050                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2051                     IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
2052                         error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2053                 break;
2054         case IEEE80211_IOC_TXPOWER:
2055                 if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
2056                         return EINVAL;
2057                 if (!(IEEE80211_TXPOWER_MIN <= ireq->i_val &&
2058                       ireq->i_val <= IEEE80211_TXPOWER_MAX))
2059                         return EINVAL;
2060                 ic->ic_txpowlimit = ireq->i_val;
2061                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2062                 break;
2063         case IEEE80211_IOC_ROAMING:
2064                 if (!(IEEE80211_ROAMING_DEVICE <= ireq->i_val &&
2065                     ireq->i_val <= IEEE80211_ROAMING_MANUAL))
2066                         return EINVAL;
2067                 ic->ic_roaming = ireq->i_val;
2068                 /* XXXX reset? */
2069                 break;
2070         case IEEE80211_IOC_PRIVACY:
2071                 if (ireq->i_val) {
2072                         /* XXX check for key state? */
2073                         ic->ic_flags |= IEEE80211_F_PRIVACY;
2074                 } else
2075                         ic->ic_flags &= ~IEEE80211_F_PRIVACY;
2076                 break;
2077         case IEEE80211_IOC_DROPUNENCRYPTED:
2078                 if (ireq->i_val)
2079                         ic->ic_flags |= IEEE80211_F_DROPUNENC;
2080                 else
2081                         ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
2082                 break;
2083         case IEEE80211_IOC_WPAKEY:
2084                 error = ieee80211_ioctl_setkey(ic, ireq);
2085                 break;
2086         case IEEE80211_IOC_DELKEY:
2087                 error = ieee80211_ioctl_delkey(ic, ireq);
2088                 break;
2089         case IEEE80211_IOC_MLME:
2090                 error = ieee80211_ioctl_setmlme(ic, ireq);
2091                 break;
2092         case IEEE80211_IOC_OPTIE:
2093                 error = ieee80211_ioctl_setoptie(ic, ireq);
2094                 break;
2095         case IEEE80211_IOC_COUNTERMEASURES:
2096                 if (ireq->i_val) {
2097                         if ((ic->ic_flags & IEEE80211_F_WPA) == 0)
2098                                 return EINVAL;
2099                         ic->ic_flags |= IEEE80211_F_COUNTERM;
2100                 } else
2101                         ic->ic_flags &= ~IEEE80211_F_COUNTERM;
2102                 break;
2103         case IEEE80211_IOC_WPA:
2104                 if (ireq->i_val > 3)
2105                         return EINVAL;
2106                 /* XXX verify ciphers available */
2107                 ic->ic_flags &= ~IEEE80211_F_WPA;
2108                 switch (ireq->i_val) {
2109                 case 1:
2110                         ic->ic_flags |= IEEE80211_F_WPA1;
2111                         break;
2112                 case 2:
2113                         ic->ic_flags |= IEEE80211_F_WPA2;
2114                         break;
2115                 case 3:
2116                         ic->ic_flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2;
2117                         break;
2118                 }
2119                 error = ENETRESET;
2120                 break;
2121         case IEEE80211_IOC_WME:
2122                 if (ireq->i_val) {
2123                         if ((ic->ic_caps & IEEE80211_C_WME) == 0)
2124                                 return EINVAL;
2125                         ic->ic_flags |= IEEE80211_F_WME;
2126                 } else
2127                         ic->ic_flags &= ~IEEE80211_F_WME;
2128                 if (IS_UP_AUTO(ic))
2129                         error = ieee80211_init(ic, 0);
2130                 break;
2131         case IEEE80211_IOC_HIDESSID:
2132                 if (ireq->i_val)
2133                         ic->ic_flags |= IEEE80211_F_HIDESSID;
2134                 else
2135                         ic->ic_flags &= ~IEEE80211_F_HIDESSID;
2136                 error = ENETRESET;
2137                 break;
2138         case IEEE80211_IOC_APBRIDGE:
2139                 if (ireq->i_val == 0)
2140                         ic->ic_flags |= IEEE80211_F_NOBRIDGE;
2141                 else
2142                         ic->ic_flags &= ~IEEE80211_F_NOBRIDGE;
2143                 break;
2144         case IEEE80211_IOC_MCASTCIPHER:
2145                 if ((ic->ic_caps & cipher2cap(ireq->i_val)) == 0 &&
2146                     !ieee80211_crypto_available(ireq->i_val))
2147                         return EINVAL;
2148                 rsn->rsn_mcastcipher = ireq->i_val;
2149                 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2150                 break;
2151         case IEEE80211_IOC_MCASTKEYLEN:
2152                 if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
2153                         return EINVAL;
2154                 /* XXX no way to verify driver capability */
2155                 rsn->rsn_mcastkeylen = ireq->i_val;
2156                 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2157                 break;
2158         case IEEE80211_IOC_UCASTCIPHERS:
2159                 /*
2160                  * Convert user-specified cipher set to the set
2161                  * we can support (via hardware or software).
2162                  * NB: this logic intentionally ignores unknown and
2163                  * unsupported ciphers so folks can specify 0xff or
2164                  * similar and get all available ciphers.
2165                  */
2166                 caps = 0;
2167                 for (j = 1; j < 32; j++)        /* NB: skip WEP */
2168                         if ((ireq->i_val & (1<<j)) &&
2169                             ((ic->ic_caps & cipher2cap(j)) ||
2170                              ieee80211_crypto_available(j)))
2171                                 caps |= 1<<j;
2172                 if (caps == 0)                  /* nothing available */
2173                         return EINVAL;
2174                 /* XXX verify ciphers ok for unicast use? */
2175                 /* XXX disallow if running as it'll have no effect */
2176                 rsn->rsn_ucastcipherset = caps;
2177                 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2178                 break;
2179         case IEEE80211_IOC_UCASTCIPHER:
2180                 if ((rsn->rsn_ucastcipherset & cipher2cap(ireq->i_val)) == 0)
2181                         return EINVAL;
2182                 rsn->rsn_ucastcipher = ireq->i_val;
2183                 break;
2184         case IEEE80211_IOC_UCASTKEYLEN:
2185                 if (!(0 < ireq->i_val && ireq->i_val < IEEE80211_KEYBUF_SIZE))
2186                         return EINVAL;
2187                 /* XXX no way to verify driver capability */
2188                 rsn->rsn_ucastkeylen = ireq->i_val;
2189                 break;
2190         case IEEE80211_IOC_DRIVER_CAPS:
2191                 /* NB: for testing */
2192                 ic->ic_caps = (((uint16_t) ireq->i_val) << 16) |
2193                                ((uint16_t) ireq->i_len);
2194                 break;
2195         case IEEE80211_IOC_KEYMGTALGS:
2196                 /* XXX check */
2197                 rsn->rsn_keymgmtset = ireq->i_val;
2198                 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2199                 break;
2200         case IEEE80211_IOC_RSNCAPS:
2201                 /* XXX check */
2202                 rsn->rsn_caps = ireq->i_val;
2203                 error = (ic->ic_flags & IEEE80211_F_WPA) ? ENETRESET : 0;
2204                 break;
2205         case IEEE80211_IOC_BSSID:
2206                 if (ireq->i_len != sizeof(tmpbssid))
2207                         return EINVAL;
2208                 error = copyin(ireq->i_data, tmpbssid, ireq->i_len);
2209                 if (error)
2210                         break;
2211                 IEEE80211_ADDR_COPY(ic->ic_des_bssid, tmpbssid);
2212                 if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zerobssid))
2213                         ic->ic_flags &= ~IEEE80211_F_DESBSSID;
2214                 else
2215                         ic->ic_flags |= IEEE80211_F_DESBSSID;
2216                 if (IS_UP_AUTO(ic))
2217                         error = ieee80211_init(ic, RESCAN);
2218                 break;
2219         case IEEE80211_IOC_CHANLIST:
2220                 error = ieee80211_ioctl_setchanlist(ic, ireq);
2221                 break;
2222         case IEEE80211_IOC_SCAN_REQ:
2223                 if (!IS_UP(ic))
2224                         return EINVAL;
2225                 (void) ieee80211_start_scan(ic,
2226                         IEEE80211_SCAN_ACTIVE |
2227                         IEEE80211_SCAN_NOPICK |
2228                         IEEE80211_SCAN_ONCE, IEEE80211_SCAN_FOREVER,
2229                         /* XXX use ioctl params */
2230                         ic->ic_des_nssid, ic->ic_des_ssid);
2231                 break;
2232         case IEEE80211_IOC_ADDMAC:
2233         case IEEE80211_IOC_DELMAC:
2234                 error = ieee80211_ioctl_macmac(ic, ireq);
2235                 break;
2236         case IEEE80211_IOC_MACCMD:
2237                 error = ieee80211_ioctl_setmaccmd(ic, ireq);
2238                 break;
2239         case IEEE80211_IOC_STA_STATS:
2240                 error = ieee80211_ioctl_setstastats(ic, ireq);
2241                 break;
2242         case IEEE80211_IOC_STA_TXPOW:
2243                 error = ieee80211_ioctl_setstatxpow(ic, ireq);
2244                 break;
2245         case IEEE80211_IOC_WME_CWMIN:           /* WME: CWmin */
2246         case IEEE80211_IOC_WME_CWMAX:           /* WME: CWmax */
2247         case IEEE80211_IOC_WME_AIFS:            /* WME: AIFS */
2248         case IEEE80211_IOC_WME_TXOPLIMIT:       /* WME: txops limit */
2249         case IEEE80211_IOC_WME_ACM:             /* WME: ACM (bss only) */
2250         case IEEE80211_IOC_WME_ACKPOLICY:       /* WME: ACK policy (bss only) */
2251                 error = ieee80211_ioctl_setwmeparam(ic, ireq);
2252                 break;
2253         case IEEE80211_IOC_DTIM_PERIOD:
2254                 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
2255                     ic->ic_opmode != IEEE80211_M_IBSS)
2256                         return EINVAL;
2257                 if (IEEE80211_DTIM_MIN <= ireq->i_val &&
2258                     ireq->i_val <= IEEE80211_DTIM_MAX) {
2259                         ic->ic_dtim_period = ireq->i_val;
2260                         error = ENETRESET;              /* requires restart */
2261                 } else
2262                         error = EINVAL;
2263                 break;
2264         case IEEE80211_IOC_BEACON_INTERVAL:
2265                 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
2266                     ic->ic_opmode != IEEE80211_M_IBSS)
2267                         return EINVAL;
2268                 if (IEEE80211_BINTVAL_MIN <= ireq->i_val &&
2269                     ireq->i_val <= IEEE80211_BINTVAL_MAX) {
2270                         ic->ic_bintval = ireq->i_val;
2271                         error = ENETRESET;              /* requires restart */
2272                 } else
2273                         error = EINVAL;
2274                 break;
2275         case IEEE80211_IOC_PUREG:
2276                 if (ireq->i_val)
2277                         ic->ic_flags |= IEEE80211_F_PUREG;
2278                 else
2279                         ic->ic_flags &= ~IEEE80211_F_PUREG;
2280                 /* NB: reset only if we're operating on an 11g channel */
2281                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2282                     IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
2283                         error = ENETRESET;
2284                 break;
2285         case IEEE80211_IOC_FF:
2286                 if (ireq->i_val) {
2287                         if ((ic->ic_caps & IEEE80211_C_FF) == 0)
2288                                 return EINVAL;
2289                         ic->ic_flags |= IEEE80211_F_FF;
2290                 } else
2291                         ic->ic_flags &= ~IEEE80211_F_FF;
2292                 error = ENETRESET;
2293                 break;
2294         case IEEE80211_IOC_TURBOP:
2295                 if (ireq->i_val) {
2296                         if ((ic->ic_caps & IEEE80211_C_TURBOP) == 0)
2297                                 return EINVAL;
2298                         ic->ic_flags |= IEEE80211_F_TURBOP;
2299                 } else
2300                         ic->ic_flags &= ~IEEE80211_F_TURBOP;
2301                 error = ENETRESET;
2302                 break;
2303         case IEEE80211_IOC_BGSCAN:
2304                 if (ireq->i_val) {
2305                         if ((ic->ic_caps & IEEE80211_C_BGSCAN) == 0)
2306                                 return EINVAL;
2307                         ic->ic_flags |= IEEE80211_F_BGSCAN;
2308                 } else
2309                         ic->ic_flags &= ~IEEE80211_F_BGSCAN;
2310                 break;
2311         case IEEE80211_IOC_BGSCAN_IDLE:
2312                 if (ireq->i_val >= IEEE80211_BGSCAN_IDLE_MIN)
2313                         ic->ic_bgscanidle = ireq->i_val*hz/1000;
2314                 else
2315                         error = EINVAL;
2316                 break;
2317         case IEEE80211_IOC_BGSCAN_INTERVAL:
2318                 if (ireq->i_val >= IEEE80211_BGSCAN_INTVAL_MIN)
2319                         ic->ic_bgscanintvl = ireq->i_val*hz;
2320                 else
2321                         error = EINVAL;
2322                 break;
2323         case IEEE80211_IOC_SCANVALID:
2324                 if (ireq->i_val >= IEEE80211_SCAN_VALID_MIN)
2325                         ic->ic_scanvalid = ireq->i_val*hz;
2326                 else
2327                         error = EINVAL;
2328                 break;
2329         case IEEE80211_IOC_ROAM_RSSI_11A:
2330                 ic->ic_roam.rssi11a = ireq->i_val;
2331                 break;
2332         case IEEE80211_IOC_ROAM_RSSI_11B:
2333                 ic->ic_roam.rssi11bOnly = ireq->i_val;
2334                 break;
2335         case IEEE80211_IOC_ROAM_RSSI_11G:
2336                 ic->ic_roam.rssi11b = ireq->i_val;
2337                 break;
2338         case IEEE80211_IOC_ROAM_RATE_11A:
2339                 ic->ic_roam.rate11a = ireq->i_val & IEEE80211_RATE_VAL;
2340                 break;
2341         case IEEE80211_IOC_ROAM_RATE_11B:
2342                 ic->ic_roam.rate11bOnly = ireq->i_val & IEEE80211_RATE_VAL;
2343                 break;
2344         case IEEE80211_IOC_ROAM_RATE_11G:
2345                 ic->ic_roam.rate11b = ireq->i_val & IEEE80211_RATE_VAL;
2346                 break;
2347         case IEEE80211_IOC_MCAST_RATE:
2348                 ic->ic_mcast_rate = ireq->i_val & IEEE80211_RATE_VAL;
2349                 break;
2350         case IEEE80211_IOC_FRAGTHRESHOLD:
2351                 if ((ic->ic_caps & IEEE80211_C_TXFRAG) == 0 &&
2352                     ireq->i_val != IEEE80211_FRAG_MAX)
2353                         return EINVAL;
2354                 if (!(IEEE80211_FRAG_MIN <= ireq->i_val &&
2355                       ireq->i_val <= IEEE80211_FRAG_MAX))
2356                         return EINVAL;
2357                 ic->ic_fragthreshold = ireq->i_val;
2358                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2359                 break;
2360         case IEEE80211_IOC_BURST:
2361                 if (ireq->i_val) {
2362                         if ((ic->ic_caps & IEEE80211_C_BURST) == 0)
2363                                 return EINVAL;
2364                         ic->ic_flags |= IEEE80211_F_BURST;
2365                 } else
2366                         ic->ic_flags &= ~IEEE80211_F_BURST;
2367                 error = ENETRESET;              /* XXX maybe not for station? */
2368                 break;
2369         case IEEE80211_IOC_BMISSTHRESHOLD:
2370                 if (!(IEEE80211_HWBMISS_MIN <= ireq->i_val &&
2371                       ireq->i_val <= IEEE80211_HWBMISS_MAX))
2372                         return EINVAL;
2373                 ic->ic_bmissthreshold = ireq->i_val;
2374                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2375                 break;
2376         case IEEE80211_IOC_CURCHAN:
2377                 error = ieee80211_ioctl_setcurchan(ic, ireq);
2378                 break;
2379         case IEEE80211_IOC_SHORTGI:
2380                 if (ireq->i_val) {
2381 #define IEEE80211_HTCAP_SHORTGI \
2382         (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40)
2383                         if (((ireq->i_val ^ ic->ic_htcaps) & IEEE80211_HTCAP_SHORTGI) != 0)
2384                                 return EINVAL;
2385                         if (ireq->i_val & IEEE80211_HTCAP_SHORTGI20)
2386                                 ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI20;
2387                         if (ireq->i_val & IEEE80211_HTCAP_SHORTGI40)
2388                                 ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI40;
2389 #undef IEEE80211_HTCAP_SHORTGI
2390                 } else
2391                         ic->ic_flags_ext &=
2392                             ~(IEEE80211_FEXT_SHORTGI20 | IEEE80211_FEXT_SHORTGI40);
2393                 /* XXX kick state machine? */
2394                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2395                 break;
2396         case IEEE80211_IOC_AMPDU:
2397                 if (ireq->i_val) {
2398                         if ((ic->ic_htcaps & IEEE80211_HTC_AMPDU) == 0)
2399                                 return EINVAL;
2400                         if (ireq->i_val & 1)
2401                                 ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_TX;
2402                         if (ireq->i_val & 2)
2403                                 ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_RX;
2404                 } else
2405                         ic->ic_flags_ext &=
2406                             ~(IEEE80211_FEXT_AMPDU_TX|IEEE80211_FEXT_AMPDU_RX);
2407                 /* NB: reset only if we're operating on an 11n channel */
2408                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2409                     IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
2410                         error = ENETRESET;
2411                 break;
2412         case IEEE80211_IOC_AMPDU_LIMIT:
2413                 /* XXX validate */
2414                 ic->ic_ampdu_limit = ireq->i_val;
2415                 break;
2416         case IEEE80211_IOC_AMPDU_DENSITY:
2417                 /* XXX validate */
2418                 ic->ic_ampdu_density = ireq->i_val;
2419                 break;
2420         case IEEE80211_IOC_AMSDU:
2421                 if (ireq->i_val) {
2422                         if ((ic->ic_htcaps & IEEE80211_HTC_AMSDU) == 0)
2423                                 return EINVAL;
2424                         if (ireq->i_val & 1)
2425                                 ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_TX;
2426                         if (ireq->i_val & 2)
2427                                 ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_RX;
2428                 } else
2429                         ic->ic_flags_ext &=
2430                             ~(IEEE80211_FEXT_AMSDU_TX|IEEE80211_FEXT_AMSDU_RX);
2431                 /* NB: reset only if we're operating on an 11n channel */
2432                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2433                     IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
2434                         error = ENETRESET;
2435                 break;
2436         case IEEE80211_IOC_AMSDU_LIMIT:
2437                 /* XXX validate */
2438                 ic->ic_amsdu_limit = ireq->i_val;       /* XXX truncation? */
2439                 break;
2440         case IEEE80211_IOC_PUREN:
2441                 if (ireq->i_val) {
2442                         if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) == 0)
2443                                 return EINVAL;
2444                         ic->ic_flags_ext |= IEEE80211_FEXT_PUREN;
2445                 } else
2446                         ic->ic_flags_ext &= ~IEEE80211_FEXT_PUREN;
2447                 /* NB: reset only if we're operating on an 11n channel */
2448                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2449                     IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
2450                         error = ENETRESET;
2451                 break;
2452         case IEEE80211_IOC_DOTH:
2453                 if (ireq->i_val) {
2454 #if 0
2455                         /* XXX no capability */
2456                         if ((ic->ic_caps & IEEE80211_C_DOTH) == 0)
2457                                 return EINVAL;
2458 #endif
2459                         ic->ic_flags |= IEEE80211_F_DOTH;
2460                 } else
2461                         ic->ic_flags &= ~IEEE80211_F_DOTH;
2462                 error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
2463                 break;
2464         case IEEE80211_IOC_HTCOMPAT:
2465                 if (ireq->i_val) {
2466                         if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) == 0)
2467                                 return EINVAL;
2468                         ic->ic_flags_ext |= IEEE80211_FEXT_HTCOMPAT;
2469                 } else
2470                         ic->ic_flags_ext &= ~IEEE80211_FEXT_HTCOMPAT;
2471                 /* NB: reset only if we're operating on an 11n channel */
2472                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
2473                     IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
2474                         error = ENETRESET;
2475                 break;
2476         case IEEE80211_IOC_INACTIVITY:
2477                 if (ireq->i_val)
2478                         ic->ic_flags_ext |= IEEE80211_FEXT_INACT;
2479                 else
2480                         ic->ic_flags_ext &= ~IEEE80211_FEXT_INACT;
2481                 break;
2482         default:
2483                 error = EINVAL;
2484                 break;
2485         }
2486         if (error == ENETRESET)
2487                 error = IS_UP_AUTO(ic) ? ieee80211_init(ic, 0) : 0;
2488         return error;
2489 }
2490
2491 int
2492 ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, caddr_t data)
2493 {
2494         struct ifnet *ifp = ic->ic_ifp;
2495         int error = 0;
2496         struct ifreq *ifr;
2497         struct ifaddr *ifa;                     /* XXX */
2498
2499         switch (cmd) {
2500         case SIOCSIFMEDIA:
2501         case SIOCGIFMEDIA:
2502                 error = ifmedia_ioctl(ifp, (struct ifreq *) data,
2503                                 &ic->ic_media, cmd);
2504                 break;
2505         case SIOCG80211:
2506                 error = ieee80211_ioctl_get80211(ic, cmd,
2507                                 (struct ieee80211req *) data);
2508                 break;
2509         case SIOCS80211:
2510                 error = priv_check(curthread, PRIV_NET80211_MANAGE);
2511                 if (error == 0)
2512                         error = ieee80211_ioctl_set80211(ic, cmd,
2513                                         (struct ieee80211req *) data);
2514                 break;
2515         case SIOCG80211STATS:
2516                 ifr = (struct ifreq *)data;
2517                 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
2518                 break;
2519         case SIOCSIFMTU:
2520                 ifr = (struct ifreq *)data;
2521                 if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
2522                     ifr->ifr_mtu <= IEEE80211_MTU_MAX))
2523                         error = EINVAL;
2524                 else
2525                         ifp->if_mtu = ifr->ifr_mtu;
2526                 break;
2527         case SIOCSIFADDR:
2528                 /*
2529                  * XXX Handle this directly so we can supress if_init calls.
2530                  * XXX This should be done in ether_ioctl but for the moment
2531                  * XXX there are too many other parts of the system that
2532                  * XXX set IFF_UP and so supress if_init being called when
2533                  * XXX it should be.
2534                  */
2535                 ifa = (struct ifaddr *) data;
2536                 switch (ifa->ifa_addr->sa_family) {
2537 #ifdef INET
2538                 case AF_INET:
2539                         if ((ifp->if_flags & IFF_UP) == 0) {
2540                                 ifp->if_flags |= IFF_UP;
2541                                 ifp->if_init(ifp->if_softc);
2542                         }
2543                         arp_ifinit(ifp, ifa);
2544                         break;
2545 #endif
2546 #ifdef IPX
2547                 /*
2548                  * XXX - This code is probably wrong,
2549                  *       but has been copied many times.
2550                  */
2551                 case AF_IPX: {
2552                         struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
2553
2554                         if (ipx_nullhost(*ina))
2555                                 ina->x_host = *(union ipx_host *)
2556                                     IF_LLADDR(ifp);
2557                         else
2558                                 bcopy((caddr_t) ina->x_host.c_host,
2559                                       (caddr_t) IF_LLADDR(ifp),
2560                                       ETHER_ADDR_LEN);
2561                         /* fall thru... */
2562                 }
2563 #endif
2564                 default:
2565                         if ((ifp->if_flags & IFF_UP) == 0) {
2566                                 ifp->if_flags |= IFF_UP;
2567                                 ifp->if_init(ifp->if_softc);
2568                         }
2569                         break;
2570                 }
2571                 break;
2572         default:
2573                 error = ether_ioctl(ifp, cmd, data);
2574                 break;
2575         }
2576         return error;
2577 }