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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2001 Atsushi Onoe
    3  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * Alternatively, this software may be distributed under the terms of the
   18  * GNU General Public License ("GPL") version 2 as published by the Free
   19  * Software Foundation.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 /*
   37  * IEEE 802.11 ioctl support (FreeBSD-specific)
   38  */
   39 
   40 #include "opt_inet.h"
   41 #include "opt_ipx.h"
   42 
   43 #include <sys/endian.h>
   44 #include <sys/param.h>
   45 #include <sys/kernel.h>
   46 #include <sys/socket.h>
   47 #include <sys/sockio.h>
   48 #include <sys/systm.h>
   49  
   50 #include <net/if.h>
   51 #include <net/if_arp.h>
   52 #include <net/if_media.h>
   53 #include <net/ethernet.h>
   54 
   55 #ifdef INET
   56 #include <netinet/in.h>
   57 #include <netinet/if_ether.h>
   58 #endif
   59 
   60 #ifdef IPX
   61 #include <netipx/ipx.h>
   62 #include <netipx/ipx_if.h>
   63 #endif
   64 
   65 #include <net80211/ieee80211_var.h>
   66 #include <net80211/ieee80211_ioctl.h>
   67 
   68 #include <dev/wi/if_wavelan_ieee.h>
   69 
   70 /*
   71  * XXX
   72  * Wireless LAN specific configuration interface, which is compatible
   73  * with wicontrol(8).
   74  */
   75 
   76 int
   77 ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data)
   78 {
   79         struct ieee80211com *ic = (void *)ifp;
   80         int i, j, error;
   81         struct ifreq *ifr = (struct ifreq *)data;
   82         struct wi_req wreq;
   83         struct wi_ltv_keys *keys;
   84         struct wi_apinfo *ap;
   85         struct ieee80211_node *ni;
   86         struct ieee80211_rateset *rs;
   87         struct wi_sigcache wsc;
   88         struct wi_scan_p2_hdr *p2;
   89         struct wi_scan_res *res;
   90 
   91         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
   92         if (error)
   93                 return error;
   94         wreq.wi_len = 0;
   95         switch (wreq.wi_type) {
   96         case WI_RID_SERIALNO:
   97                 /* nothing appropriate */
   98                 break;
   99         case WI_RID_NODENAME:
  100                 strcpy((char *)&wreq.wi_val[1], hostname);
  101                 wreq.wi_val[0] = htole16(strlen(hostname));
  102                 wreq.wi_len = (1 + strlen(hostname) + 1) / 2;
  103                 break;
  104         case WI_RID_CURRENT_SSID:
  105                 if (ic->ic_state != IEEE80211_S_RUN) {
  106                         wreq.wi_val[0] = 0;
  107                         wreq.wi_len = 1;
  108                         break;
  109                 }
  110                 wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen);
  111                 memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid,
  112                     ic->ic_bss->ni_esslen);
  113                 wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
  114                 break;
  115         case WI_RID_OWN_SSID:
  116         case WI_RID_DESIRED_SSID:
  117                 wreq.wi_val[0] = htole16(ic->ic_des_esslen);
  118                 memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
  119                 wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2;
  120                 break;
  121         case WI_RID_CURRENT_BSSID:
  122                 if (ic->ic_state == IEEE80211_S_RUN)
  123                         IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid);
  124                 else
  125                         memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN);
  126                 wreq.wi_len = IEEE80211_ADDR_LEN / 2;
  127                 break;
  128         case WI_RID_CHANNEL_LIST:
  129                 memset(wreq.wi_val, 0, sizeof(wreq.wi_val));
  130                 /*
  131                  * Since channel 0 is not available for DS, channel 1
  132                  * is assigned to LSB on WaveLAN.
  133                  */
  134                 if (ic->ic_phytype == IEEE80211_T_DS)
  135                         i = 1;
  136                 else
  137                         i = 0;
  138                 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
  139                         if (isset(ic->ic_chan_active, i)) {
  140                                 setbit((u_int8_t *)wreq.wi_val, j);
  141                                 wreq.wi_len = j / 16 + 1;
  142                         }
  143                 break;
  144         case WI_RID_OWN_CHNL:
  145                 wreq.wi_val[0] = htole16(
  146                         ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
  147                 wreq.wi_len = 1;
  148                 break;
  149         case WI_RID_CURRENT_CHAN:
  150                 wreq.wi_val[0] = htole16(
  151                         ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
  152                 wreq.wi_len = 1;
  153                 break;
  154         case WI_RID_COMMS_QUALITY:
  155                 wreq.wi_val[0] = 0;                             /* quality */
  156                 wreq.wi_val[1] =
  157                         htole16((*ic->ic_node_getrssi)(ic, ic->ic_bss));
  158                 wreq.wi_val[2] = 0;                             /* noise */
  159                 wreq.wi_len = 3;
  160                 break;
  161         case WI_RID_PROMISC:
  162                 wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
  163                 wreq.wi_len = 1;
  164                 break;
  165         case WI_RID_PORTTYPE:
  166                 wreq.wi_val[0] = htole16(ic->ic_opmode);
  167                 wreq.wi_len = 1;
  168                 break;
  169         case WI_RID_MAC_NODE:
  170                 IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr);
  171                 wreq.wi_len = IEEE80211_ADDR_LEN / 2;
  172                 break;
  173         case WI_RID_TX_RATE:
  174                 if (ic->ic_fixed_rate == -1)
  175                         wreq.wi_val[0] = 0;     /* auto */
  176                 else
  177                         wreq.wi_val[0] = htole16(
  178                             (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
  179                             IEEE80211_RATE_VAL) / 2);
  180                 wreq.wi_len = 1;
  181                 break;
  182         case WI_RID_CUR_TX_RATE:
  183                 wreq.wi_val[0] = htole16(
  184                     (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
  185                     IEEE80211_RATE_VAL) / 2);
  186                 wreq.wi_len = 1;
  187                 break;
  188         case WI_RID_RTS_THRESH:
  189                 wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
  190                 wreq.wi_len = 1;
  191                 break;
  192         case WI_RID_CREATE_IBSS:
  193                 wreq.wi_val[0] =
  194                     htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
  195                 wreq.wi_len = 1;
  196                 break;
  197         case WI_RID_MICROWAVE_OVEN:
  198                 wreq.wi_val[0] = 0;     /* no ... not supported */
  199                 wreq.wi_len = 1;
  200                 break;
  201         case WI_RID_ROAMING_MODE:
  202                 wreq.wi_val[0] = htole16(1);    /* enabled ... not supported */
  203                 wreq.wi_len = 1;
  204                 break;
  205         case WI_RID_SYSTEM_SCALE:
  206                 wreq.wi_val[0] = htole16(1);    /* low density ... not supp */
  207                 wreq.wi_len = 1;
  208                 break;
  209         case WI_RID_PM_ENABLED:
  210                 wreq.wi_val[0] =
  211                     htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
  212                 wreq.wi_len = 1;
  213                 break;
  214         case WI_RID_MAX_SLEEP:
  215                 wreq.wi_val[0] = htole16(ic->ic_lintval);
  216                 wreq.wi_len = 1;
  217                 break;
  218         case WI_RID_CUR_BEACON_INT:
  219                 wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
  220                 wreq.wi_len = 1;
  221                 break;
  222         case WI_RID_WEP_AVAIL:
  223                 wreq.wi_val[0] =
  224                     htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0);
  225                 wreq.wi_len = 1;
  226                 break;
  227         case WI_RID_CNFAUTHMODE:
  228                 wreq.wi_val[0] = htole16(1);    /* TODO: open system only */
  229                 wreq.wi_len = 1;
  230                 break;
  231         case WI_RID_ENCRYPTION:
  232                 wreq.wi_val[0] =
  233                     htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0);
  234                 wreq.wi_len = 1;
  235                 break;
  236         case WI_RID_TX_CRYPT_KEY:
  237                 wreq.wi_val[0] = htole16(ic->ic_wep_txkey);
  238                 wreq.wi_len = 1;
  239                 break;
  240         case WI_RID_DEFLT_CRYPT_KEYS:
  241                 keys = (struct wi_ltv_keys *)&wreq;
  242                 /* do not show keys to non-root user */
  243                 error = suser(curthread);
  244                 if (error) {
  245                         memset(keys, 0, sizeof(*keys));
  246                         error = 0;
  247                         break;
  248                 }
  249                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
  250                         keys->wi_keys[i].wi_keylen =
  251                             htole16(ic->ic_nw_keys[i].wk_len);
  252                         memcpy(keys->wi_keys[i].wi_keydat,
  253                             ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len);
  254                 }
  255                 wreq.wi_len = sizeof(*keys) / 2;
  256                 break;
  257         case WI_RID_MAX_DATALEN:
  258                 wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN);    /* TODO: frag */
  259                 wreq.wi_len = 1;
  260                 break;
  261         case WI_RID_IFACE_STATS:
  262                 /* XXX: should be implemented in lower drivers */
  263                 break;
  264         case WI_RID_READ_APS:
  265                 if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
  266                         /*
  267                          * Don't return results until active scan completes.
  268                          */
  269                         if (ic->ic_state == IEEE80211_S_SCAN &&
  270                             (ic->ic_flags & IEEE80211_F_ASCAN)) {
  271                                 error = EINPROGRESS;
  272                                 break;
  273                         }
  274                 }
  275                 i = 0;
  276                 ap = (void *)((char *)wreq.wi_val + sizeof(i));
  277                 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
  278                         if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1))
  279                                 break;
  280                         memset(ap, 0, sizeof(*ap));
  281                         if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
  282                                 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
  283                                 ap->namelen = ic->ic_des_esslen;
  284                                 if (ic->ic_des_esslen)
  285                                         memcpy(ap->name, ic->ic_des_essid,
  286                                             ic->ic_des_esslen);
  287                         } else {
  288                                 IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
  289                                 ap->namelen = ni->ni_esslen;
  290                                 if (ni->ni_esslen)
  291                                         memcpy(ap->name, ni->ni_essid,
  292                                             ni->ni_esslen);
  293                         }
  294                         ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
  295                         ap->signal = (*ic->ic_node_getrssi)(ic, ni);
  296                         ap->capinfo = ni->ni_capinfo;
  297                         ap->interval = ni->ni_intval;
  298                         rs = &ni->ni_rates;
  299                         for (j = 0; j < rs->rs_nrates; j++) {
  300                                 if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
  301                                         ap->rate = (rs->rs_rates[j] &
  302                                             IEEE80211_RATE_VAL) * 5; /* XXX */
  303                                 }
  304                         }
  305                         i++;
  306                         ap++;
  307                 }
  308                 memcpy(wreq.wi_val, &i, sizeof(i));
  309                 wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2;
  310                 break;
  311         case WI_RID_PRISM2:
  312                 wreq.wi_val[0] = 1;     /* XXX lie so SCAN_RES can give rates */
  313                 wreq.wi_len = sizeof(u_int16_t) / 2;
  314                 break;
  315         case WI_RID_SCAN_RES:                   /* compatibility interface */
  316                 if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
  317                     ic->ic_state == IEEE80211_S_SCAN &&
  318                     (ic->ic_flags & IEEE80211_F_ASCAN)) {
  319                         error = EINPROGRESS;
  320                         break;
  321                 }
  322                 /* NB: we use the Prism2 format so we can return rate info */
  323                 p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
  324                 res = (void *)&p2[1];
  325                 i = 0;
  326                 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
  327                         if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1))
  328                                 break;
  329                         res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
  330                         res->wi_noise = 0;
  331                         res->wi_signal = (*ic->ic_node_getrssi)(ic, ni);
  332                         IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
  333                         res->wi_interval = ni->ni_intval;
  334                         res->wi_capinfo = ni->ni_capinfo;
  335                         res->wi_ssid_len = ni->ni_esslen;
  336                         memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
  337                         /* NB: assumes wi_srates holds <= ni->ni_rates */
  338                         memcpy(res->wi_srates, ni->ni_rates.rs_rates,
  339                                 sizeof(res->wi_srates));
  340                         if (ni->ni_rates.rs_nrates < 10)
  341                                 res->wi_srates[ni->ni_rates.rs_nrates] = 0;
  342                         res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
  343                         res->wi_rsvd = 0;
  344                         res++, i++;
  345                 }
  346                 p2->wi_rsvd = 0;
  347                 p2->wi_reason = i;
  348                 wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2;
  349                 break;
  350         case WI_RID_READ_CACHE:
  351                 i = 0;
  352                 TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
  353                         if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1)
  354                                 break;
  355                         IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr);
  356                         memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc));
  357                         wsc.signal = (*ic->ic_node_getrssi)(ic, ni);
  358                         wsc.noise = 0;
  359                         wsc.quality = 0;
  360                         memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
  361                             &wsc, sizeof(wsc));
  362                         i++;
  363                 }
  364                 wreq.wi_len = sizeof(wsc) * i / 2;
  365                 break;
  366         case WI_RID_SCAN_APS:
  367                 error = EINVAL;
  368                 break;
  369         default:
  370                 error = EINVAL;
  371                 break;
  372         }
  373         if (error == 0) {
  374                 wreq.wi_len++;
  375                 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
  376         }
  377         return error;
  378 }
  379 
  380 static int
  381 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
  382 {
  383 #define IEEERATE(_ic,_m,_i) \
  384         ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
  385         int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
  386         for (i = 0; i < nrates; i++)
  387                 if (IEEERATE(ic, mode, i) == rate)
  388                         return i;
  389         return -1;
  390 #undef IEEERATE
  391 }
  392 
  393 /*
  394  * Prepare to do a user-initiated scan for AP's.  If no
  395  * current/default channel is setup or the current channel
  396  * is invalid then pick the first available channel from
  397  * the active list as the place to start the scan.
  398  */
  399 static int
  400 ieee80211_setupscan(struct ieee80211com *ic)
  401 {
  402         u_char *chanlist = ic->ic_chan_active;
  403         int i;
  404 
  405         if (ic->ic_ibss_chan == NULL ||
  406             isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
  407                 for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
  408                         if (isset(chanlist, i)) {
  409                                 ic->ic_ibss_chan = &ic->ic_channels[i];
  410                                 goto found;
  411                         }
  412                 return EINVAL;                  /* no active channels */
  413 found:
  414                 ;
  415         }
  416         if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
  417             isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
  418                 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
  419         /*
  420          * XXX don't permit a scan to be started unless we
  421          * know the device is ready.  For the moment this means
  422          * the device is marked up as this is the required to
  423          * initialize the hardware.  It would be better to permit
  424          * scanning prior to being up but that'll require some
  425          * changes to the infrastructure.
  426          */
  427         return (ic->ic_if.if_flags & IFF_UP) ? 0 : ENETRESET;
  428 }
  429 
  430 int
  431 ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data)
  432 {
  433         struct ieee80211com *ic = (void *)ifp;
  434         int i, j, len, error, rate;
  435         struct ifreq *ifr = (struct ifreq *)data;
  436         struct wi_ltv_keys *keys;
  437         struct wi_req wreq;
  438         u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
  439 
  440         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
  441         if (error)
  442                 return error;
  443         len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
  444         switch (wreq.wi_type) {
  445         case WI_RID_SERIALNO:
  446         case WI_RID_NODENAME:
  447                 return EPERM;
  448         case WI_RID_CURRENT_SSID:
  449                 return EPERM;
  450         case WI_RID_OWN_SSID:
  451         case WI_RID_DESIRED_SSID:
  452                 if (le16toh(wreq.wi_val[0]) * 2 > len ||
  453                     le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
  454                         error = ENOSPC;
  455                         break;
  456                 }
  457                 memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
  458                 ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
  459                 memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
  460                 error = ENETRESET;
  461                 break;
  462         case WI_RID_CURRENT_BSSID:
  463                 return EPERM;
  464         case WI_RID_OWN_CHNL:
  465                 if (len != 2)
  466                         return EINVAL;
  467                 i = le16toh(wreq.wi_val[0]);
  468                 if (i < 0 ||
  469                     i > IEEE80211_CHAN_MAX ||
  470                     isclr(ic->ic_chan_active, i))
  471                         return EINVAL;
  472                 ic->ic_ibss_chan = &ic->ic_channels[i];
  473                 if (ic->ic_flags & IEEE80211_F_SIBSS)
  474                         error = ENETRESET;
  475                 break;
  476         case WI_RID_CURRENT_CHAN:
  477                 return EPERM;
  478         case WI_RID_COMMS_QUALITY:
  479                 return EPERM;
  480         case WI_RID_PROMISC:
  481                 if (len != 2)
  482                         return EINVAL;
  483                 if (ifp->if_flags & IFF_PROMISC) {
  484                         if (wreq.wi_val[0] == 0) {
  485                                 ifp->if_flags &= ~IFF_PROMISC;
  486                                 error = ENETRESET;
  487                         }
  488                 } else {
  489                         if (wreq.wi_val[0] != 0) {
  490                                 ifp->if_flags |= IFF_PROMISC;
  491                                 error = ENETRESET;
  492                         }
  493                 }
  494                 break;
  495         case WI_RID_PORTTYPE:
  496                 if (len != 2)
  497                         return EINVAL;
  498                 switch (le16toh(wreq.wi_val[0])) {
  499                 case IEEE80211_M_STA:
  500                         break;
  501                 case IEEE80211_M_IBSS:
  502                         if (!(ic->ic_caps & IEEE80211_C_IBSS))
  503                                 return EINVAL;
  504                         break;
  505                 case IEEE80211_M_AHDEMO:
  506                         if (ic->ic_phytype != IEEE80211_T_DS ||
  507                             !(ic->ic_caps & IEEE80211_C_AHDEMO))
  508                                 return EINVAL;
  509                         break;
  510                 case IEEE80211_M_HOSTAP:
  511                         if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
  512                                 return EINVAL;
  513                         break;
  514                 default:
  515                         return EINVAL;
  516                 }
  517                 if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
  518                         ic->ic_opmode = le16toh(wreq.wi_val[0]);
  519                         error = ENETRESET;
  520                 }
  521                 break;
  522 #if 0
  523         case WI_RID_MAC_NODE:
  524                 if (len != IEEE80211_ADDR_LEN)
  525                         return EINVAL;
  526                 IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
  527                 /* if_init will copy lladdr into ic_myaddr */
  528                 error = ENETRESET;
  529                 break;
  530 #endif
  531         case WI_RID_TX_RATE:
  532                 if (len != 2)
  533                         return EINVAL;
  534                 if (wreq.wi_val[0] == 0) {
  535                         /* auto */
  536                         ic->ic_fixed_rate = -1;
  537                         break;
  538                 }
  539                 rate = 2 * le16toh(wreq.wi_val[0]);
  540                 if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
  541                         /*
  542                          * In autoselect mode search for the rate.  We take
  543                          * the first instance which may not be right, but we
  544                          * are limited by the interface.  Note that we also
  545                          * lock the mode to insure the rate is meaningful
  546                          * when it is used.
  547                          */
  548                         for (j = IEEE80211_MODE_11A;
  549                              j < IEEE80211_MODE_MAX; j++) {
  550                                 if ((ic->ic_modecaps & (1<<j)) == 0)
  551                                         continue;
  552                                 i = findrate(ic, j, rate);
  553                                 if (i != -1) {
  554                                         /* lock mode too */
  555                                         ic->ic_curmode = j;
  556                                         goto setrate;
  557                                 }
  558                         }
  559                 } else {
  560                         i = findrate(ic, ic->ic_curmode, rate);
  561                         if (i != -1)
  562                                 goto setrate;
  563                 }
  564                 return EINVAL;
  565         setrate:
  566                 ic->ic_fixed_rate = i;
  567                 error = ENETRESET;
  568                 break;
  569         case WI_RID_CUR_TX_RATE:
  570                 return EPERM;
  571         case WI_RID_RTS_THRESH:
  572                 if (len != 2)
  573                         return EINVAL;
  574                 if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN)
  575                         return EINVAL;          /* TODO: RTS */
  576                 break;
  577         case WI_RID_CREATE_IBSS:
  578                 if (len != 2)
  579                         return EINVAL;
  580                 if (wreq.wi_val[0] != 0) {
  581                         if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
  582                                 return EINVAL;
  583                         if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
  584                                 ic->ic_flags |= IEEE80211_F_IBSSON;
  585                                 if (ic->ic_opmode == IEEE80211_M_IBSS &&
  586                                     ic->ic_state == IEEE80211_S_SCAN)
  587                                         error = ENETRESET;
  588                         }
  589                 } else {
  590                         if (ic->ic_flags & IEEE80211_F_IBSSON) {
  591                                 ic->ic_flags &= ~IEEE80211_F_IBSSON;
  592                                 if (ic->ic_flags & IEEE80211_F_SIBSS) {
  593                                         ic->ic_flags &= ~IEEE80211_F_SIBSS;
  594                                         error = ENETRESET;
  595                                 }
  596                         }
  597                 }
  598                 break;
  599         case WI_RID_MICROWAVE_OVEN:
  600                 if (len != 2)
  601                         return EINVAL;
  602                 if (wreq.wi_val[0] != 0)
  603                         return EINVAL;          /* not supported */
  604                 break;
  605         case WI_RID_ROAMING_MODE:
  606                 if (len != 2)
  607                         return EINVAL;
  608                 if (le16toh(wreq.wi_val[0]) != 1)
  609                         return EINVAL;          /* not supported */
  610                 break;
  611         case WI_RID_SYSTEM_SCALE:
  612                 if (len != 2)
  613                         return EINVAL;
  614                 if (le16toh(wreq.wi_val[0]) != 1)
  615                         return EINVAL;          /* not supported */
  616                 break;
  617         case WI_RID_PM_ENABLED:
  618                 if (len != 2)
  619                         return EINVAL;
  620                 if (wreq.wi_val[0] != 0) {
  621                         if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
  622                                 return EINVAL;
  623                         if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
  624                                 ic->ic_flags |= IEEE80211_F_PMGTON;
  625                                 error = ENETRESET;
  626                         }
  627                 } else {
  628                         if (ic->ic_flags & IEEE80211_F_PMGTON) {
  629                                 ic->ic_flags &= ~IEEE80211_F_PMGTON;
  630                                 error = ENETRESET;
  631                         }
  632                 }
  633                 break;
  634         case WI_RID_MAX_SLEEP:
  635                 if (len != 2)
  636                         return EINVAL;
  637                 ic->ic_lintval = le16toh(wreq.wi_val[0]);
  638                 if (ic->ic_flags & IEEE80211_F_PMGTON)
  639                         error = ENETRESET;
  640                 break;
  641         case WI_RID_CUR_BEACON_INT:
  642                 return EPERM;
  643         case WI_RID_WEP_AVAIL:
  644                 return EPERM;
  645         case WI_RID_CNFAUTHMODE:
  646                 if (len != 2)
  647                         return EINVAL;
  648                 if (le16toh(wreq.wi_val[0]) != 1)
  649                         return EINVAL;          /* TODO: shared key auth */
  650                 break;
  651         case WI_RID_ENCRYPTION:
  652                 if (len != 2)
  653                         return EINVAL;
  654                 if (wreq.wi_val[0] != 0) {
  655                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
  656                                 return EINVAL;
  657                         if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) {
  658                                 ic->ic_flags |= IEEE80211_F_WEPON;
  659                                 error = ENETRESET;
  660                         }
  661                 } else {
  662                         if (ic->ic_flags & IEEE80211_F_WEPON) {
  663                                 ic->ic_flags &= ~IEEE80211_F_WEPON;
  664                                 error = ENETRESET;
  665                         }
  666                 }
  667                 break;
  668         case WI_RID_TX_CRYPT_KEY:
  669                 if (len != 2)
  670                         return EINVAL;
  671                 i = le16toh(wreq.wi_val[0]);
  672                 if (i >= IEEE80211_WEP_NKID)
  673                         return EINVAL;
  674                 ic->ic_wep_txkey = i;
  675                 break;
  676         case WI_RID_DEFLT_CRYPT_KEYS:
  677                 if (len != sizeof(struct wi_ltv_keys))
  678                         return EINVAL;
  679                 keys = (struct wi_ltv_keys *)&wreq;
  680                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
  681                         len = le16toh(keys->wi_keys[i].wi_keylen);
  682                         if (len != 0 && len < IEEE80211_WEP_KEYLEN)
  683                                 return EINVAL;
  684                         if (len > sizeof(ic->ic_nw_keys[i].wk_key))
  685                                 return EINVAL;
  686                 }
  687                 memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys));
  688                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
  689                         len = le16toh(keys->wi_keys[i].wi_keylen);
  690                         ic->ic_nw_keys[i].wk_len = len;
  691                         memcpy(ic->ic_nw_keys[i].wk_key,
  692                             keys->wi_keys[i].wi_keydat, len);
  693                 }
  694                 error = ENETRESET;
  695                 break;
  696         case WI_RID_MAX_DATALEN:
  697                 if (len != 2)
  698                         return EINVAL;
  699                 len = le16toh(wreq.wi_val[0]);
  700                 if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
  701                         return EINVAL;
  702                 if (len != IEEE80211_MAX_LEN)
  703                         return EINVAL;          /* TODO: fragment */
  704                 ic->ic_fragthreshold = len;
  705                 error = ENETRESET;
  706                 break;
  707         case WI_RID_IFACE_STATS:
  708                 error = EPERM;
  709                 break;
  710         case WI_RID_SCAN_REQ:                   /* XXX wicontrol */
  711                 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
  712                         break;
  713                 error = ieee80211_setupscan(ic);
  714                 if (error == 0)
  715                         error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
  716                 break;
  717         case WI_RID_SCAN_APS:
  718                 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
  719                         break;
  720                 len--;                  /* XXX: tx rate? */
  721                 /* FALLTHRU */
  722         case WI_RID_CHANNEL_LIST:
  723                 memset(chanlist, 0, sizeof(chanlist));
  724                 /*
  725                  * Since channel 0 is not available for DS, channel 1
  726                  * is assigned to LSB on WaveLAN.
  727                  */
  728                 if (ic->ic_phytype == IEEE80211_T_DS)
  729                         i = 1;
  730                 else
  731                         i = 0;
  732                 for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
  733                         if ((j / 8) >= len)
  734                                 break;
  735                         if (isclr((u_int8_t *)wreq.wi_val, j))
  736                                 continue;
  737                         if (isclr(ic->ic_chan_active, i)) {
  738                                 if (wreq.wi_type != WI_RID_CHANNEL_LIST)
  739                                         continue;
  740                                 if (isclr(ic->ic_chan_avail, i))
  741                                         return EPERM;
  742                         }
  743                         setbit(chanlist, i);
  744                 }
  745                 memcpy(ic->ic_chan_active, chanlist,
  746                     sizeof(ic->ic_chan_active));
  747                 error = ieee80211_setupscan(ic);
  748                 if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
  749                         /* NB: ignore error from ieee80211_setupscan */
  750                         error = ENETRESET;
  751                 } else if (error == 0)
  752                         error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
  753                 break;
  754         default:
  755                 error = EINVAL;
  756                 break;
  757         }
  758         return error;
  759 }
  760 
  761 int
  762 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  763 {
  764         struct ieee80211com *ic = (void *)ifp;
  765         int error = 0;
  766         u_int kid, len;
  767         struct ieee80211req *ireq;
  768         struct ifreq *ifr;
  769         u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
  770         char tmpssid[IEEE80211_NWID_LEN];
  771         struct ieee80211_channel *chan;
  772         struct ifaddr *ifa;                     /* XXX */
  773 
  774         switch (cmd) {
  775         case SIOCSIFMEDIA:
  776         case SIOCGIFMEDIA:
  777                 error = ifmedia_ioctl(ifp, (struct ifreq *) data,
  778                                 &ic->ic_media, cmd);
  779                 break;
  780         case SIOCG80211:
  781                 ireq = (struct ieee80211req *) data;
  782                 switch (ireq->i_type) {
  783                 case IEEE80211_IOC_SSID:
  784                         switch (ic->ic_state) {
  785                         case IEEE80211_S_INIT:
  786                         case IEEE80211_S_SCAN:
  787                                 ireq->i_len = ic->ic_des_esslen;
  788                                 memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
  789                                 break;
  790                         default:
  791                                 ireq->i_len = ic->ic_bss->ni_esslen;
  792                                 memcpy(tmpssid, ic->ic_bss->ni_essid,
  793                                         ireq->i_len);
  794                                 break;
  795                         }
  796                         error = copyout(tmpssid, ireq->i_data, ireq->i_len);
  797                         break;
  798                 case IEEE80211_IOC_NUMSSIDS:
  799                         ireq->i_val = 1;
  800                         break;
  801                 case IEEE80211_IOC_WEP:
  802                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
  803                                 ireq->i_val = IEEE80211_WEP_NOSUP; 
  804                         } else {
  805                                 if (ic->ic_flags & IEEE80211_F_WEPON) {
  806                                         ireq->i_val =
  807                                             IEEE80211_WEP_MIXED;
  808                                 } else {
  809                                         ireq->i_val =
  810                                             IEEE80211_WEP_OFF;
  811                                 }
  812                         }
  813                         break;
  814                 case IEEE80211_IOC_WEPKEY:
  815                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
  816                                 error = EINVAL;
  817                                 break;
  818                         }
  819                         kid = (u_int) ireq->i_val;
  820                         if (kid >= IEEE80211_WEP_NKID) {
  821                                 error = EINVAL;
  822                                 break;
  823                         }
  824                         len = (u_int) ic->ic_nw_keys[kid].wk_len;
  825                         /* NB: only root can read WEP keys */
  826                         if (suser(curthread) == 0) {
  827                                 bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
  828                         } else {
  829                                 bzero(tmpkey, len);
  830                         }
  831                         ireq->i_len = len;
  832                         error = copyout(tmpkey, ireq->i_data, len);
  833                         break;
  834                 case IEEE80211_IOC_NUMWEPKEYS:
  835                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
  836                                 error = EINVAL;
  837                         else
  838                                 ireq->i_val = IEEE80211_WEP_NKID;
  839                         break;
  840                 case IEEE80211_IOC_WEPTXKEY:
  841                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
  842                                 error = EINVAL;
  843                         else
  844                                 ireq->i_val = ic->ic_wep_txkey;
  845                         break;
  846                 case IEEE80211_IOC_AUTHMODE:
  847                         ireq->i_val = IEEE80211_AUTH_OPEN;
  848                         break;
  849                 case IEEE80211_IOC_CHANNEL:
  850                         switch (ic->ic_state) {
  851                         case IEEE80211_S_INIT:
  852                         case IEEE80211_S_SCAN:
  853                                 if (ic->ic_opmode == IEEE80211_M_STA)
  854                                         chan = ic->ic_des_chan;
  855                                 else
  856                                         chan = ic->ic_ibss_chan;
  857                                 break;
  858                         default:
  859                                 chan = ic->ic_bss->ni_chan;
  860                                 break;
  861                         }
  862                         ireq->i_val = ieee80211_chan2ieee(ic, chan);
  863                         break;
  864                 case IEEE80211_IOC_POWERSAVE:
  865                         if (ic->ic_flags & IEEE80211_F_PMGTON)
  866                                 ireq->i_val = IEEE80211_POWERSAVE_ON;
  867                         else
  868                                 ireq->i_val = IEEE80211_POWERSAVE_OFF;
  869                         break;
  870                 case IEEE80211_IOC_POWERSAVESLEEP:
  871                         ireq->i_val = ic->ic_lintval;
  872                         break;
  873                 case IEEE80211_IOC_RTSTHRESHOLD:
  874                         ireq->i_val = ic->ic_rtsthreshold;
  875                         break;
  876                 case IEEE80211_IOC_PROTMODE:
  877                         ireq->i_val = ic->ic_protmode;
  878                         break;
  879                 case IEEE80211_IOC_TXPOWER:
  880                         if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
  881                                 error = EINVAL;
  882                         else
  883                                 ireq->i_val = ic->ic_txpower;
  884                         break;
  885                 default:
  886                         error = EINVAL;
  887                         break;
  888                 }
  889                 break;
  890         case SIOCS80211:
  891                 error = suser(curthread);
  892                 if (error)
  893                         break;
  894                 ireq = (struct ieee80211req *) data;
  895                 switch (ireq->i_type) {
  896                 case IEEE80211_IOC_SSID:
  897                         if (ireq->i_val != 0 ||
  898                             ireq->i_len > IEEE80211_NWID_LEN) {
  899                                 error = EINVAL;
  900                                 break;
  901                         }
  902                         error = copyin(ireq->i_data, tmpssid, ireq->i_len);
  903                         if (error)
  904                                 break;
  905                         memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
  906                         ic->ic_des_esslen = ireq->i_len;
  907                         memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
  908                         error = ENETRESET;
  909                         break;
  910                 case IEEE80211_IOC_WEP:
  911                         /*
  912                          * These cards only support one mode so
  913                          * we just turn wep on if what ever is
  914                          * passed in is not OFF.
  915                          */
  916                         if (ireq->i_val == IEEE80211_WEP_OFF) {
  917                                 ic->ic_flags &= ~IEEE80211_F_WEPON;
  918                         } else {
  919                                 ic->ic_flags |= IEEE80211_F_WEPON;
  920                         }
  921                         error = ENETRESET;
  922                         break;
  923                 case IEEE80211_IOC_WEPKEY:
  924                         if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
  925                                 error = EINVAL;
  926                                 break;
  927                         }
  928                         kid = (u_int) ireq->i_val;
  929                         if (kid >= IEEE80211_WEP_NKID) {
  930                                 error = EINVAL;
  931                                 break;
  932                         } 
  933                         if (ireq->i_len > sizeof(tmpkey)) {
  934                                 error = EINVAL;
  935                                 break;
  936                         }
  937                         memset(tmpkey, 0, sizeof(tmpkey));
  938                         error = copyin(ireq->i_data, tmpkey, ireq->i_len);
  939                         if (error)
  940                                 break;
  941                         memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey,
  942                                 sizeof(tmpkey));
  943                         ic->ic_nw_keys[kid].wk_len = ireq->i_len;
  944                         error = ENETRESET;
  945                         break;
  946                 case IEEE80211_IOC_WEPTXKEY:
  947                         kid = (u_int) ireq->i_val;
  948                         if (kid >= IEEE80211_WEP_NKID) {
  949                                 error = EINVAL;
  950                                 break;
  951                         }
  952                         ic->ic_wep_txkey = kid;
  953                         error = ENETRESET;
  954                         break;
  955 #if 0
  956                 case IEEE80211_IOC_AUTHMODE:
  957                         sc->wi_authmode = ireq->i_val;
  958                         break;
  959 #endif
  960                 case IEEE80211_IOC_CHANNEL:
  961                         /* XXX 0xffff overflows 16-bit signed */
  962                         if (ireq->i_val == 0 ||
  963                             ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
  964                                 ic->ic_des_chan = IEEE80211_CHAN_ANYC;
  965                         else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
  966                             isclr(ic->ic_chan_active, ireq->i_val)) {
  967                                 error = EINVAL;
  968                                 break;
  969                         } else
  970                                 ic->ic_ibss_chan = ic->ic_des_chan =
  971                                         &ic->ic_channels[ireq->i_val];
  972                         switch (ic->ic_state) {
  973                         case IEEE80211_S_INIT:
  974                         case IEEE80211_S_SCAN:
  975                                 error = ENETRESET;
  976                                 break;
  977                         default:
  978                                 if (ic->ic_opmode == IEEE80211_M_STA) {
  979                                         if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
  980                                             ic->ic_bss->ni_chan != ic->ic_des_chan)
  981                                                 error = ENETRESET;
  982                                 } else {
  983                                         if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
  984                                                 error = ENETRESET;
  985                                 }
  986                                 break;
  987                         }
  988                         break;
  989                 case IEEE80211_IOC_POWERSAVE:
  990                         switch (ireq->i_val) {
  991                         case IEEE80211_POWERSAVE_OFF:
  992                                 if (ic->ic_flags & IEEE80211_F_PMGTON) {
  993                                         ic->ic_flags &= ~IEEE80211_F_PMGTON;
  994                                         error = ENETRESET;
  995                                 }
  996                                 break;
  997                         case IEEE80211_POWERSAVE_ON:
  998                                 if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
  999                                         error = EINVAL;
 1000                                 else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
 1001                                         ic->ic_flags |= IEEE80211_F_PMGTON;
 1002                                         error = ENETRESET;
 1003                                 }
 1004                                 break;
 1005                         default:
 1006                                 error = EINVAL;
 1007                                 break;
 1008                         }
 1009                         break;
 1010                 case IEEE80211_IOC_POWERSAVESLEEP:
 1011                         if (ireq->i_val < 0) {
 1012                                 error = EINVAL;
 1013                                 break;
 1014                         }
 1015                         ic->ic_lintval = ireq->i_val;
 1016                         error = ENETRESET;
 1017                         break;
 1018                 case IEEE80211_IOC_RTSTHRESHOLD:
 1019                         if (!(IEEE80211_RTS_MIN < ireq->i_val &&
 1020                               ireq->i_val < IEEE80211_RTS_MAX)) {
 1021                                 error = EINVAL;
 1022                                 break;
 1023                         }
 1024                         ic->ic_rtsthreshold = ireq->i_val;
 1025                         error = ENETRESET;
 1026                         break;
 1027                 case IEEE80211_IOC_PROTMODE:
 1028                         if (ireq->i_val > IEEE80211_PROT_RTSCTS) {
 1029                                 error = EINVAL;
 1030                                 break;
 1031                         }
 1032                         ic->ic_protmode = ireq->i_val;
 1033                         /* NB: if not operating in 11g this can wait */
 1034                         if (ic->ic_curmode == IEEE80211_MODE_11G)
 1035                                 error = ENETRESET;
 1036                         break;
 1037                 case IEEE80211_IOC_TXPOWER:
 1038                         if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
 1039                                 error = EINVAL;
 1040                                 break;
 1041                         }
 1042                         if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
 1043                               ireq->i_val < IEEE80211_TXPOWER_MAX)) {
 1044                                 error = EINVAL;
 1045                                 break;
 1046                         }
 1047                         ic->ic_txpower = ireq->i_val;
 1048                         error = ENETRESET;
 1049                         break;
 1050                 default:
 1051                         error = EINVAL;
 1052                         break;
 1053                 }
 1054                 break;
 1055         case SIOCGIFGENERIC:
 1056                 error = ieee80211_cfgget(ifp, cmd, data);
 1057                 break;
 1058         case SIOCSIFGENERIC:
 1059                 error = suser(curthread);
 1060                 if (error)
 1061                         break;
 1062                 error = ieee80211_cfgset(ifp, cmd, data);
 1063                 break;
 1064         case SIOCG80211STATS:
 1065                 ifr = (struct ifreq *)data;
 1066                 copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
 1067                 break;
 1068         case SIOCSIFMTU:
 1069                 ifr = (struct ifreq *)data;
 1070                 if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
 1071                     ifr->ifr_mtu <= IEEE80211_MTU_MAX))
 1072                         error = EINVAL;
 1073                 else
 1074                         ifp->if_mtu = ifr->ifr_mtu;
 1075                 break;
 1076         case SIOCSIFADDR:
 1077                 /*
 1078                  * XXX Handle this directly so we can supress if_init calls.
 1079                  * XXX This should be done in ether_ioctl but for the moment
 1080                  * XXX there are too many other parts of the system that
 1081                  * XXX set IFF_UP and so supress if_init being called when
 1082                  * XXX it should be.
 1083                  */
 1084                 ifa = (struct ifaddr *) data;
 1085                 switch (ifa->ifa_addr->sa_family) {
 1086 #ifdef INET
 1087                 case AF_INET:
 1088                         if ((ifp->if_flags & IFF_UP) == 0) {
 1089                                 ifp->if_flags |= IFF_UP;
 1090                                 ifp->if_init(ifp->if_softc);
 1091                         }
 1092                         arp_ifinit(ifp, ifa);
 1093                         break;
 1094 #endif
 1095 #ifdef IPX
 1096                 /*
 1097                  * XXX - This code is probably wrong,
 1098                  *       but has been copied many times.
 1099                  */
 1100                 case AF_IPX: {
 1101                         struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
 1102                         struct arpcom *ac = (struct arpcom *)ifp;
 1103 
 1104                         if (ipx_nullhost(*ina))
 1105                                 ina->x_host = *(union ipx_host *) ac->ac_enaddr;
 1106                         else
 1107                                 bcopy((caddr_t) ina->x_host.c_host,
 1108                                       (caddr_t) ac->ac_enaddr,
 1109                                       sizeof(ac->ac_enaddr));
 1110                         /* fall thru... */
 1111                 }
 1112 #endif
 1113                 default:
 1114                         if ((ifp->if_flags & IFF_UP) == 0) {
 1115                                 ifp->if_flags |= IFF_UP;
 1116                                 ifp->if_init(ifp->if_softc);
 1117                         }
 1118                         break;
 1119                 }
 1120                 break;
 1121         default:
 1122                 error = ether_ioctl(ifp, cmd, data);
 1123                 break;
 1124         }
 1125         return error;
 1126 }

Cache object: abb75289afc41e5f06dcd3dc98500ff6


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