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

Cache object: 8681bb83f804d59610445a86073a288b


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