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

Cache object: 3817991e983cf1ef05c872aa7d9cf1e6


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