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

Cache object: a3a043c6af4df8ab9ed0cc04cd955d57


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