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

Cache object: b65afb5c6be7139a7b10bff62d1efcc0


[ 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.