The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

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

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  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  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: f020c87aaf82c9364aa254fbf59099ec


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.