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