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

Cache object: 0096ab3465a5946b830e00674ee00b48


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