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.18 2005/02/26 22:45:09 perry Exp $       */
    2 /*-
    3  * Copyright (c) 2001 Atsushi Onoe
    4  * Copyright (c) 2002, 2003 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.13 2004/03/30 22:57:57 sam Exp $");
   37 #else
   38 __KERNEL_RCSID(0, "$NetBSD: ieee80211_ioctl.c,v 1.18 2005/02/26 22:45:09 perry Exp $");
   39 #endif
   40 
   41 /*
   42  * IEEE 802.11 ioctl support (FreeBSD-specific)
   43  */
   44 
   45 #include "opt_inet.h"
   46 
   47 #include <sys/endian.h>
   48 #include <sys/param.h>
   49 #include <sys/kernel.h>
   50 #include <sys/socket.h>
   51 #include <sys/sockio.h>
   52 #include <sys/systm.h>
   53 #include <sys/proc.h>
   54 
   55 #include <net/if.h>
   56 #include <net/if_arp.h>
   57 #include <net/if_media.h>
   58 #ifdef __FreeBSD__
   59 #include <net/ethernet.h>
   60 #else
   61 #include <net/if_ether.h>
   62 #endif
   63 
   64 #ifdef INET
   65 #include <netinet/in.h>
   66 #ifdef __FreeBSD__
   67 #include <netinet/if_ether.h>
   68 #endif /* __FreeBSD__ */
   69 #include <netinet/if_inarp.h>
   70 #endif
   71 
   72 #include <net80211/ieee80211_var.h>
   73 #include <net80211/ieee80211_ioctl.h>
   74 
   75 #ifdef __FreeBSD__
   76 #include <dev/wi/if_wavelan_ieee.h>
   77 #else
   78 #include <dev/ic/wi_ieee.h>
   79 #endif
   80 
   81 /*
   82  * XXX
   83  * Wireless LAN specific configuration interface, which is compatible
   84  * with wicontrol(8).
   85  */
   86 
   87 int
   88 ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data)
   89 {
   90         struct ieee80211com *ic = (void *)ifp;
   91         int i, j, error;
   92         struct ifreq *ifr = (struct ifreq *)data;
   93         struct wi_req wreq;
   94         struct wi_ltv_keys *keys;
   95         struct wi_apinfo *ap;
   96         struct ieee80211_node *ni;
   97         struct ieee80211_rateset *rs;
   98 #ifdef WICACHE
   99         struct wi_sigcache wsc;
  100 #endif /* WICACHE */
  101 #if 0 /* TBD */
  102         struct wi_scan_p2_hdr *p2;
  103         struct wi_scan_res *res;
  104 #endif
  105 
  106         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
  107         if (error)
  108                 return error;
  109         wreq.wi_len = 0;
  110         switch (wreq.wi_type) {
  111         case WI_RID_SERIALNO:
  112         case WI_RID_STA_IDENTITY:
  113                 /* nothing appropriate */
  114                 break;
  115         case WI_RID_NODENAME:
  116                 strlcpy((char *)&wreq.wi_val[1], hostname,
  117                     sizeof(wreq.wi_val) - sizeof(wreq.wi_val[0]));
  118                 wreq.wi_val[0] = htole16(strlen(hostname));
  119                 wreq.wi_len = (1 + strlen(hostname) + 1) / 2;
  120                 break;
  121         case WI_RID_CURRENT_SSID:
  122                 if (ic->ic_state != IEEE80211_S_RUN) {
  123                         wreq.wi_val[0] = 0;
  124                         wreq.wi_len = 1;
  125                         break;
  126                 }
  127                 wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen);
  128                 memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid,
  129                     ic->ic_bss->ni_esslen);
  130                 wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
  131                 break;
  132         case WI_RID_OWN_SSID:
  133         case WI_RID_DESIRED_SSID:
  134                 wreq.wi_val[0] = htole16(ic->ic_des_esslen);
  135                 memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
  136                 wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2;
  137                 break;
  138         case WI_RID_CURRENT_BSSID:
  139                 if (ic->ic_state == IEEE80211_S_RUN)
  140                         IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid);
  141                 else
  142                         memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN);
  143                 wreq.wi_len = IEEE80211_ADDR_LEN / 2;
  144                 break;
  145         case WI_RID_CHANNEL_LIST:
  146                 memset(wreq.wi_val, 0, sizeof(wreq.wi_val));
  147                 /*
  148                  * Since channel 0 is not available for DS, channel 1
  149                  * is assigned to LSB on WaveLAN.
  150                  */
  151                 if (ic->ic_phytype == IEEE80211_T_DS)
  152                         i = 1;
  153                 else
  154                         i = 0;
  155                 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
  156                         if (isset(ic->ic_chan_active, i)) {
  157                                 setbit((u_int8_t *)wreq.wi_val, j);
  158                                 wreq.wi_len = j / 16 + 1;
  159                         }
  160                 break;
  161         case WI_RID_OWN_CHNL:
  162                 wreq.wi_val[0] = htole16(
  163                         ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
  164                 wreq.wi_len = 1;
  165                 break;
  166         case WI_RID_CURRENT_CHAN:
  167                 wreq.wi_val[0] = htole16(
  168                         ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
  169                 wreq.wi_len = 1;
  170                 break;
  171         case WI_RID_COMMS_QUALITY:
  172                 wreq.wi_val[0] = 0;                             /* quality */
  173                 wreq.wi_val[1] =
  174                         htole16((*ic->ic_node_getrssi)(ic, ic->ic_bss));
  175                 wreq.wi_val[2] = 0;                             /* noise */
  176                 wreq.wi_len = 3;
  177                 break;
  178         case WI_RID_PROMISC:
  179                 wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
  180                 wreq.wi_len = 1;
  181                 break;
  182         case WI_RID_PORTTYPE:
  183                 wreq.wi_val[0] = htole16(ic->ic_opmode);
  184                 wreq.wi_len = 1;
  185                 break;
  186         case WI_RID_MAC_NODE:
  187                 IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr);
  188                 wreq.wi_len = IEEE80211_ADDR_LEN / 2;
  189                 break;
  190         case WI_RID_TX_RATE:
  191                 if (ic->ic_fixed_rate == -1)
  192                         wreq.wi_val[0] = 0;     /* auto */
  193                 else
  194                         wreq.wi_val[0] = htole16(
  195                             (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
  196                             IEEE80211_RATE_VAL) / 2);
  197                 wreq.wi_len = 1;
  198                 break;
  199         case WI_RID_CUR_TX_RATE:
  200                 wreq.wi_val[0] = htole16(
  201                     (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
  202                     IEEE80211_RATE_VAL) / 2);
  203                 wreq.wi_len = 1;
  204                 break;
  205         case WI_RID_FRAG_THRESH:
  206                 wreq.wi_val[0] = htole16(ic->ic_fragthreshold);
  207                 wreq.wi_len = 1;
  208                 break;
  209         case WI_RID_RTS_THRESH:
  210                 wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
  211                 wreq.wi_len = 1;
  212                 break;
  213         case WI_RID_CREATE_IBSS:
  214                 wreq.wi_val[0] =
  215                     htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
  216                 wreq.wi_len = 1;
  217                 break;
  218         case WI_RID_MICROWAVE_OVEN:
  219                 wreq.wi_val[0] = 0;     /* no ... not supported */
  220                 wreq.wi_len = 1;
  221                 break;
  222         case WI_RID_ROAMING_MODE:
  223                 wreq.wi_val[0] = htole16(1);    /* enabled ... not supported */
  224                 wreq.wi_len = 1;
  225                 break;
  226         case WI_RID_SYSTEM_SCALE:
  227                 wreq.wi_val[0] = htole16(1);    /* low density ... not supp */
  228                 wreq.wi_len = 1;
  229                 break;
  230         case WI_RID_PM_ENABLED:
  231                 wreq.wi_val[0] =
  232                     htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
  233                 wreq.wi_len = 1;
  234                 break;
  235         case WI_RID_MAX_SLEEP:
  236                 wreq.wi_val[0] = htole16(ic->ic_lintval);
  237                 wreq.wi_len = 1;
  238                 break;
  239         case WI_RID_CUR_BEACON_INT:
  240                 wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
  241                 wreq.wi_len = 1;
  242                 break;
  243         case WI_RID_WEP_AVAIL:
  244                 wreq.wi_val[0] =
  245                     htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0);
  246                 wreq.wi_len = 1;
  247                 break;
  248         case WI_RID_CNFAUTHMODE:
  249                 wreq.wi_val[0] = htole16(1);    /* TODO: open system only */
  250                 wreq.wi_len = 1;
  251                 break;
  252         case WI_RID_ENCRYPTION:
  253                 wreq.wi_val[0] =
  254                     htole16((ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0);
  255                 wreq.wi_len = 1;
  256                 break;
  257         case WI_RID_TX_CRYPT_KEY:
  258                 wreq.wi_val[0] = htole16(ic->ic_wep_txkey);
  259                 wreq.wi_len = 1;
  260                 break;
  261         case WI_RID_DEFLT_CRYPT_KEYS:
  262                 keys = (struct wi_ltv_keys *)&wreq;
  263                 /* do not show keys to non-root user */
  264                 error = suser(curproc->p_ucred, &curproc->p_acflag);
  265                 if (error) {
  266                         memset(keys, 0, sizeof(*keys));
  267                         error = 0;
  268                         break;
  269                 }
  270                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
  271                         keys->wi_keys[i].wi_keylen =
  272                             htole16(ic->ic_nw_keys[i].wk_len);
  273                         memcpy(keys->wi_keys[i].wi_keydat,
  274                             ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len);
  275                 }
  276                 wreq.wi_len = sizeof(*keys) / 2;
  277                 break;
  278         case WI_RID_MAX_DATALEN:
  279                 wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN);    /* TODO: frag */
  280                 wreq.wi_len = 1;
  281                 break;
  282         case WI_RID_DBM_ADJUST:
  283                 /* not supported, we just pass rssi value from driver. */
  284                 break;
  285         case WI_RID_IFACE_STATS:
  286                 /* XXX: should be implemented in lower drivers */
  287                 break;
  288         case WI_RID_READ_APS:
  289                 if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
  290                         /*
  291                          * Don't return results until active scan completes.
  292                          */
  293                         if (ic->ic_state == IEEE80211_S_SCAN &&
  294                             (ic->ic_flags & IEEE80211_F_ASCAN)) {
  295                                 error = EINPROGRESS;
  296                                 break;
  297                         }
  298                 }
  299                 i = 0;
  300                 ap = (void *)((char *)wreq.wi_val + sizeof(i));
  301                 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
  302                         if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1))
  303                                 break;
  304                         memset(ap, 0, sizeof(*ap));
  305                         if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
  306                                 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
  307                                 ap->namelen = ic->ic_des_esslen;
  308                                 if (ic->ic_des_esslen)
  309                                         memcpy(ap->name, ic->ic_des_essid,
  310                                             ic->ic_des_esslen);
  311                         } else {
  312                                 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
  313                                 ap->namelen = ni->ni_esslen;
  314                                 if (ni->ni_esslen)
  315                                         memcpy(ap->name, ni->ni_essid,
  316                                             ni->ni_esslen);
  317                         }
  318                         ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
  319                         ap->signal = (*ic->ic_node_getrssi)(ic, ni);
  320                         ap->capinfo = ni->ni_capinfo;
  321                         ap->interval = ni->ni_intval;
  322                         rs = &ni->ni_rates;
  323                         for (j = 0; j < rs->rs_nrates; j++) {
  324                                 if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
  325                                         ap->rate = (rs->rs_rates[j] &
  326                                             IEEE80211_RATE_VAL) * 5; /* XXX */
  327                                 }
  328                         }
  329                         i++;
  330                         ap++;
  331                 }
  332                 memcpy(wreq.wi_val, &i, sizeof(i));
  333                 wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2;
  334                 break;
  335 #if 0
  336         case WI_RID_PRISM2:
  337                 wreq.wi_val[0] = 1;     /* XXX lie so SCAN_RES can give rates */
  338                 wreq.wi_len = sizeof(u_int16_t) / 2;
  339                 break;
  340         case WI_RID_SCAN_RES:                   /* compatibility interface */
  341                 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
  342                     ic->ic_state == IEEE80211_S_SCAN &&
  343                     (ic->ic_flags & IEEE80211_F_ASCAN)) {
  344                         error = EINPROGRESS;
  345                         break;
  346                 }
  347                 /* NB: we use the Prism2 format so we can return rate info */
  348                 p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
  349                 res = (void *)&p2[1];
  350                 i = 0;
  351                 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
  352                         if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1))
  353                                 break;
  354                         res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
  355                         res->wi_noise = 0;
  356                         res->wi_signal = (*ic->ic_node_getrssi)(ic, ni);
  357                         IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
  358                         res->wi_interval = ni->ni_intval;
  359                         res->wi_capinfo = ni->ni_capinfo;
  360                         res->wi_ssid_len = ni->ni_esslen;
  361                         memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
  362                         /* NB: assumes wi_srates holds <= ni->ni_rates */
  363                         memcpy(res->wi_srates, ni->ni_rates.rs_rates,
  364                                 sizeof(res->wi_srates));
  365                         if (ni->ni_rates.rs_nrates < 10)
  366                                 res->wi_srates[ni->ni_rates.rs_nrates] = 0;
  367                         res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
  368                         res->wi_rsvd = 0;
  369                         res++, i++;
  370                 }
  371                 p2->wi_rsvd = 0;
  372                 p2->wi_reason = i;
  373                 wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2;
  374                 break;
  375 #endif /* 0 */
  376 #ifdef WICACHE
  377         case WI_RID_READ_CACHE:
  378                 i = 0;
  379                 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
  380                         if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1)
  381                                 break;
  382                         IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr);
  383                         memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc));
  384                         wsc.signal = (*ic->ic_node_getrssi)(ic, ni);
  385                         wsc.noise = 0;
  386                         wsc.quality = 0;
  387                         memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
  388                             &wsc, sizeof(wsc));
  389                         i++;
  390                 }
  391                 wreq.wi_len = sizeof(wsc) * i / 2;
  392                 break;
  393 #endif /* WICACHE */
  394         case WI_RID_SCAN_APS:
  395                 error = EINVAL;
  396                 break;
  397         default:
  398                 error = EINVAL;
  399                 break;
  400         }
  401         if (error == 0) {
  402                 wreq.wi_len++;
  403                 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
  404         }
  405         return error;
  406 }
  407 
  408 static int
  409 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
  410 {
  411 #define IEEERATE(_ic,_m,_i) \
  412         ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
  413         int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
  414         for (i = 0; i < nrates; i++)
  415                 if (IEEERATE(ic, mode, i) == rate)
  416                         return i;
  417         return -1;
  418 #undef IEEERATE
  419 }
  420 
  421 /*
  422  * Prepare to do a user-initiated scan for AP's.  If no
  423  * current/default channel is setup or the current channel
  424  * is invalid then pick the first available channel from
  425  * the active list as the place to start the scan.
  426  */
  427 static int
  428 ieee80211_setupscan(struct ieee80211com *ic)
  429 {
  430         u_char *chanlist = ic->ic_chan_active;
  431         int i;
  432 
  433         if (ic->ic_ibss_chan == NULL ||
  434             isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
  435                 for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
  436                         if (isset(chanlist, i)) {
  437                                 ic->ic_ibss_chan = &ic->ic_channels[i];
  438                                 goto found;
  439                         }
  440                 return EINVAL;                  /* no active channels */
  441 found:
  442                 ;
  443         }
  444         if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
  445             isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
  446                 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
  447         /*
  448          * XXX don't permit a scan to be started unless we
  449          * know the device is ready.  For the moment this means
  450          * the device is marked up as this is the required to
  451          * initialize the hardware.  It would be better to permit
  452          * scanning prior to being up but that'll require some
  453          * changes to the infrastructure.
  454          */
  455         return (ic->ic_if.if_flags & IFF_UP) ? 0 : ENETRESET;
  456 }
  457 
  458 int
  459 ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data)
  460 {
  461         struct ieee80211com *ic = (void *)ifp;
  462         int i, j, len, error, rate;
  463         struct ifreq *ifr = (struct ifreq *)data;
  464         struct wi_ltv_keys *keys;
  465         struct wi_req wreq;
  466         u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
  467 
  468         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
  469         if (error)
  470                 return error;
  471         len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
  472         switch (wreq.wi_type) {
  473         case WI_RID_SERIALNO:
  474         case WI_RID_NODENAME:
  475                 return EPERM;
  476         case WI_RID_CURRENT_SSID:
  477                 return EPERM;
  478         case WI_RID_OWN_SSID:
  479         case WI_RID_DESIRED_SSID:
  480                 if (le16toh(wreq.wi_val[0]) * 2 > len ||
  481                     le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
  482                         error = ENOSPC;
  483                         break;
  484                 }
  485                 memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
  486                 ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
  487                 memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
  488                 error = ENETRESET;
  489                 break;
  490         case WI_RID_CURRENT_BSSID:
  491                 return EPERM;
  492         case WI_RID_OWN_CHNL:
  493                 if (len != 2)
  494                         return EINVAL;
  495                 i = le16toh(wreq.wi_val[0]);
  496                 if (i < 0 ||
  497                     i > IEEE80211_CHAN_MAX ||
  498                     isclr(ic->ic_chan_active, i))
  499                         return EINVAL;
  500                 ic->ic_ibss_chan = &ic->ic_channels[i];
  501                 if (ic->ic_flags & IEEE80211_F_SIBSS)
  502                         error = ENETRESET;
  503                 break;
  504         case WI_RID_CURRENT_CHAN:
  505                 return EPERM;
  506         case WI_RID_COMMS_QUALITY:
  507                 return EPERM;
  508         case WI_RID_PROMISC:
  509                 if (len != 2)
  510                         return EINVAL;
  511                 if (ifp->if_flags & IFF_PROMISC) {
  512                         if (wreq.wi_val[0] == 0) {
  513                                 ifp->if_flags &= ~IFF_PROMISC;
  514                                 error = ENETRESET;
  515                         }
  516                 } else {
  517                         if (wreq.wi_val[0] != 0) {
  518                                 ifp->if_flags |= IFF_PROMISC;
  519                                 error = ENETRESET;
  520                         }
  521                 }
  522                 break;
  523         case WI_RID_PORTTYPE:
  524                 if (len != 2)
  525                         return EINVAL;
  526                 switch (le16toh(wreq.wi_val[0])) {
  527                 case IEEE80211_M_STA:
  528                         break;
  529                 case IEEE80211_M_IBSS:
  530                         if (!(ic->ic_caps & IEEE80211_C_IBSS))
  531                                 return EINVAL;
  532                         break;
  533                 case IEEE80211_M_AHDEMO:
  534                         if (ic->ic_phytype != IEEE80211_T_DS ||
  535                             !(ic->ic_caps & IEEE80211_C_AHDEMO))
  536                                 return EINVAL;
  537                         break;
  538                 case IEEE80211_M_HOSTAP:
  539                         if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
  540                                 return EINVAL;
  541                         break;
  542                 default:
  543                         return EINVAL;
  544                 }
  545                 if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
  546                         ic->ic_opmode = le16toh(wreq.wi_val[0]);
  547                         error = ENETRESET;
  548                 }
  549                 break;
  550 #if 0
  551         case WI_RID_MAC_NODE:
  552                 if (len != IEEE80211_ADDR_LEN)
  553                         return EINVAL;
  554                 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
  555                 /* if_init will copy lladdr into ic_myaddr */
  556                 error = ENETRESET;
  557                 break;
  558 #endif
  559         case WI_RID_TX_RATE:
  560                 if (len != 2)
  561                         return EINVAL;
  562                 if (wreq.wi_val[0] == 0) {
  563                         /* auto */
  564                         ic->ic_fixed_rate = -1;
  565                         break;
  566                 }
  567                 rate = 2 * le16toh(wreq.wi_val[0]);
  568                 if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
  569                         /*
  570                          * In autoselect mode search for the rate.  We take
  571                          * the first instance which may not be right, but we
  572                          * are limited by the interface.  Note that we also
  573                          * lock the mode to insure the rate is meaningful
  574                          * when it is used.
  575                          */
  576                         for (j = IEEE80211_MODE_11A;
  577                              j < IEEE80211_MODE_MAX; j++) {
  578                                 if ((ic->ic_modecaps & (1<<j)) == 0)
  579                                         continue;
  580                                 i = findrate(ic, j, rate);
  581                                 if (i != -1) {
  582                                         /* lock mode too */
  583                                         ic->ic_curmode = j;
  584                                         goto setrate;
  585                                 }
  586                         }
  587                 } else {
  588                         i = findrate(ic, ic->ic_curmode, rate);
  589                         if (i != -1)
  590                                 goto setrate;
  591                 }
  592                 return EINVAL;
  593         setrate:
  594                 ic->ic_fixed_rate = i;
  595                 error = ENETRESET;
  596                 break;
  597         case WI_RID_CUR_TX_RATE:
  598                 return EPERM;
  599         case WI_RID_FRAG_THRESH:
  600                 if (len != 2)
  601                         return EINVAL;
  602                 ic->ic_fragthreshold = le16toh(wreq.wi_val[0]);
  603                 error = ENETRESET;
  604                 break;
  605         case WI_RID_RTS_THRESH:
  606                 if (len != 2)
  607                         return EINVAL;
  608                 ic->ic_rtsthreshold = le16toh(wreq.wi_val[0]);
  609                 error = ENETRESET;
  610                 break;
  611         case WI_RID_CREATE_IBSS:
  612                 if (len != 2)
  613                         return EINVAL;
  614                 if (wreq.wi_val[0] != 0) {
  615                         if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
  616                                 return EINVAL;
  617                         if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
  618                                 ic->ic_flags |= IEEE80211_F_IBSSON;
  619                                 if (ic->ic_opmode == IEEE80211_M_IBSS &&
  620                                     ic->ic_state == IEEE80211_S_SCAN)
  621                                         error = ENETRESET;
  622                         }
  623                 } else {
  624                         if (ic->ic_flags & IEEE80211_F_IBSSON) {
  625                                 ic->ic_flags &= ~IEEE80211_F_IBSSON;
  626                                 if (ic->ic_flags & IEEE80211_F_SIBSS) {
  627                                         ic->ic_flags &= ~IEEE80211_F_SIBSS;
  628                                         error = ENETRESET;
  629                                 }
  630                         }
  631                 }
  632                 break;
  633         case WI_RID_MICROWAVE_OVEN:
  634                 if (len != 2)
  635                         return EINVAL;
  636                 if (wreq.wi_val[0] != 0)
  637                         return EINVAL;          /* not supported */
  638                 break;
  639         case WI_RID_ROAMING_MODE:
  640                 if (len != 2)
  641                         return EINVAL;
  642                 if (le16toh(wreq.wi_val[0]) != 1)
  643                         return EINVAL;          /* not supported */
  644                 break;
  645         case WI_RID_SYSTEM_SCALE:
  646                 if (len != 2)
  647                         return EINVAL;
  648                 if (le16toh(wreq.wi_val[0]) != 1)
  649                         return EINVAL;          /* not supported */
  650                 break;
  651         case WI_RID_PM_ENABLED:
  652                 if (len != 2)
  653                         return EINVAL;
  654                 if (wreq.wi_val[0] != 0) {
  655                         if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
  656                                 return EINVAL;
  657                         if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
  658                                 ic->ic_flags |= IEEE80211_F_PMGTON;
  659                                 error = ENETRESET;
  660                         }
  661                 } else {
  662                         if (ic->ic_flags & IEEE80211_F_PMGTON) {
  663                                 ic->ic_flags &= ~IEEE80211_F_PMGTON;
  664                                 error = ENETRESET;
  665                         }
  666                 }
  667                 break;
  668         case WI_RID_MAX_SLEEP:
  669                 if (len != 2)
  670                         return EINVAL;
  671                 ic->ic_lintval = le16toh(wreq.wi_val[0]);
  672                 if (ic->ic_flags & IEEE80211_F_PMGTON)
  673                         error = ENETRESET;
  674                 break;
  675         case WI_RID_CUR_BEACON_INT:
  676                 return EPERM;
  677         case WI_RID_WEP_AVAIL:
  678                 return EPERM;
  679         case WI_RID_CNFAUTHMODE:
  680                 if (len != 2)
  681                         return EINVAL;
  682                 if (le16toh(wreq.wi_val[0]) != 1)
  683                         return EINVAL;          /* TODO: shared key auth */
  684                 break;
  685         case WI_RID_ENCRYPTION:
  686                 if (len != 2)
  687                         return EINVAL;
  688                 if (wreq.wi_val[0] != 0) {
  689                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
  690                                 return EINVAL;
  691                         if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
  692                                 ic->ic_flags |= IEEE80211_F_PRIVACY;
  693                                 error = ENETRESET;
  694                         }
  695                 } else {
  696                         if (ic->ic_flags & IEEE80211_F_PRIVACY) {
  697                                 ic->ic_flags &= ~IEEE80211_F_PRIVACY;
  698                                 error = ENETRESET;
  699                         }
  700                 }
  701                 break;
  702         case WI_RID_TX_CRYPT_KEY:
  703                 if (len != 2)
  704                         return EINVAL;
  705                 i = le16toh(wreq.wi_val[0]);
  706                 if (i >= IEEE80211_WEP_NKID)
  707                         return EINVAL;
  708                 ic->ic_wep_txkey = i;
  709                 break;
  710         case WI_RID_DEFLT_CRYPT_KEYS:
  711                 if (len != sizeof(struct wi_ltv_keys))
  712                         return EINVAL;
  713                 keys = (struct wi_ltv_keys *)&wreq;
  714                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
  715                         len = le16toh(keys->wi_keys[i].wi_keylen);
  716                         if (len != 0 && len < IEEE80211_WEP_KEYLEN)
  717                                 return EINVAL;
  718                         if (len > sizeof(ic->ic_nw_keys[i].wk_key))
  719                                 return EINVAL;
  720                 }
  721                 memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys));
  722                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
  723                         len = le16toh(keys->wi_keys[i].wi_keylen);
  724                         ic->ic_nw_keys[i].wk_len = len;
  725                         memcpy(ic->ic_nw_keys[i].wk_key,
  726                             keys->wi_keys[i].wi_keydat, len);
  727                 }
  728                 error = ENETRESET;
  729                 break;
  730         case WI_RID_MAX_DATALEN:
  731                 if (len != 2)
  732                         return EINVAL;
  733                 len = le16toh(wreq.wi_val[0]);
  734                 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
  735                         return EINVAL;
  736                 if (len != IEEE80211_MAX_LEN)
  737                         return EINVAL;          /* TODO: fragment */
  738                 ic->ic_fragthreshold = len;
  739                 error = ENETRESET;
  740                 break;
  741         case WI_RID_IFACE_STATS:
  742                 error = EPERM;
  743                 break;
  744         case WI_RID_SCAN_REQ:                   /* XXX wicontrol */
  745                 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
  746                         break;
  747                 error = ieee80211_setupscan(ic);
  748                 if (error == 0)
  749                         error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
  750                 break;
  751         case WI_RID_SCAN_APS:
  752                 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
  753                         break;
  754                 len--;                  /* XXX: tx rate? */
  755                 /* FALLTHRU */
  756         case WI_RID_CHANNEL_LIST:
  757                 memset(chanlist, 0, sizeof(chanlist));
  758                 /*
  759                  * Since channel 0 is not available for DS, channel 1
  760                  * is assigned to LSB on WaveLAN.
  761                  */
  762                 if (ic->ic_phytype == IEEE80211_T_DS)
  763                         i = 1;
  764                 else
  765                         i = 0;
  766                 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
  767                         if ((j / 8) >= len)
  768                                 break;
  769                         if (isclr((u_int8_t *)wreq.wi_val, j))
  770                                 continue;
  771                         if (isclr(ic->ic_chan_active, i)) {
  772                                 if (wreq.wi_type != WI_RID_CHANNEL_LIST)
  773                                         continue;
  774                                 if (isclr(ic->ic_chan_avail, i))
  775                                         return EPERM;
  776                         }
  777                         setbit(chanlist, i);
  778                 }
  779                 memcpy(ic->ic_chan_active, chanlist,
  780                     sizeof(ic->ic_chan_active));
  781                 error = ieee80211_setupscan(ic);
  782                 if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
  783                         /* NB: ignore error from ieee80211_setupscan */
  784                         error = ENETRESET;
  785                 } else if (error == 0)
  786                         error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
  787                 break;
  788         default:
  789                 error = EINVAL;
  790                 break;
  791         }
  792         return error;
  793 }
  794 
  795 #ifdef __FreeBSD__
  796 int
  797 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  798 {
  799         struct ieee80211com *ic = (void *)ifp;
  800         int error = 0;
  801         u_int kid, len;
  802         struct ieee80211req *ireq;
  803         struct ifreq *ifr;
  804         u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
  805         char tmpssid[IEEE80211_NWID_LEN];
  806         struct ieee80211_channel *chan;
  807         struct ifaddr *ifa;                     /* XXX */
  808 
  809         switch (cmd) {
  810         case SIOCSIFMEDIA:
  811         case SIOCGIFMEDIA:
  812                 error = ifmedia_ioctl(ifp, (struct ifreq *) data,
  813                                 &ic->ic_media, cmd);
  814                 break;
  815         case SIOCG80211:
  816                 ireq = (struct ieee80211req *) data;
  817                 switch (ireq->i_type) {
  818                 case IEEE80211_IOC_SSID:
  819                         switch (ic->ic_state) {
  820                         case IEEE80211_S_INIT:
  821                         case IEEE80211_S_SCAN:
  822                                 ireq->i_len = ic->ic_des_esslen;
  823                                 memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
  824                                 break;
  825                         default:
  826                                 ireq->i_len = ic->ic_bss->ni_esslen;
  827                                 memcpy(tmpssid, ic->ic_bss->ni_essid,
  828                                         ireq->i_len);
  829                                 break;
  830                         }
  831                         error = copyout(tmpssid, ireq->i_data, ireq->i_len);
  832                         break;
  833                 case IEEE80211_IOC_NUMSSIDS:
  834                         ireq->i_val = 1;
  835                         break;
  836                 case IEEE80211_IOC_WEP:
  837                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
  838                                 ireq->i_val = IEEE80211_WEP_NOSUP;
  839                         } else {
  840                                 if (ic->ic_flags & IEEE80211_F_PRIVACY) {
  841                                         ireq->i_val =
  842                                             IEEE80211_WEP_MIXED;
  843                                 } else {
  844                                         ireq->i_val =
  845                                             IEEE80211_WEP_OFF;
  846                                 }
  847                         }
  848                         break;
  849                 case IEEE80211_IOC_WEPKEY:
  850                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
  851                                 error = EINVAL;
  852                                 break;
  853                         }
  854                         kid = (u_int) ireq->i_val;
  855                         if (kid >= IEEE80211_WEP_NKID) {
  856                                 error = EINVAL;
  857                                 break;
  858                         }
  859                         len = (u_int) ic->ic_nw_keys[kid].wk_len;
  860                         /* NB: only root can read WEP keys */
  861                         if (suser(curthread) == 0) {
  862                                 bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
  863                         } else {
  864                                 bzero(tmpkey, len);
  865                         }
  866                         ireq->i_len = len;
  867                         error = copyout(tmpkey, ireq->i_data, len);
  868                         break;
  869                 case IEEE80211_IOC_NUMWEPKEYS:
  870                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
  871                                 error = EINVAL;
  872                         else
  873                                 ireq->i_val = IEEE80211_WEP_NKID;
  874                         break;
  875                 case IEEE80211_IOC_WEPTXKEY:
  876                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
  877                                 error = EINVAL;
  878                         else
  879                                 ireq->i_val = ic->ic_wep_txkey;
  880                         break;
  881                 case IEEE80211_IOC_AUTHMODE:
  882                         ireq->i_val = IEEE80211_AUTH_OPEN;
  883                         break;
  884                 case IEEE80211_IOC_CHANNEL:
  885                         switch (ic->ic_state) {
  886                         case IEEE80211_S_INIT:
  887                         case IEEE80211_S_SCAN:
  888                                 if (ic->ic_opmode == IEEE80211_M_STA)
  889                                         chan = ic->ic_des_chan;
  890                                 else
  891                                         chan = ic->ic_ibss_chan;
  892                                 break;
  893                         default:
  894                                 chan = ic->ic_bss->ni_chan;
  895                                 break;
  896                         }
  897                         ireq->i_val = ieee80211_chan2ieee(ic, chan);
  898                         break;
  899                 case IEEE80211_IOC_POWERSAVE:
  900                         if (ic->ic_flags & IEEE80211_F_PMGTON)
  901                                 ireq->i_val = IEEE80211_POWERSAVE_ON;
  902                         else
  903                                 ireq->i_val = IEEE80211_POWERSAVE_OFF;
  904                         break;
  905                 case IEEE80211_IOC_POWERSAVESLEEP:
  906                         ireq->i_val = ic->ic_lintval;
  907                         break;
  908                 case IEEE80211_IOC_RTSTHRESHOLD:
  909                         ireq->i_val = ic->ic_rtsthreshold;
  910                         break;
  911                 case IEEE80211_IOC_PROTMODE:
  912                         ireq->i_val = ic->ic_protmode;
  913                         break;
  914                 case IEEE80211_IOC_TXPOWER:
  915                         if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
  916                                 error = EINVAL;
  917                         else
  918                                 ireq->i_val = ic->ic_txpower;
  919                         break;
  920                 default:
  921                         error = EINVAL;
  922                         break;
  923                 }
  924                 break;
  925         case SIOCS80211:
  926                 error = suser(curproc->p_ucred, &curproc->p_acflag);
  927                 if (error)
  928                         break;
  929                 ireq = (struct ieee80211req *) data;
  930                 switch (ireq->i_type) {
  931                 case IEEE80211_IOC_SSID:
  932                         if (ireq->i_val != 0 ||
  933                             ireq->i_len > IEEE80211_NWID_LEN) {
  934                                 error = EINVAL;
  935                                 break;
  936                         }
  937                         error = copyin(ireq->i_data, tmpssid, ireq->i_len);
  938                         if (error)
  939                                 break;
  940                         memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
  941                         ic->ic_des_esslen = ireq->i_len;
  942                         memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
  943                         error = ENETRESET;
  944                         break;
  945                 case IEEE80211_IOC_WEP:
  946                         /*
  947                          * These cards only support one mode so
  948                          * we just turn wep on if what ever is
  949                          * passed in is not OFF.
  950                          */
  951                         if (ireq->i_val == IEEE80211_WEP_OFF) {
  952                                 ic->ic_flags &= ~IEEE80211_F_PRIVACY;
  953                         } else {
  954                                 ic->ic_flags |= IEEE80211_F_PRIVACY;
  955                         }
  956                         error = ENETRESET;
  957                         break;
  958                 case IEEE80211_IOC_WEPKEY:
  959                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
  960                                 error = EINVAL;
  961                                 break;
  962                         }
  963                         kid = (u_int) ireq->i_val;
  964                         if (kid >= IEEE80211_WEP_NKID) {
  965                                 error = EINVAL;
  966                                 break;
  967                         }
  968                         if (ireq->i_len > sizeof(tmpkey)) {
  969                                 error = EINVAL;
  970                                 break;
  971                         }
  972                         memset(tmpkey, 0, sizeof(tmpkey));
  973                         error = copyin(ireq->i_data, tmpkey, ireq->i_len);
  974                         if (error)
  975                                 break;
  976                         memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey,
  977                                 sizeof(tmpkey));
  978                         ic->ic_nw_keys[kid].wk_len = ireq->i_len;
  979                         error = ENETRESET;
  980                         break;
  981                 case IEEE80211_IOC_WEPTXKEY:
  982                         kid = (u_int) ireq->i_val;
  983                         if (kid >= IEEE80211_WEP_NKID) {
  984                                 error = EINVAL;
  985                                 break;
  986                         }
  987                         ic->ic_wep_txkey = kid;
  988                         error = ENETRESET;
  989                         break;
  990 #if 0
  991                 case IEEE80211_IOC_AUTHMODE:
  992                         sc->wi_authmode = ireq->i_val;
  993                         break;
  994 #endif
  995                 case IEEE80211_IOC_CHANNEL:
  996                         /* XXX 0xffff overflows 16-bit signed */
  997                         if (ireq->i_val == 0 ||
  998                             ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
  999                                 ic->ic_des_chan = IEEE80211_CHAN_ANYC;
 1000                         else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
 1001                             isclr(ic->ic_chan_active, ireq->i_val)) {
 1002                                 error = EINVAL;
 1003                                 break;
 1004                         } else
 1005                                 ic->ic_ibss_chan = ic->ic_des_chan =
 1006                                         &ic->ic_channels[ireq->i_val];
 1007                         switch (ic->ic_state) {
 1008                         case IEEE80211_S_INIT:
 1009                         case IEEE80211_S_SCAN:
 1010                                 error = ENETRESET;
 1011                                 break;
 1012                         default:
 1013                                 if (ic->ic_opmode == IEEE80211_M_STA) {
 1014                                         if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
 1015                                             ic->ic_bss->ni_chan != ic->ic_des_chan)
 1016                                                 error = ENETRESET;
 1017                                 } else {
 1018                                         if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
 1019                                                 error = ENETRESET;
 1020                                 }
 1021                                 break;
 1022                         }
 1023                         break;
 1024                 case IEEE80211_IOC_POWERSAVE:
 1025                         switch (ireq->i_val) {
 1026                         case IEEE80211_POWERSAVE_OFF:
 1027                                 if (ic->ic_flags & IEEE80211_F_PMGTON) {
 1028                                         ic->ic_flags &= ~IEEE80211_F_PMGTON;
 1029                                         error = ENETRESET;
 1030                                 }
 1031                                 break;
 1032                         case IEEE80211_POWERSAVE_ON:
 1033                                 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
 1034                                         error = EINVAL;
 1035                                 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
 1036                                         ic->ic_flags |= IEEE80211_F_PMGTON;
 1037                                         error = ENETRESET;
 1038                                 }
 1039                                 break;
 1040                         default:
 1041                                 error = EINVAL;
 1042                                 break;
 1043                         }
 1044                         break;
 1045                 case IEEE80211_IOC_POWERSAVESLEEP:
 1046                         if (ireq->i_val < 0) {
 1047                                 error = EINVAL;
 1048                                 break;
 1049                         }
 1050                         ic->ic_lintval = ireq->i_val;
 1051                         error = ENETRESET;
 1052                         break;
 1053                 case IEEE80211_IOC_RTSTHRESHOLD:
 1054                         if (!(IEEE80211_RTS_MIN < ireq->i_val &&
 1055                               ireq->i_val <= IEEE80211_RTS_MAX + 1)) {
 1056                                 error = EINVAL;
 1057                                 break;
 1058                         }
 1059                         ic->ic_rtsthreshold = ireq->i_val;
 1060                         error = ENETRESET;
 1061                         break;
 1062                 case IEEE80211_IOC_PROTMODE:
 1063                         if (ireq->i_val > IEEE80211_PROT_RTSCTS) {
 1064                                 error = EINVAL;
 1065                                 break;
 1066                         }
 1067                         ic->ic_protmode = ireq->i_val;
 1068                         /* NB: if not operating in 11g this can wait */
 1069                         if (ic->ic_curmode == IEEE80211_MODE_11G)
 1070                                 error = ENETRESET;
 1071                         break;
 1072                 case IEEE80211_IOC_TXPOWER:
 1073                         if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
 1074                                 error = EINVAL;
 1075                                 break;
 1076                         }
 1077                         if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
 1078                               ireq->i_val < IEEE80211_TXPOWER_MAX)) {
 1079                                 error = EINVAL;
 1080                                 break;
 1081                         }
 1082                         ic->ic_txpower = ireq->i_val;
 1083                         error = ENETRESET;
 1084                         break;
 1085                 default:
 1086                         error = EINVAL;
 1087                         break;
 1088                 }
 1089                 break;
 1090         case SIOCGIFGENERIC:
 1091                 error = ieee80211_cfgget(ifp, cmd, data);
 1092                 break;
 1093         case SIOCSIFGENERIC:
 1094                 error = suser(curproc->p_ucred, &curproc->p_acflag);
 1095                 if (error)
 1096                         break;
 1097                 error = ieee80211_cfgset(ifp, cmd, data);
 1098                 break;
 1099         default:
 1100                 error = ether_ioctl(ifp, cmd, data);
 1101                 break;
 1102         }
 1103         return error;
 1104 }
 1105 #endif /* __FreeBSD__ */
 1106 
 1107 #ifdef __NetBSD__
 1108 int
 1109 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 1110 {
 1111         struct ieee80211com *ic = (void *)ifp;
 1112         struct ifreq *ifr = (struct ifreq *)data;
 1113         int i, error = 0, s;
 1114         struct ieee80211_nwid nwid;
 1115         struct ieee80211_nwkey *nwkey;
 1116         struct ieee80211_power *power;
 1117         struct ieee80211_bssid *bssid;
 1118         struct ieee80211chanreq *chanreq;
 1119         struct ieee80211_channel *chan;
 1120         struct ieee80211_wepkey keys[IEEE80211_WEP_NKID];
 1121         static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
 1122                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 1123         };
 1124 
 1125         switch (cmd) {
 1126         case SIOCSIFMEDIA:
 1127         case SIOCGIFMEDIA:
 1128                 error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
 1129                 break;
 1130         case SIOCS80211NWID:
 1131                 if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
 1132                         break;
 1133                 if (nwid.i_len > IEEE80211_NWID_LEN) {
 1134                         error = EINVAL;
 1135                         break;
 1136                 }
 1137                 memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
 1138                 ic->ic_des_esslen = nwid.i_len;
 1139                 memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
 1140                 error = ENETRESET;
 1141                 break;
 1142         case SIOCG80211NWID:
 1143                 memset(&nwid, 0, sizeof(nwid));
 1144                 switch (ic->ic_state) {
 1145                 case IEEE80211_S_INIT:
 1146                 case IEEE80211_S_SCAN:
 1147                         nwid.i_len = ic->ic_des_esslen;
 1148                         memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
 1149                         break;
 1150                 default:
 1151                         nwid.i_len = ic->ic_bss->ni_esslen;
 1152                         memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
 1153                         break;
 1154                 }
 1155                 error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
 1156                 break;
 1157         case SIOCS80211NWKEY:
 1158                 nwkey = (struct ieee80211_nwkey *)data;
 1159                 if ((ic->ic_caps & IEEE80211_C_WEP) == 0 &&
 1160                     nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
 1161                         error = EINVAL;
 1162                         break;
 1163                 }
 1164                 /* check and copy keys */
 1165                 memset(keys, 0, sizeof(keys));
 1166                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
 1167                         keys[i].wk_len = nwkey->i_key[i].i_keylen;
 1168                         if ((keys[i].wk_len > 0 &&
 1169                             keys[i].wk_len < IEEE80211_WEP_KEYLEN) ||
 1170                             keys[i].wk_len > sizeof(keys[i].wk_key)) {
 1171                                 error = EINVAL;
 1172                                 break;
 1173                         }
 1174                         if (keys[i].wk_len <= 0)
 1175                                 continue;
 1176                         if ((error = copyin(nwkey->i_key[i].i_keydat,
 1177                             keys[i].wk_key, keys[i].wk_len)) != 0)
 1178                                 break;
 1179                 }
 1180                 if (error)
 1181                         break;
 1182                 i = nwkey->i_defkid - 1;
 1183                 if (i < 0 || i >= IEEE80211_WEP_NKID ||
 1184                     keys[i].wk_len == 0 ||
 1185                     (keys[i].wk_len == -1 && ic->ic_nw_keys[i].wk_len == 0)) {
 1186                         if (nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
 1187                                 error = EINVAL;
 1188                                 break;
 1189                         }
 1190                 } else
 1191                         ic->ic_wep_txkey = i;
 1192                 /* save the key */
 1193                 if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN)
 1194                         ic->ic_flags &= ~IEEE80211_F_PRIVACY;
 1195                 else
 1196                         ic->ic_flags |= IEEE80211_F_PRIVACY;
 1197                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
 1198                         if (keys[i].wk_len < 0)
 1199                                 continue;
 1200                         ic->ic_nw_keys[i].wk_len = keys[i].wk_len;
 1201                         memcpy(ic->ic_nw_keys[i].wk_key, keys[i].wk_key,
 1202                             sizeof(keys[i].wk_key));
 1203                 }
 1204                 error = ENETRESET;
 1205                 break;
 1206         case SIOCG80211NWKEY:
 1207                 nwkey = (struct ieee80211_nwkey *)data;
 1208                 if (ic->ic_flags & IEEE80211_F_PRIVACY)
 1209                         nwkey->i_wepon = IEEE80211_NWKEY_WEP;
 1210                 else
 1211                         nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
 1212                 nwkey->i_defkid = ic->ic_wep_txkey + 1;
 1213                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
 1214                         if (nwkey->i_key[i].i_keydat == NULL)
 1215                                 continue;
 1216                         /* do not show any keys to non-root user */
 1217                         if ((error = suser(curproc->p_ucred,
 1218                             &curproc->p_acflag)) != 0)
 1219                                 break;
 1220                         nwkey->i_key[i].i_keylen = ic->ic_nw_keys[i].wk_len;
 1221                         if ((error = copyout(ic->ic_nw_keys[i].wk_key,
 1222                             nwkey->i_key[i].i_keydat,
 1223                             ic->ic_nw_keys[i].wk_len)) != 0)
 1224                                 break;
 1225                 }
 1226                 break;
 1227         case SIOCS80211POWER:
 1228                 power = (struct ieee80211_power *)data;
 1229                 ic->ic_lintval = power->i_maxsleep;
 1230                 if (power->i_enabled != 0) {
 1231                         if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
 1232                                 error = EINVAL;
 1233                         else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
 1234                                 ic->ic_flags |= IEEE80211_F_PMGTON;
 1235                                 error = ENETRESET;
 1236                         }
 1237                 } else {
 1238                         if (ic->ic_flags & IEEE80211_F_PMGTON) {
 1239                                 ic->ic_flags &= ~IEEE80211_F_PMGTON;
 1240                                 error = ENETRESET;
 1241                         }
 1242                 }
 1243                 break;
 1244         case SIOCG80211POWER:
 1245                 power = (struct ieee80211_power *)data;
 1246                 power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
 1247                 power->i_maxsleep = ic->ic_lintval;
 1248                 break;
 1249         case SIOCS80211BSSID:
 1250                 bssid = (struct ieee80211_bssid *)data;
 1251                 if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr))
 1252                         ic->ic_flags &= ~IEEE80211_F_DESBSSID;
 1253                 else {
 1254                         ic->ic_flags |= IEEE80211_F_DESBSSID;
 1255                         IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
 1256                 }
 1257                 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
 1258                         break;
 1259                 switch (ic->ic_state) {
 1260                 case IEEE80211_S_INIT:
 1261                 case IEEE80211_S_SCAN:
 1262                         error = ENETRESET;
 1263                         break;
 1264                 default:
 1265                         if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
 1266                             !IEEE80211_ADDR_EQ(ic->ic_des_bssid,
 1267                             ic->ic_bss->ni_bssid))
 1268                                 error = ENETRESET;
 1269                         break;
 1270                 }
 1271                 break;
 1272         case SIOCG80211BSSID:
 1273                 bssid = (struct ieee80211_bssid *)data;
 1274                 switch (ic->ic_state) {
 1275                 case IEEE80211_S_INIT:
 1276                 case IEEE80211_S_SCAN:
 1277                         if (ic->ic_opmode == IEEE80211_M_HOSTAP)
 1278                                 IEEE80211_ADDR_COPY(bssid->i_bssid,
 1279                                     ic->ic_myaddr);
 1280                         else if (ic->ic_flags & IEEE80211_F_DESBSSID)
 1281                                 IEEE80211_ADDR_COPY(bssid->i_bssid,
 1282                                     ic->ic_des_bssid);
 1283                         else
 1284                                 memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
 1285                         break;
 1286                 default:
 1287                         IEEE80211_ADDR_COPY(bssid->i_bssid,
 1288                             ic->ic_bss->ni_bssid);
 1289                         break;
 1290                 }
 1291                 break;
 1292         case SIOCS80211CHANNEL:
 1293                 chanreq = (struct ieee80211chanreq *)data;
 1294                 if (chanreq->i_channel == IEEE80211_CHAN_ANY)
 1295                         ic->ic_des_chan = IEEE80211_CHAN_ANYC;
 1296                 else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
 1297                     isclr(ic->ic_chan_active, chanreq->i_channel)) {
 1298                         error = EINVAL;
 1299                         break;
 1300                 } else
 1301                         ic->ic_ibss_chan = ic->ic_des_chan =
 1302                             &ic->ic_channels[chanreq->i_channel];
 1303                 switch (ic->ic_state) {
 1304                 case IEEE80211_S_INIT:
 1305                 case IEEE80211_S_SCAN:
 1306                         error = ENETRESET;
 1307                         break;
 1308                 default:
 1309                         if (ic->ic_opmode == IEEE80211_M_STA) {
 1310                                 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
 1311                                     ic->ic_bss->ni_chan != ic->ic_des_chan)
 1312                                         error = ENETRESET;
 1313                         } else {
 1314                                 if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
 1315                                         error = ENETRESET;
 1316                         }
 1317                         break;
 1318                 }
 1319                 break;
 1320         case SIOCG80211CHANNEL:
 1321                 chanreq = (struct ieee80211chanreq *)data;
 1322                 switch (ic->ic_state) {
 1323                 case IEEE80211_S_INIT:
 1324                 case IEEE80211_S_SCAN:
 1325                         if (ic->ic_opmode == IEEE80211_M_STA)
 1326                                 chan = ic->ic_des_chan;
 1327                         else
 1328                                 chan = ic->ic_ibss_chan;
 1329                         break;
 1330                 default:
 1331                         chan = ic->ic_bss->ni_chan;
 1332                         break;
 1333                 }
 1334                 chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
 1335                 break;
 1336         case SIOCGIFGENERIC:
 1337                 error = ieee80211_cfgget(ifp, cmd, data);
 1338                 break;
 1339         case SIOCSIFGENERIC:
 1340                 error = suser(curproc->p_ucred, &curproc->p_acflag);
 1341                 if (error)
 1342                         break;
 1343                 error = ieee80211_cfgset(ifp, cmd, data);
 1344                 break;
 1345         case SIOCG80211ZSTATS:
 1346         case SIOCG80211STATS:
 1347                 ifr = (struct ifreq *)data;
 1348                 s = splnet();
 1349                 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
 1350                 if (cmd == SIOCG80211ZSTATS)
 1351                         (void)memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
 1352                 splx(s);
 1353                 break;
 1354         case SIOCSIFMTU:
 1355                 ifr = (struct ifreq *)data;
 1356                 if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
 1357                     ifr->ifr_mtu <= IEEE80211_MTU_MAX))
 1358                         error = EINVAL;
 1359                 else
 1360                         ifp->if_mtu = ifr->ifr_mtu;
 1361                 break;
 1362         default:
 1363                 error = ether_ioctl(ifp, cmd, data);
 1364                 break;
 1365         }
 1366         return error;
 1367 }
 1368 #endif /* __NetBSD__ */

Cache object: aae8395d05a99cf16d25f166ec89344d


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