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

Cache object: c6996f6d14a563604f8d005a48bad647


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