[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/net80211/ieee80211_ioctl.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /*-
  2  * Copyright (c) 2001 Atsushi Onoe
  3  * Copyright (c) 2002-2008 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: src/sys/net80211/ieee80211_ioctl.c,v 1.68 2008/10/25 23:32:24 sam Exp $");
 29 
 30 /*
 31  * IEEE 802.11 ioctl support (FreeBSD-specific)
 32  */
 33 
 34 #include "opt_inet.h"
 35 #include "opt_ipx.h"
 36 #include "opt_wlan.h"
 37 
 38 #include <sys/endian.h>
 39 #include <sys/param.h>
 40 #include <sys/kernel.h>
 41 #include <sys/priv.h>
 42 #include <sys/socket.h>
 43 #include <sys/sockio.h>
 44 #include <sys/systm.h>
 45  
 46 #include <net/if.h>
 47 #include <net/if_dl.h>
 48 #include <net/if_media.h>
 49 #include <net/ethernet.h>
 50 
 51 #ifdef INET
 52 #include <netinet/in.h>
 53 #include <netinet/if_ether.h>
 54 #endif
 55 
 56 #ifdef IPX
 57 #include <netipx/ipx.h>
 58 #include <netipx/ipx_if.h>
 59 #endif
 60 
 61 #include <net80211/ieee80211_var.h>
 62 #include <net80211/ieee80211_ioctl.h>
 63 #include <net80211/ieee80211_regdomain.h>
 64 #include <net80211/ieee80211_input.h>
 65 
 66 #define IS_UP_AUTO(_vap) \
 67         (IFNET_IS_UP_RUNNING(vap->iv_ifp) && \
 68          (_vap)->iv_roaming == IEEE80211_ROAMING_AUTO)
 69 
 70 static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
 71 static struct ieee80211_channel *findchannel(struct ieee80211com *,
 72                 int ieee, int mode);
 73 
 74 static __noinline int
 75 ieee80211_ioctl_getkey(struct ieee80211vap *vap, struct ieee80211req *ireq)
 76 {
 77         struct ieee80211com *ic = vap->iv_ic;
 78         struct ieee80211_node *ni;
 79         struct ieee80211req_key ik;
 80         struct ieee80211_key *wk;
 81         const struct ieee80211_cipher *cip;
 82         u_int kid;
 83         int error;
 84 
 85         if (ireq->i_len != sizeof(ik))
 86                 return EINVAL;
 87         error = copyin(ireq->i_data, &ik, sizeof(ik));
 88         if (error)
 89                 return error;
 90         kid = ik.ik_keyix;
 91         if (kid == IEEE80211_KEYIX_NONE) {
 92                 ni = ieee80211_find_vap_node(&ic->ic_sta, vap, ik.ik_macaddr);
 93                 if (ni == NULL)
 94                         return ENOENT;
 95                 wk = &ni->ni_ucastkey;
 96         } else {
 97                 if (kid >= IEEE80211_WEP_NKID)
 98                         return EINVAL;
 99                 wk = &vap->iv_nw_keys[kid];
100                 IEEE80211_ADDR_COPY(&ik.ik_macaddr, vap->iv_bss->ni_macaddr);
101                 ni = NULL;
102         }
103         cip = wk->wk_cipher;
104         ik.ik_type = cip->ic_cipher;
105         ik.ik_keylen = wk->wk_keylen;
106         ik.ik_flags = wk->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
107         if (wk->wk_keyix == vap->iv_def_txkey)
108                 ik.ik_flags |= IEEE80211_KEY_DEFAULT;
109         if (priv_check(curthread, PRIV_NET80211_GETKEY) == 0) {
110                 /* NB: only root can read key data */
111                 ik.ik_keyrsc = wk->wk_keyrsc[IEEE80211_NONQOS_TID];
112                 ik.ik_keytsc = wk->wk_keytsc;
113                 memcpy(ik.ik_keydata, wk->wk_key, wk->wk_keylen);
114                 if (cip->ic_cipher == IEEE80211_CIPHER_TKIP) {
115                         memcpy(ik.ik_keydata+wk->wk_keylen,
116                                 wk->wk_key + IEEE80211_KEYBUF_SIZE,
117                                 IEEE80211_MICBUF_SIZE);
118                         ik.ik_keylen += IEEE80211_MICBUF_SIZE;
119                 }
120         } else {
121                 ik.ik_keyrsc = 0;
122                 ik.ik_keytsc = 0;
123                 memset(ik.ik_keydata, 0, sizeof(ik.ik_keydata));
124         }
125         if (ni != NULL)
126                 ieee80211_free_node(ni);
127         return copyout(&ik, ireq->i_data, sizeof(ik));
128 }
129 
130 static __noinline int
131 ieee80211_ioctl_getchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq)
132 {
133         struct ieee80211com *ic = vap->iv_ic;
134 
135         if (sizeof(ic->ic_chan_active) < ireq->i_len)
136                 ireq->i_len = sizeof(ic->ic_chan_active);
137         return copyout(&ic->ic_chan_active, ireq->i_data, ireq->i_len);
138 }
139 
140 static __noinline int
141 ieee80211_ioctl_getchaninfo(struct ieee80211vap *vap, struct ieee80211req *ireq)
142 {
143         struct ieee80211com *ic = vap->iv_ic;
144         int space;
145 
146         space = __offsetof(struct ieee80211req_chaninfo,
147                         ic_chans[ic->ic_nchans]);
148         if (space > ireq->i_len)
149                 space = ireq->i_len;
150         /* XXX assumes compatible layout */
151         return copyout(&ic->ic_nchans, ireq->i_data, space);
152 }
153 
154 static __noinline int
155 ieee80211_ioctl_getwpaie(struct ieee80211vap *vap,
156         struct ieee80211req *ireq, int req)
157 {
158         struct ieee80211_node *ni;
159         struct ieee80211req_wpaie2 wpaie;
160         int error;
161 
162         if (ireq->i_len < IEEE80211_ADDR_LEN)
163                 return EINVAL;
164         error = copyin(ireq->i_data, wpaie.wpa_macaddr, IEEE80211_ADDR_LEN);
165         if (error != 0)
166                 return error;
167         ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, wpaie.wpa_macaddr);
168         if (ni == NULL)
169                 return ENOENT;
170         memset(wpaie.wpa_ie, 0, sizeof(wpaie.wpa_ie));
171         if (ni->ni_ies.wpa_ie != NULL) {
172                 int ielen = ni->ni_ies.wpa_ie[1] + 2;
173                 if (ielen > sizeof(wpaie.wpa_ie))
174                         ielen = sizeof(wpaie.wpa_ie);
175                 memcpy(wpaie.wpa_ie, ni->ni_ies.wpa_ie, ielen);
176         }
177         if (req == IEEE80211_IOC_WPAIE2) {
178                 memset(wpaie.rsn_ie, 0, sizeof(wpaie.rsn_ie));
179                 if (ni->ni_ies.rsn_ie != NULL) {
180                         int ielen = ni->ni_ies.rsn_ie[1] + 2;
181                         if (ielen > sizeof(wpaie.rsn_ie))
182                                 ielen = sizeof(wpaie.rsn_ie);
183                         memcpy(wpaie.rsn_ie, ni->ni_ies.rsn_ie, ielen);
184                 }
185                 if (ireq->i_len > sizeof(struct ieee80211req_wpaie2))
186                         ireq->i_len = sizeof(struct ieee80211req_wpaie2);
187         } else {
188                 /* compatibility op, may overwrite wpa ie */
189                 /* XXX check ic_flags? */
190                 if (ni->ni_ies.rsn_ie != NULL) {
191                         int ielen = ni->ni_ies.rsn_ie[1] + 2;
192                         if (ielen > sizeof(wpaie.wpa_ie))
193                                 ielen = sizeof(wpaie.wpa_ie);
194                         memcpy(wpaie.wpa_ie, ni->ni_ies.rsn_ie, ielen);
195                 }
196                 if (ireq->i_len > sizeof(struct ieee80211req_wpaie))
197                         ireq->i_len = sizeof(struct ieee80211req_wpaie);
198         }
199         ieee80211_free_node(ni);
200         return copyout(&wpaie, ireq->i_data, ireq->i_len);
201 }
202 
203 static __noinline int
204 ieee80211_ioctl_getstastats(struct ieee80211vap *vap, struct ieee80211req *ireq)
205 {
206         struct ieee80211_node *ni;
207         uint8_t macaddr[IEEE80211_ADDR_LEN];
208         const int off = __offsetof(struct ieee80211req_sta_stats, is_stats);
209         int error;
210 
211         if (ireq->i_len < off)
212                 return EINVAL;
213         error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
214         if (error != 0)
215                 return error;
216         ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, macaddr);
217         if (ni == NULL)
218                 return ENOENT;
219         if (ireq->i_len > sizeof(struct ieee80211req_sta_stats))
220                 ireq->i_len = sizeof(struct ieee80211req_sta_stats);
221         /* NB: copy out only the statistics */
222         error = copyout(&ni->ni_stats, (uint8_t *) ireq->i_data + off,
223                         ireq->i_len - off);
224         ieee80211_free_node(ni);
225         return error;
226 }
227 
228 struct scanreq {
229         struct ieee80211req_scan_result *sr;
230         size_t space;
231 };
232 
233 static size_t
234 scan_space(const struct ieee80211_scan_entry *se, int *ielen)
235 {
236         size_t len;
237 
238         *ielen = se->se_ies.len;
239         /*
240          * NB: ie's can be no more than 255 bytes and the max 802.11
241          * packet is <3Kbytes so we are sure this doesn't overflow
242          * 16-bits; if this is a concern we can drop the ie's.
243          */
244         len = sizeof(struct ieee80211req_scan_result) + se->se_ssid[1] + *ielen;
245         return roundup(len, sizeof(uint32_t));
246 }
247 
248 static void
249 get_scan_space(void *arg, const struct ieee80211_scan_entry *se)
250 {
251         struct scanreq *req = arg;
252         int ielen;
253 
254         req->space += scan_space(se, &ielen);
255 }
256 
257 static __noinline void
258 get_scan_result(void *arg, const struct ieee80211_scan_entry *se)
259 {
260         struct scanreq *req = arg;
261         struct ieee80211req_scan_result *sr;
262         int ielen, len, nr, nxr;
263         uint8_t *cp;
264 
265         len = scan_space(se, &ielen);
266         if (len > req->space)
267                 return;
268 
269         sr = req->sr;
270         KASSERT(len <= 65535 && ielen <= 65535,
271             ("len %u ssid %u ie %u", len, se->se_ssid[1], ielen));
272         sr->isr_len = len;
273         sr->isr_ie_off = sizeof(struct ieee80211req_scan_result);
274         sr->isr_ie_len = ielen;
275         sr->isr_freq = se->se_chan->ic_freq;
276         sr->isr_flags = se->se_chan->ic_flags;
277         sr->isr_rssi = se->se_rssi;
278         sr->isr_noise = se->se_noise;
279         sr->isr_intval = se->se_intval;
280         sr->isr_capinfo = se->se_capinfo;
281         sr->isr_erp = se->se_erp;
282         IEEE80211_ADDR_COPY(sr->isr_bssid, se->se_bssid);
283         nr = min(se->se_rates[1], IEEE80211_RATE_MAXSIZE);
284         memcpy(sr->isr_rates, se->se_rates+2, nr);
285         nxr = min(se->se_xrates[1], IEEE80211_RATE_MAXSIZE - nr);
286         memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
287         sr->isr_nrates = nr + nxr;
288 
289         sr->isr_ssid_len = se->se_ssid[1];
290         cp = ((uint8_t *)sr) + sr->isr_ie_off;
291         memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
292 
293         if (ielen) {
294                 cp += sr->isr_ssid_len;
295                 memcpy(cp, se->se_ies.data, ielen);
296         }
297 
298         req->space -= len;
299         req->sr = (struct ieee80211req_scan_result *)(((uint8_t *)sr) + len);
300 }
301 
302 static __noinline int
303 ieee80211_ioctl_getscanresults(struct ieee80211vap *vap,
304         struct ieee80211req *ireq)
305 {
306         struct scanreq req;
307         int error;
308 
309         if (ireq->i_len < sizeof(struct scanreq))
310                 return EFAULT;
311 
312         error = 0;
313         req.space = 0;
314         ieee80211_scan_iterate(vap, get_scan_space, &req);
315         if (req.space > ireq->i_len)
316                 req.space = ireq->i_len;
317         if (req.space > 0) {
318                 size_t space;
319                 void *p;
320 
321                 space = req.space;
322                 /* XXX M_WAITOK after driver lock released */
323                 MALLOC(p, void *, space, M_TEMP, M_NOWAIT | M_ZERO);
324                 if (p == NULL)
325                         return ENOMEM;
326                 req.sr = p;
327                 ieee80211_scan_iterate(vap, get_scan_result, &req);
328                 ireq->i_len = space - req.space;
329                 error = copyout(p, ireq->i_data, ireq->i_len);
330                 FREE(p, M_TEMP);
331         } else
332                 ireq->i_len = 0;
333 
334         return error;
335 }
336 
337 struct stainforeq {
338         struct ieee80211vap *vap;
339         struct ieee80211req_sta_info *si;
340         size_t  space;
341 };
342 
343 static size_t
344 sta_space(const struct ieee80211_node *ni, size_t *ielen)
345 {
346         *ielen = ni->ni_ies.len;
347         return roundup(sizeof(struct ieee80211req_sta_info) + *ielen,
348                       sizeof(uint32_t));
349 }
350 
351 static void
352 get_sta_space(void *arg, struct ieee80211_node *ni)
353 {
354         struct stainforeq *req = arg;
355         size_t ielen;
356 
357         if (req->vap != ni->ni_vap)
358                 return;
359         if (ni->ni_vap->iv_opmode == IEEE80211_M_HOSTAP &&
360             ni->ni_associd == 0)        /* only associated stations */
361                 return;
362         req->space += sta_space(ni, &ielen);
363 }
364 
365 static __noinline void
366 get_sta_info(void *arg, struct ieee80211_node *ni)
367 {
368         struct stainforeq *req = arg;
369         struct ieee80211vap *vap = ni->ni_vap;
370         struct ieee80211req_sta_info *si;
371         size_t ielen, len;
372         uint8_t *cp;
373 
374         if (req->vap != ni->ni_vap)
375                 return;
376         if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
377             ni->ni_associd == 0)        /* only associated stations */
378                 return;
379         if (ni->ni_chan == IEEE80211_CHAN_ANYC) /* XXX bogus entry */
380                 return;
381         len = sta_space(ni, &ielen);
382         if (len > req->space)
383                 return;
384         si = req->si;
385         si->isi_len = len;
386         si->isi_ie_off = sizeof(struct ieee80211req_sta_info);
387         si->isi_ie_len = ielen;
388         si->isi_freq = ni->ni_chan->ic_freq;
389         si->isi_flags = ni->ni_chan->ic_flags;
390         si->isi_state = ni->ni_flags;
391         si->isi_authmode = ni->ni_authmode;
392         vap->iv_ic->ic_node_getsignal(ni, &si->isi_rssi, &si->isi_noise);
393         vap->iv_ic->ic_node_getmimoinfo(ni, &si->isi_mimo);
394         si->isi_capinfo = ni->ni_capinfo;
395         si->isi_erp = ni->ni_erp;
396         IEEE80211_ADDR_COPY(si->isi_macaddr, ni->ni_macaddr);
397         si->isi_nrates = ni->ni_rates.rs_nrates;
398         if (si->isi_nrates > 15)
399                 si->isi_nrates = 15;
400         memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates);
401         si->isi_txrate = ni->ni_txrate;
402         if (si->isi_txrate & IEEE80211_RATE_MCS) {
403                 const struct ieee80211_mcs_rates *mcs =
404                     &ieee80211_htrates[ni->ni_txrate &~ IEEE80211_RATE_MCS];
405                 if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
406                         if (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40)
407                                 si->isi_txmbps = mcs->ht40_rate_800ns;
408                         else
409                                 si->isi_txmbps = mcs->ht40_rate_400ns;
410                 } else {
411                         if (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)
412                                 si->isi_txmbps = mcs->ht20_rate_800ns;
413                         else
414                                 si->isi_txmbps = mcs->ht20_rate_400ns;
415                 }
416         } else
417                 si->isi_txmbps = si->isi_txrate;
418         si->isi_associd = ni->ni_associd;
419         si->isi_txpower = ni->ni_txpower;
420         si->isi_vlan = ni->ni_vlan;
421         if (ni->ni_flags & IEEE80211_NODE_QOS) {
422                 memcpy(si->isi_txseqs, ni->ni_txseqs, sizeof(ni->ni_txseqs));
423                 memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs));
424         } else {
425                 si->isi_txseqs[0] = ni->ni_txseqs[IEEE80211_NONQOS_TID];
426                 si->isi_rxseqs[0] = ni->ni_rxseqs[IEEE80211_NONQOS_TID];
427         }
428         /* NB: leave all cases in case we relax ni_associd == 0 check */
429         if (ieee80211_node_is_authorized(ni))
430                 si->isi_inact = vap->iv_inact_run;
431         else if (ni->ni_associd != 0 ||
432             (vap->iv_opmode == IEEE80211_M_WDS &&
433              (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY)))
434                 si->isi_inact = vap->iv_inact_auth;
435         else
436                 si->isi_inact = vap->iv_inact_init;
437         si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
438 
439         if (ielen) {
440                 cp = ((uint8_t *)si) + si->isi_ie_off;
441                 memcpy(cp, ni->ni_ies.data, ielen);
442         }
443 
444         req->si = (struct ieee80211req_sta_info *)(((uint8_t *)si) + len);
445         req->space -= len;
446 }
447 
448 static __noinline int
449 getstainfo_common(struct ieee80211vap *vap, struct ieee80211req *ireq,
450         struct ieee80211_node *ni, int off)
451 {
452         struct ieee80211com *ic = vap->iv_ic;
453         struct stainforeq req;
454         size_t space;
455         void *p;
456         int error;
457 
458         error = 0;
459         req.space = 0;
460         req.vap = vap;
461         if (ni == NULL)
462                 ieee80211_iterate_nodes(&ic->ic_sta, get_sta_space, &req);
463         else
464                 get_sta_space(&req, ni);
465         if (req.space > ireq->i_len)
466                 req.space = ireq->i_len;
467         if (req.space > 0) {
468                 space = req.space;
469                 /* XXX M_WAITOK after driver lock released */
470                 MALLOC(p, void *, space, M_TEMP, M_NOWAIT | M_ZERO);
471                 if (p == NULL) {
472                         error = ENOMEM;
473                         goto bad;
474                 }
475                 req.si = p;
476                 if (ni == NULL)
477                         ieee80211_iterate_nodes(&ic->ic_sta, get_sta_info, &req);
478                 else
479                         get_sta_info(&req, ni);
480                 ireq->i_len = space - req.space;
481                 error = copyout(p, (uint8_t *) ireq->i_data+off, ireq->i_len);
482                 FREE(p, M_TEMP);
483         } else
484                 ireq->i_len = 0;
485 bad:
486         if (ni != NULL)
487                 ieee80211_free_node(ni);
488         return error;
489 }
490 
491 static __noinline int
492 ieee80211_ioctl_getstainfo(struct ieee80211vap *vap, struct ieee80211req *ireq)
493 {
494         uint8_t macaddr[IEEE80211_ADDR_LEN];
495         const int off = __offsetof(struct ieee80211req_sta_req, info);
496         struct ieee80211_node *ni;
497         int error;
498 
499         if (ireq->i_len < sizeof(struct ieee80211req_sta_req))
500                 return EFAULT;
501         error = copyin(ireq->i_data, macaddr, IEEE80211_ADDR_LEN);
502         if (error != 0)
503                 return error;
504         if (IEEE80211_ADDR_EQ(macaddr, vap->iv_ifp->if_broadcastaddr)) {
505                 ni = NULL;
506         } else {
507                 ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, macaddr);
508                 if (ni == NULL)
509                         return ENOENT;
510         }
511         return getstainfo_common(vap, ireq, ni, off);
512 }
513 
514 static __noinline int
515 ieee80211_ioctl_getstatxpow(struct ieee80211vap *vap, struct ieee80211req *ireq)
516 {
517         struct ieee80211_node *ni;
518         struct ieee80211req_sta_txpow txpow;
519         int error;
520 
521         if (ireq->i_len != sizeof(txpow))
522                 return EINVAL;
523         error = copyin(ireq->i_data, &txpow, sizeof(txpow));
524         if (error != 0)
525                 return error;
526         ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap, txpow.it_macaddr);
527         if (ni == NULL)
528                 return ENOENT;
529         txpow.it_txpow = ni->ni_txpower;
530         error = copyout(&txpow, ireq->i_data, sizeof(txpow));
531         ieee80211_free_node(ni);
532         return error;
533 }
534 
535 static __noinline int
536 ieee80211_ioctl_getwmeparam(struct ieee80211vap *vap, struct ieee80211req *ireq)
537 {
538         struct ieee80211com *ic = vap->iv_ic;
539         struct ieee80211_wme_state *wme = &ic->ic_wme;
540         struct wmeParams *wmep;
541         int ac;
542 
543         if ((ic->ic_caps & IEEE80211_C_WME) == 0)
544                 return EINVAL;
545 
546         ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
547         if (ac >= WME_NUM_AC)
548                 ac = WME_AC_BE;
549         if (ireq->i_len & IEEE80211_WMEPARAM_BSS)
550                 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
551         else
552                 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
553         switch (ireq->i_type) {
554         case IEEE80211_IOC_WME_CWMIN:           /* WME: CWmin */
555                 ireq->i_val = wmep->wmep_logcwmin;
556                 break;
557         case IEEE80211_IOC_WME_CWMAX:           /* WME: CWmax */
558                 ireq->i_val = wmep->wmep_logcwmax;
559                 break;
560         case IEEE80211_IOC_WME_AIFS:            /* WME: AIFS */
561                 ireq->i_val = wmep->wmep_aifsn;
562                 break;
563         case IEEE80211_IOC_WME_TXOPLIMIT:       /* WME: txops limit */
564                 ireq->i_val = wmep->wmep_txopLimit;
565                 break;
566         case IEEE80211_IOC_WME_ACM:             /* WME: ACM (bss only) */
567                 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
568                 ireq->i_val = wmep->wmep_acm;
569                 break;
570         case IEEE80211_IOC_WME_ACKPOLICY:       /* WME: ACK policy (!bss only)*/
571                 wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
572                 ireq->i_val = !wmep->wmep_noackPolicy;
573                 break;
574         }
575         return 0;
576 }
577 
578 static __noinline int
579 ieee80211_ioctl_getmaccmd(struct ieee80211vap *vap, struct ieee80211req *ireq)
580 {
581         const struct ieee80211_aclator *acl = vap->iv_acl;
582 
583         return (acl == NULL ? EINVAL : acl->iac_getioctl(vap, ireq));
584 }
585 
586 /*
587  * Return the current ``state'' of an Atheros capbility.
588  * If associated in station mode report the negotiated
589  * setting. Otherwise report the current setting.
590  */
591 static int
592 getathcap(struct ieee80211vap *vap, int cap)
593 {
594         if (vap->iv_opmode == IEEE80211_M_STA &&
595             vap->iv_state == IEEE80211_S_RUN)
596                 return IEEE80211_ATH_CAP(vap, vap->iv_bss, cap) != 0;
597         else
598                 return (vap->iv_flags & cap) != 0;
599 }
600 
601 static __noinline int
602 ieee80211_ioctl_getcurchan(struct ieee80211vap *vap, struct ieee80211req *ireq)
603 {
604         struct ieee80211com *ic = vap->iv_ic;
605         struct ieee80211_channel *c;
606 
607         if (ireq->i_len != sizeof(struct ieee80211_channel))
608                 return EINVAL;
609         /*
610          * vap's may have different operating channels when HT is
611          * in use.  When in RUN state report the vap-specific channel.
612          * Otherwise return curchan.
613          */
614         if (vap->iv_state == IEEE80211_S_RUN)
615                 c = vap->iv_bss->ni_chan;
616         else
617                 c = ic->ic_curchan;
618         return copyout(c, ireq->i_data, sizeof(*c));
619 }
620 
621 static int
622 getappie(const struct ieee80211_appie *aie, struct ieee80211req *ireq)
623 {
624         if (aie == NULL)
625                 return EINVAL;
626         /* NB: truncate, caller can check length */
627         if (ireq->i_len > aie->ie_len)
628                 ireq->i_len = aie->ie_len;
629         return copyout(aie->ie_data, ireq->i_data, ireq->i_len);
630 }
631 
632 static int
633 ieee80211_ioctl_getappie(struct ieee80211vap *vap, struct ieee80211req *ireq)
634 {
635         uint8_t fc0;
636 
637         fc0 = ireq->i_val & 0xff;
638         if ((fc0 & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
639                 return EINVAL;
640         /* NB: could check iv_opmode and reject but hardly worth the effort */
641         switch (fc0 & IEEE80211_FC0_SUBTYPE_MASK) {
642         case IEEE80211_FC0_SUBTYPE_BEACON:
643                 return getappie(vap->iv_appie_beacon, ireq);
644         case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
645                 return getappie(vap->iv_appie_proberesp, ireq);
646         case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
647                 return getappie(vap->iv_appie_assocresp, ireq);
648         case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
649                 return getappie(vap->iv_appie_probereq, ireq);
650         case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
651                 return getappie(vap->iv_appie_assocreq, ireq);
652         case IEEE80211_FC0_SUBTYPE_BEACON|IEEE80211_FC0_SUBTYPE_PROBE_RESP:
653                 return getappie(vap->iv_appie_wpa, ireq);
654         }
655         return EINVAL;
656 }
657 
658 static __noinline int
659 ieee80211_ioctl_getregdomain(struct ieee80211vap *vap,
660         const struct ieee80211req *ireq)
661 {
662         struct ieee80211com *ic = vap->iv_ic;
663 
664         if (ireq->i_len != sizeof(ic->ic_regdomain))
665                 return EINVAL;
666         return copyout(&ic->ic_regdomain, ireq->i_data,
667             sizeof(ic->ic_regdomain));
668 }
669 
670 static __noinline int
671 ieee80211_ioctl_getroam(struct ieee80211vap *vap,
672         const struct ieee80211req *ireq)
673 {
674         if (ireq->i_len != sizeof(vap->iv_roamparms))
675                 return EINVAL;
676         return copyout(vap->iv_roamparms, ireq->i_data,
677             sizeof(vap->iv_roamparms));
678 }
679 
680 static __noinline int
681 ieee80211_ioctl_gettxparams(struct ieee80211vap *vap,
682         const struct ieee80211req *ireq)
683 {
684         if (ireq->i_len != sizeof(vap->iv_txparms))
685                 return EINVAL;
686         return copyout(vap->iv_txparms, ireq->i_data, sizeof(vap->iv_txparms));
687 }
688 
689 static __noinline int
690 ieee80211_ioctl_getdevcaps(struct ieee80211com *ic,
691         const struct ieee80211req *ireq)
692 {
693         struct ieee80211_devcaps_req *dc;
694         struct ieee80211req_chaninfo *ci;
695         int error;
696 
697         if (ireq->i_len != sizeof(struct ieee80211_devcaps_req))
698                 return EINVAL;
699         MALLOC(dc, struct ieee80211_devcaps_req *,
700             sizeof(struct ieee80211_devcaps_req), M_TEMP, M_NOWAIT | M_ZERO);
701         if (dc == NULL)
702                 return ENOMEM;
703         dc->dc_drivercaps = ic->ic_caps;
704         dc->dc_cryptocaps = ic->ic_cryptocaps;
705         dc->dc_htcaps = ic->ic_htcaps;
706         ci = &dc->dc_chaninfo;
707         ic->ic_getradiocaps(ic, &ci->ic_nchans, ci->ic_chans);
708         ieee80211_sort_channels(ci->ic_chans, ci->ic_nchans);
709         error = copyout(dc, ireq->i_data, sizeof(*dc));
710         FREE(dc, M_TEMP);
711         return error;
712 }
713 
714 static __noinline int
715 ieee80211_ioctl_getstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq)
716 {
717         struct ieee80211_node *ni;
718         struct ieee80211req_sta_vlan vlan;
719         int error;
720 
721         if (ireq->i_len != sizeof(vlan))
722                 return EINVAL;
723         error = copyin(ireq->i_data, &vlan, sizeof(vlan));
724         if (error != 0)
725                 return error;
726         if (!IEEE80211_ADDR_EQ(vlan.sv_macaddr, zerobssid)) {
727                 ni = ieee80211_find_vap_node(&vap->iv_ic->ic_sta, vap,
728                     vlan.sv_macaddr);
729                 if (ni == NULL)
730                         return ENOENT;
731         } else
732                 ni = ieee80211_ref_node(vap->iv_bss);
733         vlan.sv_vlan = ni->ni_vlan;
734         error = copyout(&vlan, ireq->i_data, sizeof(vlan));
735         ieee80211_free_node(ni);
736         return error;
737 }
738 
739 /*
740  * When building the kernel with -O2 on the i386 architecture, gcc
741  * seems to want to inline this function into ieee80211_ioctl()
742  * (which is the only routine that calls it). When this happens,
743  * ieee80211_ioctl() ends up consuming an additional 2K of stack
744  * space. (Exactly why it needs so much is unclear.) The problem
745  * is that it's possible for ieee80211_ioctl() to invoke other
746  * routines (including driver init functions) which could then find
747  * themselves perilously close to exhausting the stack.
748  *
749  * To avoid this, we deliberately prevent gcc from inlining this
750  * routine. Another way to avoid this is to use less agressive
751  * optimization when compiling this file (i.e. -O instead of -O2)
752  * but special-casing the compilation of this one module in the
753  * build system would be awkward.
754  */
755 static __noinline int
756 ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd,
757     struct ieee80211req *ireq)
758 {
759 #define MS(_v, _f)      (((_v) & _f) >> _f##_S)
760         struct ieee80211com *ic = vap->iv_ic;
761         u_int kid, len;
762         uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
763         char tmpssid[IEEE80211_NWID_LEN];
764         int error = 0;
765 
766         switch (ireq->i_type) {
767         case IEEE80211_IOC_SSID:
768                 switch (vap->iv_state) {
769                 case IEEE80211_S_INIT:
770                 case IEEE80211_S_SCAN:
771                         ireq->i_len = vap->iv_des_ssid[0].len;
772                         memcpy(tmpssid, vap->iv_des_ssid[0].ssid, ireq->i_len);
773                         break;
774                 default:
775                         ireq->i_len = vap->iv_bss->ni_esslen;
776                         memcpy(tmpssid, vap->iv_bss->ni_essid, ireq->i_len);
777                         break;
778                 }
779                 error = copyout(tmpssid, ireq->i_data, ireq->i_len);
780                 break;
781         case IEEE80211_IOC_NUMSSIDS:
782                 ireq->i_val = 1;
783                 break;
784         case IEEE80211_IOC_WEP:
785                 if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0)
786                         ireq->i_val = IEEE80211_WEP_OFF;
787                 else if (vap->iv_flags & IEEE80211_F_DROPUNENC)
788                         ireq->i_val = IEEE80211_WEP_ON;
789                 else
790                         ireq->i_val = IEEE80211_WEP_MIXED;
791                 break;
792         case IEEE80211_IOC_WEPKEY:
793                 kid = (u_int) ireq->i_val;
794                 if (kid >= IEEE80211_WEP_NKID)
795                         return EINVAL;
796                 len = (u_int) vap->iv_nw_keys[kid].wk_keylen;
797                 /* NB: only root can read WEP keys */
798                 if (priv_check(curthread, PRIV_NET80211_GETKEY) == 0) {
799                         bcopy(vap->iv_nw_keys[kid].wk_key, tmpkey, len);
800                 } else {
801                         bzero(tmpkey, len);
802                 }
803                 ireq->i_len = len;
804                 error = copyout(tmpkey, ireq->i_data, len);
805                 break;
806         case IEEE80211_IOC_NUMWEPKEYS:
807                 ireq->i_val = IEEE80211_WEP_NKID;
808                 break;
809         case IEEE80211_IOC_WEPTXKEY:
810                 ireq->i_val = vap->iv_def_txkey;
811                 break;
812         case IEEE80211_IOC_AUTHMODE:
813                 if (vap->iv_flags & IEEE80211_F_WPA)
814                         ireq->i_val = IEEE80211_AUTH_WPA;
815                 else
816                         ireq->i_val = vap->iv_bss->ni_authmode;
817                 break;
818         case IEEE80211_IOC_CHANNEL:
819                 ireq->i_val = ieee80211_chan2ieee(ic, ic->ic_curchan);
820                 break;
821         case IEEE80211_IOC_POWERSAVE:
822                 if (vap->iv_flags & IEEE80211_F_PMGTON)
823                         ireq->i_val = IEEE80211_POWERSAVE_ON;
824                 else
825                         ireq->i_val = IEEE80211_POWERSAVE_OFF;
826                 break;
827         case IEEE80211_IOC_POWERSAVESLEEP:
828                 ireq->i_val = ic->ic_lintval;
829                 break;
830         case IEEE80211_IOC_RTSTHRESHOLD:
831                 ireq->i_val = vap->iv_rtsthreshold;
832                 break;
833         case IEEE80211_IOC_PROTMODE:
834                 ireq->i_val = ic->ic_protmode;
835                 break;
836         case IEEE80211_IOC_TXPOWER:
837                 /*
838                  * Tx power limit is the min of max regulatory
839                  * power, any user-set limit, and the max the
840                  * radio can do.
841                  */
842                 ireq->i_val = 2*ic->ic_curchan->ic_maxregpower;
843                 if (ireq->i_val > ic->ic_txpowlimit)
844                         ireq->i_val = ic->ic_txpowlimit;
845                 if (ireq->i_val > ic->ic_curchan->ic_maxpower)
846                         ireq->i_val = ic->ic_curchan->ic_maxpower;
847                 break;
848         case IEEE80211_IOC_WPA:
849                 switch (vap->iv_flags & IEEE80211_F_WPA) {
850                 case IEEE80211_F_WPA1:
851                         ireq->i_val = 1;
852                         break;
853                 case IEEE80211_F_WPA2:
854                         ireq->i_val = 2;
855                         break;
856                 case IEEE80211_F_WPA1 | IEEE80211_F_WPA2:
857                         ireq->i_val = 3;
858                         break;
859                 default:
860                         ireq->i_val = 0;
861                         break;
862                 }
863                 break;
864         case IEEE80211_IOC_CHANLIST:
865                 error = ieee80211_ioctl_getchanlist(vap, ireq);
866                 break;
867         case IEEE80211_IOC_ROAMING:
868                 ireq->i_val = vap->iv_roaming;
869                 break;
870         case IEEE80211_IOC_PRIVACY:
871                 ireq->i_val = (vap->iv_flags & IEEE80211_F_PRIVACY) != 0;
872                 break;
873         case IEEE80211_IOC_DROPUNENCRYPTED:
874                 ireq->i_val = (vap->iv_flags & IEEE80211_F_DROPUNENC) != 0;
875                 break;
876         case IEEE80211_IOC_COUNTERMEASURES:
877                 ireq->i_val = (vap->iv_flags & IEEE80211_F_COUNTERM) != 0;
878                 break;
879         case IEEE80211_IOC_WME:
880                 ireq->i_val = (vap->iv_flags & IEEE80211_F_WME) != 0;
881                 break;
882         case IEEE80211_IOC_HIDESSID:
883                 ireq->i_val = (vap->iv_flags & IEEE80211_F_HIDESSID) != 0;
884                 break;
885         case IEEE80211_IOC_APBRIDGE:
886                 ireq->i_val = (vap->iv_flags & IEEE80211_F_NOBRIDGE) == 0;
887                 break;
888         case IEEE80211_IOC_WPAKEY:
889                 error = ieee80211_ioctl_getkey(vap, ireq);
890                 break;
891         case IEEE80211_IOC_CHANINFO:
892                 error = ieee80211_ioctl_getchaninfo(