linux/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
<<
>>
Prefs
   1/******************************************************************************
   2 * rtl871x_ioctl_linux.c
   3 *
   4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
   5 * Linux device driver for RTL8192SU
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of version 2 of the GNU General Public License as
   9 * published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful, but WITHOUT
  12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  14 * more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along with
  17 * this program; if not, write to the Free Software Foundation, Inc.,
  18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
  19 *
  20 * Modifications for inclusion into the Linux staging tree are
  21 * Copyright(c) 2010 Larry Finger. All rights reserved.
  22 *
  23 * Contact information:
  24 * WLAN FAE <wlanfae@realtek.com>
  25 * Larry Finger <Larry.Finger@lwfinger.net>
  26 *
  27 ******************************************************************************/
  28
  29#define _RTL871X_IOCTL_LINUX_C_
  30#define _RTL871X_MP_IOCTL_C_
  31
  32#include "osdep_service.h"
  33#include "drv_types.h"
  34#include "wlan_bssdef.h"
  35#include "rtl871x_debug.h"
  36#include "wifi.h"
  37#include "rtl871x_mlme.h"
  38#include "rtl871x_ioctl.h"
  39#include "rtl871x_ioctl_set.h"
  40#include "rtl871x_mp_ioctl.h"
  41#include "mlme_osdep.h"
  42#include <linux/wireless.h>
  43#include <linux/module.h>
  44#include <linux/kernel.h>
  45#include <linux/io.h>
  46#include <linux/semaphore.h>
  47#include <net/iw_handler.h>
  48#include <linux/if_arp.h>
  49#include <linux/etherdevice.h>
  50
  51
  52#define RTL_IOCTL_WPA_SUPPLICANT        (SIOCIWFIRSTPRIV + 0x1E)
  53
  54#define SCAN_ITEM_SIZE 768
  55#define MAX_CUSTOM_LEN 64
  56#define RATE_COUNT 4
  57
  58
  59static const u32 rtl8180_rates[] = {1000000, 2000000, 5500000, 11000000,
  60                       6000000, 9000000, 12000000, 18000000,
  61                       24000000, 36000000, 48000000, 54000000};
  62
  63static const long ieee80211_wlan_frequencies[] = {
  64        2412, 2417, 2422, 2427,
  65        2432, 2437, 2442, 2447,
  66        2452, 2457, 2462, 2467,
  67        2472, 2484
  68};
  69
  70static const char * const iw_operation_mode[] = {
  71        "Auto", "Ad-Hoc", "Managed",  "Master", "Repeater", "Secondary",
  72         "Monitor"
  73};
  74
  75void r8712_indicate_wx_assoc_event(struct _adapter *padapter)
  76{
  77        union iwreq_data wrqu;
  78        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
  79
  80        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
  81        memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress,
  82                ETH_ALEN);
  83        wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
  84}
  85
  86void r8712_indicate_wx_disassoc_event(struct _adapter *padapter)
  87{
  88        union iwreq_data wrqu;
  89
  90        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
  91        eth_zero_addr(wrqu.ap_addr.sa_data);
  92        wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
  93}
  94
  95static inline void handle_pairwise_key(struct sta_info *psta,
  96                                       struct ieee_param *param,
  97                                       struct _adapter *padapter)
  98{
  99        /* pairwise key */
 100        memcpy(psta->x_UncstKey.skey, param->u.crypt.key,
 101               (param->u.crypt. key_len > 16 ? 16 : param->u.crypt.key_len));
 102        if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */
 103                memcpy(psta->tkiptxmickey. skey, &(param->u.crypt.
 104                        key[16]), 8);
 105                memcpy(psta->tkiprxmickey. skey, &(param->u.crypt.
 106                        key[24]), 8);
 107                padapter->securitypriv. busetkipkey = false;
 108                mod_timer(&padapter->securitypriv.tkip_timer,
 109                          jiffies + msecs_to_jiffies(50));
 110        }
 111        r8712_setstakey_cmd(padapter, (unsigned char *)psta, true);
 112}
 113
 114static inline void handle_group_key(struct ieee_param *param,
 115                                    struct _adapter *padapter)
 116{
 117        if (param->u.crypt.idx > 0 &&
 118            param->u.crypt.idx < 3) {
 119                /* group key idx is 1 or 2 */
 120                memcpy(padapter->securitypriv.XGrpKey[param->u.crypt.
 121                        idx - 1].skey, param->u.crypt.key,
 122                        (param->u.crypt.key_len > 16 ? 16 :
 123                         param->u.crypt.key_len));
 124                memcpy(padapter->securitypriv.XGrptxmickey[param->
 125                        u.crypt.idx - 1].skey, &(param->u.crypt.key[16]), 8);
 126                memcpy(padapter->securitypriv. XGrprxmickey[param->
 127                        u.crypt.idx - 1].skey, &(param->u.crypt.key[24]), 8);
 128                padapter->securitypriv.binstallGrpkey = true;
 129                r8712_set_key(padapter, &padapter->securitypriv,
 130                        param->u.crypt.idx);
 131                if (padapter->registrypriv.power_mgnt > PS_MODE_ACTIVE) {
 132                        if (padapter->registrypriv.power_mgnt != padapter->
 133                            pwrctrlpriv.pwr_mode)
 134                                mod_timer(&padapter->mlmepriv.dhcp_timer,
 135                                          jiffies + msecs_to_jiffies(60000));
 136                }
 137        }
 138}
 139
 140static noinline_for_stack char *translate_scan(struct _adapter *padapter,
 141                                   struct iw_request_info *info,
 142                                   struct wlan_network *pnetwork,
 143                                   char *start, char *stop)
 144{
 145        struct iw_event iwe;
 146        struct ieee80211_ht_cap *pht_capie;
 147        char *current_val;
 148        s8 *p;
 149        u32 i = 0, ht_ielen = 0;
 150        u16     cap, ht_cap = false, mcs_rate;
 151        u8 rssi;
 152
 153        if ((pnetwork->network.Configuration.DSConfig < 1) ||
 154            (pnetwork->network.Configuration.DSConfig > 14)) {
 155                if (pnetwork->network.Configuration.DSConfig < 1)
 156                        pnetwork->network.Configuration.DSConfig = 1;
 157                else
 158                        pnetwork->network.Configuration.DSConfig = 14;
 159        }
 160        /* AP MAC address */
 161        iwe.cmd = SIOCGIWAP;
 162        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 163        ether_addr_copy(iwe.u.ap_addr.sa_data, pnetwork->network.MacAddress);
 164        start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
 165        /* Add the ESSID */
 166        iwe.cmd = SIOCGIWESSID;
 167        iwe.u.data.flags = 1;
 168        iwe.u.data.length = min_t(u32, pnetwork->network.Ssid.SsidLength, 32);
 169        start = iwe_stream_add_point(info, start, stop, &iwe,
 170                                     pnetwork->network.Ssid.Ssid);
 171        /* parsing HT_CAP_IE */
 172        p = r8712_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_,
 173                         &ht_ielen, pnetwork->network.IELength - 12);
 174        if (p && ht_ielen > 0) {
 175                ht_cap = true;
 176                pht_capie = (struct ieee80211_ht_cap *)(p + 2);
 177                memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
 178        }
 179        /* Add the protocol name */
 180        iwe.cmd = SIOCGIWNAME;
 181        if (r8712_is_cckratesonly_included(pnetwork->network.rates)) {
 182                if (ht_cap)
 183                        snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn");
 184                else
 185                        snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b");
 186        } else if (r8712_is_cckrates_included(pnetwork->network.rates)) {
 187                if (ht_cap)
 188                        snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn");
 189                else
 190                        snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg");
 191        } else {
 192                if (ht_cap)
 193                        snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn");
 194                else
 195                        snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g");
 196        }
 197        start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
 198        /* Add mode */
 199        iwe.cmd = SIOCGIWMODE;
 200        memcpy((u8 *)&cap, r8712_get_capability_from_ie(pnetwork->network.IEs),
 201                2);
 202        cap = le16_to_cpu(cap);
 203        if (cap & (WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_BSS)) {
 204                if (cap & WLAN_CAPABILITY_BSS)
 205                        iwe.u.mode = (u32)IW_MODE_MASTER;
 206                else
 207                        iwe.u.mode = (u32)IW_MODE_ADHOC;
 208                start = iwe_stream_add_event(info, start, stop, &iwe,
 209                        IW_EV_UINT_LEN);
 210        }
 211        /* Add frequency/channel */
 212        iwe.cmd = SIOCGIWFREQ;
 213        {
 214                /*  check legal index */
 215                u8 dsconfig = pnetwork->network.Configuration.DSConfig;
 216
 217                if (dsconfig >= 1 && dsconfig <= sizeof(
 218                    ieee80211_wlan_frequencies) / sizeof(long))
 219                        iwe.u.freq.m = (s32)(ieee80211_wlan_frequencies[
 220                                       pnetwork->network.Configuration.
 221                                       DSConfig - 1] * 100000);
 222                else
 223                        iwe.u.freq.m = 0;
 224        }
 225        iwe.u.freq.e = (s16)1;
 226        iwe.u.freq.i = (u8)pnetwork->network.Configuration.DSConfig;
 227        start = iwe_stream_add_event(info, start, stop, &iwe,
 228                IW_EV_FREQ_LEN);
 229        /* Add encryption capability */
 230        iwe.cmd = SIOCGIWENCODE;
 231        if (cap & WLAN_CAPABILITY_PRIVACY)
 232                iwe.u.data.flags = (u16)(IW_ENCODE_ENABLED |
 233                                    IW_ENCODE_NOKEY);
 234        else
 235                iwe.u.data.flags = (u16)(IW_ENCODE_DISABLED);
 236        iwe.u.data.length = (u16)0;
 237        start = iwe_stream_add_point(info, start, stop, &iwe,
 238                pnetwork->network.Ssid.Ssid);
 239        /*Add basic and extended rates */
 240        current_val = start + iwe_stream_lcp_len(info);
 241        iwe.cmd = SIOCGIWRATE;
 242        iwe.u.bitrate.fixed = 0;
 243        iwe.u.bitrate.disabled = 0;
 244        iwe.u.bitrate.value = 0;
 245        i = 0;
 246        while (pnetwork->network.rates[i] != 0) {
 247                /* Bit rate given in 500 kb/s units */
 248                iwe.u.bitrate.value = (pnetwork->network.rates[i++] &
 249                                      0x7F) * 500000;
 250                current_val = iwe_stream_add_value(info, start, current_val,
 251                              stop, &iwe, IW_EV_PARAM_LEN);
 252        }
 253        /* Check if we added any event */
 254        if ((current_val - start) > iwe_stream_lcp_len(info))
 255                start = current_val;
 256        /* parsing WPA/WPA2 IE */
 257        {
 258                u8 buf[MAX_WPA_IE_LEN];
 259                u8 wpa_ie[255], rsn_ie[255];
 260                u16 wpa_len = 0, rsn_len = 0;
 261                int n;
 262
 263                r8712_get_sec_ie(pnetwork->network.IEs,
 264                                 pnetwork->network.IELength, rsn_ie, &rsn_len,
 265                                 wpa_ie, &wpa_len);
 266                if (wpa_len > 0) {
 267                        memset(buf, 0, MAX_WPA_IE_LEN);
 268                        n = sprintf(buf, "wpa_ie=");
 269                        for (i = 0; i < wpa_len; i++) {
 270                                n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
 271                                                        "%02x", wpa_ie[i]);
 272                                if (n >= MAX_WPA_IE_LEN)
 273                                        break;
 274                        }
 275                        memset(&iwe, 0, sizeof(iwe));
 276                        iwe.cmd = IWEVCUSTOM;
 277                        iwe.u.data.length = (u16)strlen(buf);
 278                        start = iwe_stream_add_point(info, start, stop,
 279                                &iwe, buf);
 280                        memset(&iwe, 0, sizeof(iwe));
 281                        iwe.cmd = IWEVGENIE;
 282                        iwe.u.data.length = (u16)wpa_len;
 283                        start = iwe_stream_add_point(info, start, stop,
 284                                &iwe, wpa_ie);
 285                }
 286                if (rsn_len > 0) {
 287                        memset(buf, 0, MAX_WPA_IE_LEN);
 288                        n = sprintf(buf, "rsn_ie=");
 289                        for (i = 0; i < rsn_len; i++) {
 290                                n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
 291                                                        "%02x", rsn_ie[i]);
 292                                if (n >= MAX_WPA_IE_LEN)
 293                                        break;
 294                        }
 295                        memset(&iwe, 0, sizeof(iwe));
 296                        iwe.cmd = IWEVCUSTOM;
 297                        iwe.u.data.length = strlen(buf);
 298                        start = iwe_stream_add_point(info, start, stop,
 299                                &iwe, buf);
 300                        memset(&iwe, 0, sizeof(iwe));
 301                        iwe.cmd = IWEVGENIE;
 302                        iwe.u.data.length = rsn_len;
 303                        start = iwe_stream_add_point(info, start, stop, &iwe,
 304                                rsn_ie);
 305                }
 306        }
 307
 308        { /* parsing WPS IE */
 309                u8 wps_ie[512];
 310                uint wps_ielen;
 311
 312                if (r8712_get_wps_ie(pnetwork->network.IEs,
 313                    pnetwork->network.IELength,
 314                    wps_ie, &wps_ielen)) {
 315                        if (wps_ielen > 2) {
 316                                iwe.cmd = IWEVGENIE;
 317                                iwe.u.data.length = (u16)wps_ielen;
 318                                start = iwe_stream_add_point(info, start, stop,
 319                                        &iwe, wps_ie);
 320                        }
 321                }
 322        }
 323        /* Add quality statistics */
 324        iwe.cmd = IWEVQUAL;
 325        rssi = r8712_signal_scale_mapping(pnetwork->network.Rssi);
 326        /* we only update signal_level (signal strength) that is rssi. */
 327        iwe.u.qual.updated = (u8)(IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED |
 328                                  IW_QUAL_NOISE_INVALID);
 329        iwe.u.qual.level = rssi;  /* signal strength */
 330        iwe.u.qual.qual = 0; /* signal quality */
 331        iwe.u.qual.noise = 0; /* noise level */
 332        start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
 333        /* how to translate rssi to ?% */
 334        return start;
 335}
 336
 337static int wpa_set_auth_algs(struct net_device *dev, u32 value)
 338{
 339        struct _adapter *padapter = netdev_priv(dev);
 340        int ret = 0;
 341
 342        if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) {
 343                padapter->securitypriv.ndisencryptstatus =
 344                                                 Ndis802_11Encryption1Enabled;
 345                padapter->securitypriv.ndisauthtype =
 346                                                 Ndis802_11AuthModeAutoSwitch;
 347                padapter->securitypriv.AuthAlgrthm = 3;
 348        } else if (value & AUTH_ALG_SHARED_KEY) {
 349                padapter->securitypriv.ndisencryptstatus =
 350                                                 Ndis802_11Encryption1Enabled;
 351                padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared;
 352                padapter->securitypriv.AuthAlgrthm = 1;
 353        } else if (value & AUTH_ALG_OPEN_SYSTEM) {
 354                if (padapter->securitypriv.ndisauthtype <
 355                                                 Ndis802_11AuthModeWPAPSK) {
 356                        padapter->securitypriv.ndisauthtype =
 357                                                 Ndis802_11AuthModeOpen;
 358                        padapter->securitypriv.AuthAlgrthm = 0;
 359                }
 360        } else {
 361                ret = -EINVAL;
 362        }
 363        return ret;
 364}
 365
 366static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
 367                              u32 param_len)
 368{
 369        int ret = 0;
 370        u32 wep_key_idx, wep_key_len = 0;
 371        struct NDIS_802_11_WEP   *pwep = NULL;
 372        struct _adapter *padapter = netdev_priv(dev);
 373        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 374        struct security_priv *psecuritypriv = &padapter->securitypriv;
 375
 376        param->u.crypt.err = 0;
 377        param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
 378        if (param_len != (u32)((u8 *) param->u.crypt.key - (u8 *)param) +
 379                         param->u.crypt.key_len)
 380                return -EINVAL;
 381        if (is_broadcast_ether_addr(param->sta_addr)) {
 382                if (param->u.crypt.idx >= WEP_KEYS) {
 383                        /* for large key indices, set the default (0) */
 384                        param->u.crypt.idx = 0;
 385                }
 386        } else {
 387                return -EINVAL;
 388        }
 389        if (strcmp(param->u.crypt.alg, "WEP") == 0) {
 390                netdev_info(dev, "r8712u: %s: crypt.alg = WEP\n", __func__);
 391                padapter->securitypriv.ndisencryptstatus =
 392                             Ndis802_11Encryption1Enabled;
 393                padapter->securitypriv.PrivacyAlgrthm = _WEP40_;
 394                padapter->securitypriv.XGrpPrivacy = _WEP40_;
 395                wep_key_idx = param->u.crypt.idx;
 396                wep_key_len = param->u.crypt.key_len;
 397                if (wep_key_idx >= WEP_KEYS)
 398                        wep_key_idx = 0;
 399                if (wep_key_len > 0) {
 400                        wep_key_len = wep_key_len <= 5 ? 5 : 13;
 401                        pwep = kzalloc(sizeof(*pwep), GFP_ATOMIC);
 402                        if (pwep == NULL)
 403                                return -ENOMEM;
 404                        pwep->KeyLength = wep_key_len;
 405                        pwep->Length = wep_key_len +
 406                                 FIELD_OFFSET(struct NDIS_802_11_WEP,
 407                                 KeyMaterial);
 408                        if (wep_key_len == 13) {
 409                                padapter->securitypriv.PrivacyAlgrthm =
 410                                         _WEP104_;
 411                                padapter->securitypriv.XGrpPrivacy =
 412                                         _WEP104_;
 413                        }
 414                } else {
 415                        return -EINVAL;
 416                }
 417                pwep->KeyIndex = wep_key_idx;
 418                pwep->KeyIndex |= 0x80000000;
 419                memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength);
 420                if (param->u.crypt.set_tx) {
 421                        if (r8712_set_802_11_add_wep(padapter, pwep) ==
 422                            (u8)_FAIL)
 423                                ret = -EOPNOTSUPP;
 424                } else {
 425                        /* don't update "psecuritypriv->PrivacyAlgrthm" and
 426                         * "psecuritypriv->PrivacyKeyIndex=keyid", but can
 427                         * r8712_set_key to fw/cam
 428                         */
 429                        if (wep_key_idx >= WEP_KEYS) {
 430                                ret = -EOPNOTSUPP;
 431                                goto exit;
 432                        }
 433                        memcpy(&(psecuritypriv->DefKey[wep_key_idx].
 434                                skey[0]), pwep->KeyMaterial,
 435                                pwep->KeyLength);
 436                        psecuritypriv->DefKeylen[wep_key_idx] =
 437                                pwep->KeyLength;
 438                        r8712_set_key(padapter, psecuritypriv, wep_key_idx);
 439                }
 440                goto exit;
 441        }
 442        if (padapter->securitypriv.AuthAlgrthm == 2) { /* 802_1x */
 443                struct sta_info *psta, *pbcmc_sta;
 444                struct sta_priv *pstapriv = &padapter->stapriv;
 445
 446                if (check_fwstate(pmlmepriv, WIFI_STATION_STATE |
 447                    WIFI_MP_STATE)) { /* sta mode */
 448                        psta = r8712_get_stainfo(pstapriv,
 449                                                 get_bssid(pmlmepriv));
 450                        if (psta) {
 451                                psta->ieee8021x_blocked = false;
 452                                if ((padapter->securitypriv.ndisencryptstatus ==
 453                                    Ndis802_11Encryption2Enabled) ||
 454                                    (padapter->securitypriv.ndisencryptstatus ==
 455                                    Ndis802_11Encryption3Enabled))
 456                                        psta->XPrivacy = padapter->
 457                                            securitypriv.PrivacyAlgrthm;
 458                                if (param->u.crypt.set_tx == 1)
 459                                        handle_pairwise_key(psta, param,
 460                                                            padapter);
 461                                else /* group key */
 462                                        handle_group_key(param, padapter);
 463                        }
 464                        pbcmc_sta = r8712_get_bcmc_stainfo(padapter);
 465                        if (pbcmc_sta) {
 466                                pbcmc_sta->ieee8021x_blocked = false;
 467                                if ((padapter->securitypriv.ndisencryptstatus ==
 468                                    Ndis802_11Encryption2Enabled) ||
 469                                    (padapter->securitypriv.ndisencryptstatus ==
 470                                    Ndis802_11Encryption3Enabled))
 471                                        pbcmc_sta->XPrivacy =
 472                                          padapter->securitypriv.
 473                                          PrivacyAlgrthm;
 474                        }
 475                }
 476        }
 477exit:
 478        kfree(pwep);
 479        return ret;
 480}
 481
 482static int r871x_set_wpa_ie(struct _adapter *padapter, char *pie,
 483                            unsigned short ielen)
 484{
 485        u8 *buf = NULL;
 486        int group_cipher = 0, pairwise_cipher = 0;
 487        int ret = 0;
 488
 489        if ((ielen > MAX_WPA_IE_LEN) || (pie == NULL))
 490                return -EINVAL;
 491        if (ielen) {
 492                buf = kmemdup(pie, ielen, GFP_ATOMIC);
 493                if (buf == NULL)
 494                        return -ENOMEM;
 495                if (ielen < RSN_HEADER_LEN) {
 496                        ret  = -EINVAL;
 497                        goto exit;
 498                }
 499                if (r8712_parse_wpa_ie(buf, ielen, &group_cipher,
 500                    &pairwise_cipher) == _SUCCESS) {
 501                        padapter->securitypriv.AuthAlgrthm = 2;
 502                        padapter->securitypriv.ndisauthtype =
 503                                  Ndis802_11AuthModeWPAPSK;
 504                }
 505                if (r8712_parse_wpa2_ie(buf, ielen, &group_cipher,
 506                    &pairwise_cipher) == _SUCCESS) {
 507                        padapter->securitypriv.AuthAlgrthm = 2;
 508                        padapter->securitypriv.ndisauthtype =
 509                                  Ndis802_11AuthModeWPA2PSK;
 510                }
 511                switch (group_cipher) {
 512                case WPA_CIPHER_NONE:
 513                        padapter->securitypriv.XGrpPrivacy =
 514                                 _NO_PRIVACY_;
 515                        padapter->securitypriv.ndisencryptstatus =
 516                                 Ndis802_11EncryptionDisabled;
 517                        break;
 518                case WPA_CIPHER_WEP40:
 519                        padapter->securitypriv.XGrpPrivacy = _WEP40_;
 520                        padapter->securitypriv.ndisencryptstatus =
 521                                 Ndis802_11Encryption1Enabled;
 522                        break;
 523                case WPA_CIPHER_TKIP:
 524                        padapter->securitypriv.XGrpPrivacy = _TKIP_;
 525                        padapter->securitypriv.ndisencryptstatus =
 526                                 Ndis802_11Encryption2Enabled;
 527                        break;
 528                case WPA_CIPHER_CCMP:
 529                        padapter->securitypriv.XGrpPrivacy = _AES_;
 530                        padapter->securitypriv.ndisencryptstatus =
 531                                 Ndis802_11Encryption3Enabled;
 532                        break;
 533                case WPA_CIPHER_WEP104:
 534                        padapter->securitypriv.XGrpPrivacy = _WEP104_;
 535                        padapter->securitypriv.ndisencryptstatus =
 536                                 Ndis802_11Encryption1Enabled;
 537                        break;
 538                }
 539                switch (pairwise_cipher) {
 540                case WPA_CIPHER_NONE:
 541                        padapter->securitypriv.PrivacyAlgrthm =
 542                                 _NO_PRIVACY_;
 543                        padapter->securitypriv.ndisencryptstatus =
 544                                 Ndis802_11EncryptionDisabled;
 545                        break;
 546                case WPA_CIPHER_WEP40:
 547                        padapter->securitypriv.PrivacyAlgrthm = _WEP40_;
 548                        padapter->securitypriv.ndisencryptstatus =
 549                                 Ndis802_11Encryption1Enabled;
 550                        break;
 551                case WPA_CIPHER_TKIP:
 552                        padapter->securitypriv.PrivacyAlgrthm = _TKIP_;
 553                        padapter->securitypriv.ndisencryptstatus =
 554                                 Ndis802_11Encryption2Enabled;
 555                        break;
 556                case WPA_CIPHER_CCMP:
 557                        padapter->securitypriv.PrivacyAlgrthm = _AES_;
 558                        padapter->securitypriv.ndisencryptstatus =
 559                                 Ndis802_11Encryption3Enabled;
 560                        break;
 561                case WPA_CIPHER_WEP104:
 562                        padapter->securitypriv.PrivacyAlgrthm = _WEP104_;
 563                        padapter->securitypriv.ndisencryptstatus =
 564                                 Ndis802_11Encryption1Enabled;
 565                        break;
 566                }
 567                padapter->securitypriv.wps_phase = false;
 568                {/* set wps_ie */
 569                        u16 cnt = 0;
 570                        u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
 571
 572                        while (cnt < ielen) {
 573                                eid = buf[cnt];
 574
 575                                if ((eid == _VENDOR_SPECIFIC_IE_) &&
 576                                    (!memcmp(&buf[cnt + 2], wps_oui, 4))) {
 577                                        netdev_info(padapter->pnetdev, "r8712u: SET WPS_IE\n");
 578                                        padapter->securitypriv.wps_ie_len =
 579                                            ((buf[cnt + 1] + 2) <
 580                                            (MAX_WPA_IE_LEN << 2)) ?
 581                                            (buf[cnt + 1] + 2) :
 582                                            (MAX_WPA_IE_LEN << 2);
 583                                        memcpy(padapter->securitypriv.wps_ie,
 584                                            &buf[cnt],
 585                                            padapter->securitypriv.wps_ie_len);
 586                                        padapter->securitypriv.wps_phase =
 587                                                                 true;
 588                                        netdev_info(padapter->pnetdev, "r8712u: SET WPS_IE, wps_phase==true\n");
 589                                        cnt += buf[cnt + 1] + 2;
 590                                        break;
 591                                } else {
 592                                        cnt += buf[cnt + 1] + 2;
 593                                }
 594                        }
 595                }
 596        }
 597exit:
 598        kfree(buf);
 599        return ret;
 600}
 601
 602static int r8711_wx_get_name(struct net_device *dev,
 603                             struct iw_request_info *info,
 604                             union iwreq_data *wrqu, char *extra)
 605{
 606        struct _adapter *padapter = netdev_priv(dev);
 607        u32 ht_ielen = 0;
 608        char *p;
 609        u8 ht_cap = false;
 610        struct  mlme_priv       *pmlmepriv = &(padapter->mlmepriv);
 611        struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
 612        u8 *prates;
 613
 614        if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE) ==
 615            true) {
 616                /* parsing HT_CAP_IE */
 617                p = r8712_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_,
 618                                 &ht_ielen, pcur_bss->IELength - 12);
 619                if (p && ht_ielen > 0)
 620                        ht_cap = true;
 621                prates = pcur_bss->rates;
 622                if (r8712_is_cckratesonly_included(prates)) {
 623                        if (ht_cap)
 624                                snprintf(wrqu->name, IFNAMSIZ,
 625                                         "IEEE 802.11bn");
 626                        else
 627                                snprintf(wrqu->name, IFNAMSIZ,
 628                                         "IEEE 802.11b");
 629                } else if (r8712_is_cckrates_included(prates)) {
 630                        if (ht_cap)
 631                                snprintf(wrqu->name, IFNAMSIZ,
 632                                         "IEEE 802.11bgn");
 633                        else
 634                                snprintf(wrqu->name, IFNAMSIZ,
 635                                         "IEEE 802.11bg");
 636                } else {
 637                        if (ht_cap)
 638                                snprintf(wrqu->name, IFNAMSIZ,
 639                                         "IEEE 802.11gn");
 640                        else
 641                                snprintf(wrqu->name, IFNAMSIZ,
 642                                         "IEEE 802.11g");
 643                }
 644        } else {
 645                snprintf(wrqu->name, IFNAMSIZ, "unassociated");
 646        }
 647        return 0;
 648}
 649
 650static const long frequency_list[] = {
 651        2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462,
 652        2467, 2472, 2484, 4915, 4920, 4925, 4935, 4940, 4945, 4960, 4980,
 653        5035, 5040, 5045, 5055, 5060, 5080, 5170, 5180, 5190, 5200, 5210,
 654        5220, 5230, 5240, 5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560,
 655        5580, 5600, 5620, 5640, 5660, 5680, 5700, 5745, 5765, 5785, 5805,
 656        5825
 657};
 658
 659static int r8711_wx_set_freq(struct net_device *dev,
 660                             struct iw_request_info *info,
 661                             union iwreq_data *wrqu, char *extra)
 662{
 663        struct _adapter *padapter = netdev_priv(dev);
 664        struct iw_freq *fwrq = &wrqu->freq;
 665        int rc = 0;
 666
 667/* If setting by frequency, convert to a channel */
 668        if ((fwrq->e == 1) &&
 669          (fwrq->m >= (int) 2.412e8) &&
 670          (fwrq->m <= (int) 2.487e8)) {
 671                int f = fwrq->m / 100000;
 672                int c = 0;
 673
 674                while ((c < 14) && (f != frequency_list[c]))
 675                        c++;
 676                fwrq->e = 0;
 677                fwrq->m = c + 1;
 678        }
 679        /* Setting by channel number */
 680        if ((fwrq->m > 14) || (fwrq->e > 0)) {
 681                rc = -EOPNOTSUPP;
 682        } else {
 683                int channel = fwrq->m;
 684
 685                if ((channel < 1) || (channel > 14)) {
 686                        rc = -EINVAL;
 687                } else {
 688                        /* Yes ! We can set it !!! */
 689                        padapter->registrypriv.channel = channel;
 690                }
 691        }
 692        return rc;
 693}
 694
 695static int r8711_wx_get_freq(struct net_device *dev,
 696                             struct iw_request_info *info,
 697                             union iwreq_data *wrqu, char *extra)
 698{
 699        struct _adapter *padapter = netdev_priv(dev);
 700        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 701        struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
 702
 703        if (check_fwstate(pmlmepriv, _FW_LINKED)) {
 704                wrqu->freq.m = ieee80211_wlan_frequencies[
 705                               pcur_bss->Configuration.DSConfig - 1] * 100000;
 706                wrqu->freq.e = 1;
 707                wrqu->freq.i = pcur_bss->Configuration.DSConfig;
 708        } else {
 709                return -ENOLINK;
 710        }
 711        return 0;
 712}
 713
 714static int r8711_wx_set_mode(struct net_device *dev,
 715                             struct iw_request_info *a,
 716                             union iwreq_data *wrqu, char *b)
 717{
 718        struct _adapter *padapter = netdev_priv(dev);
 719        enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType;
 720
 721        switch (wrqu->mode) {
 722        case IW_MODE_AUTO:
 723                networkType = Ndis802_11AutoUnknown;
 724                break;
 725        case IW_MODE_ADHOC:
 726                networkType = Ndis802_11IBSS;
 727                break;
 728        case IW_MODE_MASTER:
 729                networkType = Ndis802_11APMode;
 730                break;
 731        case IW_MODE_INFRA:
 732                networkType = Ndis802_11Infrastructure;
 733                break;
 734        default:
 735                return -EINVAL;
 736        }
 737        if (Ndis802_11APMode == networkType)
 738                r8712_setopmode_cmd(padapter, networkType);
 739        else
 740                r8712_setopmode_cmd(padapter, Ndis802_11AutoUnknown);
 741
 742        r8712_set_802_11_infrastructure_mode(padapter, networkType);
 743        return 0;
 744}
 745
 746static int r8711_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
 747                             union iwreq_data *wrqu, char *b)
 748{
 749        struct _adapter *padapter = netdev_priv(dev);
 750        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 751
 752        if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
 753                wrqu->mode = IW_MODE_INFRA;
 754        else if (check_fwstate(pmlmepriv,
 755                 WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE))
 756                wrqu->mode = IW_MODE_ADHOC;
 757        else if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
 758                wrqu->mode = IW_MODE_MASTER;
 759        else
 760                wrqu->mode = IW_MODE_AUTO;
 761        return 0;
 762}
 763
 764static int r871x_wx_set_pmkid(struct net_device *dev,
 765                             struct iw_request_info *a,
 766                             union iwreq_data *wrqu, char *extra)
 767{
 768        struct _adapter *padapter = netdev_priv(dev);
 769        struct security_priv *psecuritypriv = &padapter->securitypriv;
 770        struct iw_pmksa *pPMK = (struct iw_pmksa *) extra;
 771        u8 strZeroMacAddress[ETH_ALEN] = {0x00};
 772        u8 strIssueBssid[ETH_ALEN] = {0x00};
 773        u8 j, blInserted = false;
 774        int intReturn = false;
 775
 776/*
 777 *      There are the BSSID information in the bssid.sa_data array.
 778 *      If cmd is IW_PMKSA_FLUSH, it means the wpa_supplicant wants to clear
 779 *      all the PMKID information. If cmd is IW_PMKSA_ADD, it means the
 780 *      wpa_supplicant wants to add a PMKID/BSSID to driver.
 781 *      If cmd is IW_PMKSA_REMOVE, it means the wpa_supplicant wants to
 782 *      remove a PMKID/BSSID from driver.
 783 */
 784        if (pPMK == NULL)
 785                return -EINVAL;
 786        memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN);
 787        switch (pPMK->cmd) {
 788        case IW_PMKSA_ADD:
 789                if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN))
 790                        return intReturn;
 791                intReturn = true;
 792                blInserted = false;
 793                /* overwrite PMKID */
 794                for (j = 0; j < NUM_PMKID_CACHE; j++) {
 795                        if (!memcmp(psecuritypriv->PMKIDList[j].Bssid,
 796                            strIssueBssid, ETH_ALEN)) {
 797                                /* BSSID is matched, the same AP => rewrite
 798                                 * with new PMKID.
 799                                 */
 800                                netdev_info(dev, "r8712u: %s: BSSID exists in the PMKList.\n",
 801                                            __func__);
 802                                memcpy(psecuritypriv->PMKIDList[j].PMKID,
 803                                        pPMK->pmkid, IW_PMKID_LEN);
 804                                psecuritypriv->PMKIDList[j].bUsed = true;
 805                                psecuritypriv->PMKIDIndex = j + 1;
 806                                blInserted = true;
 807                                break;
 808                        }
 809                }
 810                if (!blInserted) {
 811                        /* Find a new entry */
 812                        netdev_info(dev, "r8712u: %s: Use the new entry index = %d for this PMKID.\n",
 813                                    __func__, psecuritypriv->PMKIDIndex);
 814                        memcpy(psecuritypriv->PMKIDList[psecuritypriv->
 815                                PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN);
 816                        memcpy(psecuritypriv->PMKIDList[psecuritypriv->
 817                                PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN);
 818                        psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].
 819                                bUsed = true;
 820                        psecuritypriv->PMKIDIndex++;
 821                        if (psecuritypriv->PMKIDIndex == NUM_PMKID_CACHE)
 822                                psecuritypriv->PMKIDIndex = 0;
 823                }
 824                break;
 825        case IW_PMKSA_REMOVE:
 826                intReturn = true;
 827                for (j = 0; j < NUM_PMKID_CACHE; j++) {
 828                        if (!memcmp(psecuritypriv->PMKIDList[j].Bssid,
 829                            strIssueBssid, ETH_ALEN)) {
 830                                /* BSSID is matched, the same AP => Remove
 831                                 * this PMKID information and reset it.
 832                                 */
 833                                eth_zero_addr(psecuritypriv->PMKIDList[j].Bssid);
 834                                psecuritypriv->PMKIDList[j].bUsed = false;
 835                                break;
 836                        }
 837                }
 838                break;
 839        case IW_PMKSA_FLUSH:
 840                memset(psecuritypriv->PMKIDList, 0,
 841                        sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE);
 842                psecuritypriv->PMKIDIndex = 0;
 843                intReturn = true;
 844                break;
 845        default:
 846                netdev_info(dev, "r8712u: %s: unknown Command\n", __func__);
 847                intReturn = false;
 848                break;
 849        }
 850        return intReturn;
 851}
 852
 853static int r8711_wx_get_sens(struct net_device *dev,
 854                             struct iw_request_info *info,
 855                             union iwreq_data *wrqu, char *extra)
 856{
 857        wrqu->sens.value = 0;
 858        wrqu->sens.fixed = 0;   /* no auto select */
 859        wrqu->sens.disabled = 1;
 860        return 0;
 861}
 862
 863static int r8711_wx_get_range(struct net_device *dev,
 864                                struct iw_request_info *info,
 865                                union iwreq_data *wrqu, char *extra)
 866{
 867        struct iw_range *range = (struct iw_range *)extra;
 868        u16 val;
 869        int i;
 870
 871        wrqu->data.length = sizeof(*range);
 872        memset(range, 0, sizeof(*range));
 873        /* Let's try to keep this struct in the same order as in
 874         * linux/include/wireless.h
 875         */
 876
 877        /* TODO: See what values we can set, and remove the ones we can't
 878         * set, or fill them with some default data.
 879         */
 880        /* ~5 Mb/s real (802.11b) */
 881        range->throughput = 5 * 1000 * 1000;
 882        /* TODO: 8711 sensitivity ? */
 883        /* signal level threshold range */
 884        /* percent values between 0 and 100. */
 885        range->max_qual.qual = 100;
 886        range->max_qual.level = 100;
 887        range->max_qual.noise = 100;
 888        range->max_qual.updated = 7; /* Updated all three */
 889        range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
 890        /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
 891        range->avg_qual.level = 0x100 - 78;
 892        range->avg_qual.noise = 0;
 893        range->avg_qual.updated = 7; /* Updated all three */
 894        range->num_bitrates = RATE_COUNT;
 895        for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++)
 896                range->bitrate[i] = rtl8180_rates[i];
 897        range->min_frag = MIN_FRAG_THRESHOLD;
 898        range->max_frag = MAX_FRAG_THRESHOLD;
 899        range->pm_capa = 0;
 900        range->we_version_compiled = WIRELESS_EXT;
 901        range->we_version_source = 16;
 902        range->num_channels = 14;
 903        for (i = 0, val = 0; i < 14; i++) {
 904                /* Include only legal frequencies for some countries */
 905                range->freq[val].i = i + 1;
 906                range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000;
 907                range->freq[val].e = 1;
 908                val++;
 909                if (val == IW_MAX_FREQUENCIES)
 910                        break;
 911        }
 912        range->num_frequency = val;
 913        range->enc_capa = IW_ENC_CAPA_WPA |
 914                          IW_ENC_CAPA_WPA2 |
 915                          IW_ENC_CAPA_CIPHER_TKIP |
 916                          IW_ENC_CAPA_CIPHER_CCMP;
 917        return 0;
 918}
 919
 920static int r8711_wx_get_rate(struct net_device *dev,
 921                             struct iw_request_info *info,
 922                             union iwreq_data *wrqu, char *extra);
 923
 924static int r871x_wx_set_priv(struct net_device *dev,
 925                                struct iw_request_info *info,
 926                                union iwreq_data *awrq,
 927                                char *extra)
 928{
 929        int ret = 0, len = 0;
 930        char *ext;
 931        struct _adapter *padapter = netdev_priv(dev);
 932        struct iw_point *dwrq = (struct iw_point *)awrq;
 933
 934        len = dwrq->length;
 935        ext = memdup_user(dwrq->pointer, len);
 936        if (IS_ERR(ext))
 937                return PTR_ERR(ext);
 938
 939        if (!strcasecmp(ext, "RSSI")) {
 940                /*Return received signal strength indicator in -db for */
 941                /* current AP */
 942                /*<ssid> Rssi xx */
 943                struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
 944                struct wlan_network *pcur_network = &pmlmepriv->cur_network;
 945                /*static u8 xxxx; */
 946                if (check_fwstate(pmlmepriv, _FW_LINKED)) {
 947                        sprintf(ext, "%s rssi %d",
 948                                pcur_network->network.Ssid.Ssid,
 949                                /*(xxxx=xxxx+10) */
 950                                ((padapter->recvpriv.fw_rssi) >> 1) - 95
 951                                /*pcur_network->network.Rssi */
 952                                );
 953                } else {
 954                        sprintf(ext, "OK");
 955                }
 956        } else if (!strcasecmp(ext, "LINKSPEED")) {
 957                /*Return link speed in MBPS */
 958                /*LinkSpeed xx */
 959                union iwreq_data wrqd;
 960                int ret_inner;
 961                int mbps;
 962
 963                ret_inner = r8711_wx_get_rate(dev, info, &wrqd, extra);
 964                if (ret_inner != 0)
 965                        mbps = 0;
 966                else
 967                        mbps = wrqd.bitrate.value / 1000000;
 968                sprintf(ext, "LINKSPEED %d", mbps);
 969        } else if (!strcasecmp(ext, "MACADDR")) {
 970                /*Return mac address of the station */
 971                /* Macaddr = xx:xx:xx:xx:xx:xx */
 972                sprintf(ext, "MACADDR = %pM", dev->dev_addr);
 973        } else if (!strcasecmp(ext, "SCAN-ACTIVE")) {
 974                /*Set scan type to active */
 975                /*OK if successful */
 976                struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 977
 978                pmlmepriv->passive_mode = 1;
 979                sprintf(ext, "OK");
 980        } else if (!strcasecmp(ext, "SCAN-PASSIVE")) {
 981                /*Set scan type to passive */
 982                /*OK if successful */
 983                struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 984
 985                pmlmepriv->passive_mode = 0;
 986                sprintf(ext, "OK");
 987        } else if (!strncmp(ext, "DCE-E", 5)) {
 988                /*Set scan type to passive */
 989                /*OK if successful */
 990                r8712_disconnectCtrlEx_cmd(padapter
 991                        , 1 /*u32 enableDrvCtrl */
 992                        , 5 /*u32 tryPktCnt */
 993                        , 100 /*u32 tryPktInterval */
 994                        , 5000 /*u32 firstStageTO */
 995                );
 996                sprintf(ext, "OK");
 997        } else if (!strncmp(ext, "DCE-D", 5)) {
 998                /*Set scan type to passive */
 999                /*OK if successfu */
1000                r8712_disconnectCtrlEx_cmd(padapter
1001                        , 0 /*u32 enableDrvCtrl */
1002                        , 5 /*u32 tryPktCnt */
1003                        , 100 /*u32 tryPktInterval */
1004                        , 5000 /*u32 firstStageTO */
1005                );
1006                sprintf(ext, "OK");
1007        } else {
1008                netdev_info(dev, "r8712u: %s: unknown Command %s.\n",
1009                            __func__, ext);
1010                goto FREE_EXT;
1011        }
1012        if (copy_to_user(dwrq->pointer, ext,
1013                                min(dwrq->length, (__u16)(strlen(ext) + 1))))
1014                ret = -EFAULT;
1015
1016FREE_EXT:
1017        kfree(ext);
1018        return ret;
1019}
1020
1021/* set bssid flow
1022 * s1. set_802_11_infrastructure_mode()
1023 * s2. set_802_11_authentication_mode()
1024 * s3. set_802_11_encryption_mode()
1025 * s4. set_802_11_bssid()
1026 *
1027 * This function intends to handle the Set AP command, which specifies the
1028 * MAC# of a preferred Access Point.
1029 * Currently, the request comes via Wireless Extensions' SIOCSIWAP ioctl.
1030 *
1031 * For this operation to succeed, there is no need for the interface to be up.
1032 *
1033 */
1034static int r8711_wx_set_wap(struct net_device *dev,
1035                         struct iw_request_info *info,
1036                         union iwreq_data *awrq,
1037                         char *extra)
1038{
1039        int ret = -EINPROGRESS;
1040        struct _adapter *padapter = netdev_priv(dev);
1041        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1042        struct  __queue *queue = &pmlmepriv->scanned_queue;
1043        struct sockaddr *temp = (struct sockaddr *)awrq;
1044        unsigned long irqL;
1045        struct list_head *phead;
1046        u8 *dst_bssid;
1047        struct wlan_network *pnetwork = NULL;
1048        enum NDIS_802_11_AUTHENTICATION_MODE    authmode;
1049
1050        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
1051                return -EBUSY;
1052        if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
1053                return ret;
1054        if (temp->sa_family != ARPHRD_ETHER)
1055                return -EINVAL;
1056        authmode = padapter->securitypriv.ndisauthtype;
1057        spin_lock_irqsave(&queue->lock, irqL);
1058        phead = &queue->queue;
1059        pmlmepriv->pscanned = phead->next;
1060        while (1) {
1061                if (end_of_queue_search(phead, pmlmepriv->pscanned))
1062                        break;
1063                pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned,
1064                           struct wlan_network, list);
1065                pmlmepriv->pscanned = pmlmepriv->pscanned->next;
1066                dst_bssid = pnetwork->network.MacAddress;
1067                if (!memcmp(dst_bssid, temp->sa_data, ETH_ALEN)) {
1068                        r8712_set_802_11_infrastructure_mode(padapter,
1069                            pnetwork->network.InfrastructureMode);
1070                        break;
1071                }
1072        }
1073        spin_unlock_irqrestore(&queue->lock, irqL);
1074        if (!ret) {
1075                if (!r8712_set_802_11_authentication_mode(padapter, authmode)) {
1076                        ret = -ENOMEM;
1077                } else {
1078                        if (!r8712_set_802_11_bssid(padapter, temp->sa_data))
1079                                ret = -1;
1080                }
1081        }
1082        return ret;
1083}
1084
1085static int r8711_wx_get_wap(struct net_device *dev,
1086                                struct iw_request_info *info,
1087                                union iwreq_data *wrqu, char *extra)
1088{
1089        struct _adapter *padapter = netdev_priv(dev);
1090        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1091        struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
1092
1093        wrqu->ap_addr.sa_family = ARPHRD_ETHER;
1094        if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE |
1095                                     WIFI_AP_STATE))
1096                ether_addr_copy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress);
1097        else
1098                eth_zero_addr(wrqu->ap_addr.sa_data);
1099        return 0;
1100}
1101
1102static int r871x_wx_set_mlme(struct net_device *dev,
1103                             struct iw_request_info *info,
1104                             union iwreq_data *wrqu, char *extra)
1105{
1106        int ret = 0;
1107        struct _adapter *padapter = netdev_priv(dev);
1108        struct iw_mlme *mlme = (struct iw_mlme *) extra;
1109
1110        if (mlme == NULL)
1111                return -1;
1112        switch (mlme->cmd) {
1113        case IW_MLME_DEAUTH:
1114                if (!r8712_set_802_11_disassociate(padapter))
1115                        ret = -1;
1116                break;
1117        case IW_MLME_DISASSOC:
1118                if (!r8712_set_802_11_disassociate(padapter))
1119                        ret = -1;
1120                break;
1121        default:
1122                return -EOPNOTSUPP;
1123        }
1124        return ret;
1125}
1126
1127/**
1128 *
1129 * This function intends to handle the Set Scan command.
1130 * Currently, the request comes via Wireless Extensions' SIOCSIWSCAN ioctl.
1131 *
1132 * For this operation to succeed, the interface is brought Up beforehand.
1133 *
1134 */
1135static int r8711_wx_set_scan(struct net_device *dev,
1136                        struct iw_request_info *a,
1137                        union iwreq_data *wrqu, char *extra)
1138{
1139        struct _adapter *padapter = netdev_priv(dev);
1140        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1141        u8 status = true;
1142
1143        if (padapter->bDriverStopped) {
1144                netdev_info(dev, "In %s: bDriverStopped=%d\n",
1145                            __func__, padapter->bDriverStopped);
1146                return -1;
1147        }
1148        if (!padapter->bup)
1149                return -ENETDOWN;
1150        if (!padapter->hw_init_completed)
1151                return -1;
1152        if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING)) ||
1153            (pmlmepriv->sitesurveyctrl.traffic_busy))
1154                return 0;
1155        if (wrqu->data.length == sizeof(struct iw_scan_req)) {
1156                struct iw_scan_req *req = (struct iw_scan_req *)extra;
1157
1158                if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
1159                        struct ndis_802_11_ssid ssid;
1160                        unsigned long irqL;
1161                        u32 len = min_t(u8, req->essid_len, IW_ESSID_MAX_SIZE);
1162
1163                        memset((unsigned char *)&ssid, 0,
1164                                 sizeof(struct ndis_802_11_ssid));
1165                        memcpy(ssid.Ssid, req->essid, len);
1166                        ssid.SsidLength = len;
1167                        spin_lock_irqsave(&pmlmepriv->lock, irqL);
1168                        if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY |
1169                             _FW_UNDER_LINKING)) ||
1170                            (pmlmepriv->sitesurveyctrl.traffic_busy)) {
1171                                if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
1172                                        status = false;
1173                        } else {
1174                                status = r8712_sitesurvey_cmd(padapter, &ssid);
1175                        }
1176                        spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
1177                }
1178        } else {
1179                status = r8712_set_802_11_bssid_list_scan(padapter);
1180        }
1181        if (!status)
1182                return -1;
1183        return 0;
1184}
1185
1186static int r8711_wx_get_scan(struct net_device *dev,
1187                                struct iw_request_info *a,
1188                                union iwreq_data *wrqu, char *extra)
1189{
1190        struct _adapter *padapter = netdev_priv(dev);
1191        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1192        struct  __queue *queue = &pmlmepriv->scanned_queue;
1193        struct wlan_network *pnetwork = NULL;
1194        unsigned long irqL;
1195        struct list_head *plist, *phead;
1196        char *ev = extra;
1197        char *stop = ev + wrqu->data.length;
1198        u32 ret = 0, cnt = 0;
1199
1200        if (padapter->bDriverStopped)
1201                return -EINVAL;
1202        while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY |
1203                             _FW_UNDER_LINKING)) {
1204                msleep(30);
1205                cnt++;
1206                if (cnt > 100)
1207                        break;
1208        }
1209        spin_lock_irqsave(&queue->lock, irqL);
1210        phead = &queue->queue;
1211        plist = phead->next;
1212        while (1) {
1213                if (end_of_queue_search(phead, plist))
1214                        break;
1215                if ((stop - ev) < SCAN_ITEM_SIZE) {
1216                        ret = -E2BIG;
1217                        break;
1218                }
1219                pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
1220                ev = translate_scan(padapter, a, pnetwork, ev, stop);
1221                plist = plist->next;
1222        }
1223        spin_unlock_irqrestore(&queue->lock, irqL);
1224        wrqu->data.length = ev - extra;
1225        wrqu->data.flags = 0;
1226        return ret;
1227}
1228
1229/* set ssid flow
1230 * s1. set_802_11_infrastructure_mode()
1231 * s2. set_802_11_authenticaion_mode()
1232 * s3. set_802_11_encryption_mode()
1233 * s4. set_802_11_ssid()
1234 *
1235 * This function intends to handle the Set ESSID command.
1236 * Currently, the request comes via the Wireless Extensions' SIOCSIWESSID ioctl.
1237 *
1238 * For this operation to succeed, there is no need for the interface to be Up.
1239 *
1240 */
1241static int r8711_wx_set_essid(struct net_device *dev,
1242                                struct iw_request_info *a,
1243                                union iwreq_data *wrqu, char *extra)
1244{
1245        struct _adapter *padapter = netdev_priv(dev);
1246        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1247        struct  __queue *queue = &pmlmepriv->scanned_queue;
1248        struct wlan_network *pnetwork = NULL;
1249        enum NDIS_802_11_AUTHENTICATION_MODE    authmode;
1250        struct ndis_802_11_ssid ndis_ssid;
1251        u8 *dst_ssid, *src_ssid;
1252        struct list_head *phead;
1253        u32 len;
1254
1255        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
1256                return -EBUSY;
1257        if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
1258                return 0;
1259        if (wrqu->essid.length > IW_ESSID_MAX_SIZE)
1260                return -E2BIG;
1261        authmode = padapter->securitypriv.ndisauthtype;
1262        if (wrqu->essid.flags && wrqu->essid.length) {
1263                len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ?
1264                       wrqu->essid.length : IW_ESSID_MAX_SIZE;
1265                memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid));
1266                ndis_ssid.SsidLength = len;
1267                memcpy(ndis_ssid.Ssid, extra, len);
1268                src_ssid = ndis_ssid.Ssid;
1269                phead = &queue->queue;
1270                pmlmepriv->pscanned = phead->next;
1271                while (1) {
1272                        if (end_of_queue_search(phead, pmlmepriv->pscanned))
1273                                break;
1274                        pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned,
1275                                   struct wlan_network, list);
1276                        pmlmepriv->pscanned = pmlmepriv->pscanned->next;
1277                        dst_ssid = pnetwork->network.Ssid.Ssid;
1278                        if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength))
1279                            && (pnetwork->network.Ssid.SsidLength ==
1280                             ndis_ssid.SsidLength)) {
1281                                if (check_fwstate(pmlmepriv,
1282                                                        WIFI_ADHOC_STATE)) {
1283                                        if (pnetwork->network.
1284                                                InfrastructureMode
1285                                                !=
1286                                                padapter->mlmepriv.
1287                                                cur_network.network.
1288                                                InfrastructureMode)
1289                                                continue;
1290                                }
1291
1292                                r8712_set_802_11_infrastructure_mode(
1293                                     padapter,
1294                                     pnetwork->network.InfrastructureMode);
1295                                break;
1296                        }
1297                }
1298                r8712_set_802_11_authentication_mode(padapter, authmode);
1299                r8712_set_802_11_ssid(padapter, &ndis_ssid);
1300        }
1301        return -EINPROGRESS;
1302}
1303
1304static int r8711_wx_get_essid(struct net_device *dev,
1305                                struct iw_request_info *a,
1306                                union iwreq_data *wrqu, char *extra)
1307{
1308        struct _adapter *padapter = netdev_priv(dev);
1309        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1310        struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
1311        u32 len, ret = 0;
1312
1313        if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) {
1314                len = pcur_bss->Ssid.SsidLength;
1315                wrqu->essid.length = len;
1316                memcpy(extra, pcur_bss->Ssid.Ssid, len);
1317                wrqu->essid.flags = 1;
1318        } else {
1319                ret = -ENOLINK;
1320        }
1321        return ret;
1322}
1323
1324static int r8711_wx_set_rate(struct net_device *dev,
1325                                struct iw_request_info *a,
1326                                union iwreq_data *wrqu, char *extra)
1327{
1328        struct _adapter *padapter = netdev_priv(dev);
1329        u32 target_rate = wrqu->bitrate.value;
1330        u32 fixed = wrqu->bitrate.fixed;
1331        u32 ratevalue = 0;
1332        u8 datarates[NumRates];
1333        u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
1334        int i, ret = 0;
1335
1336        if (target_rate == -1) {
1337                ratevalue = 11;
1338                goto set_rate;
1339        }
1340        target_rate = target_rate / 100000;
1341        switch (target_rate) {
1342        case 10:
1343                ratevalue = 0;
1344                break;
1345        case 20:
1346                ratevalue = 1;
1347                break;
1348        case 55:
1349                ratevalue = 2;
1350                break;
1351        case 60:
1352                ratevalue = 3;
1353                break;
1354        case 90:
1355                ratevalue = 4;
1356                break;
1357        case 110:
1358                ratevalue = 5;
1359                break;
1360        case 120:
1361                ratevalue = 6;
1362                break;
1363        case 180:
1364                ratevalue = 7;
1365                break;
1366        case 240:
1367                ratevalue = 8;
1368                break;
1369        case 360:
1370                ratevalue = 9;
1371                break;
1372        case 480:
1373                ratevalue = 10;
1374                break;
1375        case 540:
1376                ratevalue = 11;
1377                break;
1378        default:
1379                ratevalue = 11;
1380                break;
1381        }
1382set_rate:
1383        for (i = 0; i < NumRates; i++) {
1384                if (ratevalue == mpdatarate[i]) {
1385                        datarates[i] = mpdatarate[i];
1386                        if (fixed == 0)
1387                                break;
1388                } else {
1389                        datarates[i] = 0xff;
1390                }
1391        }
1392        if (r8712_setdatarate_cmd(padapter, datarates) != _SUCCESS)
1393                ret = -ENOMEM;
1394        return ret;
1395}
1396
1397static int r8711_wx_get_rate(struct net_device *dev,
1398                             struct iw_request_info *info,
1399                             union iwreq_data *wrqu, char *extra)
1400{
1401        struct _adapter *padapter = netdev_priv(dev);
1402        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1403        struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
1404        struct ieee80211_ht_cap *pht_capie;
1405        unsigned char rf_type = padapter->registrypriv.rf_config;
1406        int i;
1407        u8 *p;
1408        u16 rate, max_rate = 0, ht_cap = false;
1409        u32 ht_ielen = 0;
1410        u8 bw_40MHz = 0, short_GI = 0;
1411        u16 mcs_rate = 0;
1412
1413        i = 0;
1414        if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) {
1415                p = r8712_get_ie(&pcur_bss->IEs[12],
1416                                 _HT_CAPABILITY_IE_, &ht_ielen,
1417                    pcur_bss->IELength - 12);
1418                if (p && ht_ielen > 0) {
1419                        ht_cap = true;
1420                        pht_capie = (struct ieee80211_ht_cap *)(p + 2);
1421                        memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
1422                        bw_40MHz = (pht_capie->cap_info &
1423                                    IEEE80211_HT_CAP_SUP_WIDTH) ? 1 : 0;
1424                        short_GI = (pht_capie->cap_info &
1425                                    (IEEE80211_HT_CAP_SGI_20 |
1426                                    IEEE80211_HT_CAP_SGI_40)) ? 1 : 0;
1427                }
1428                while ((pcur_bss->rates[i] != 0) &&
1429                        (pcur_bss->rates[i] != 0xFF)) {
1430                        rate = pcur_bss->rates[i] & 0x7F;
1431                        if (rate > max_rate)
1432                                max_rate = rate;
1433                        wrqu->bitrate.fixed = 0;        /* no auto select */
1434                        wrqu->bitrate.value = rate * 500000;
1435                        i++;
1436                }
1437                if (ht_cap) {
1438                        if (mcs_rate & 0x8000 /* MCS15 */
1439                                &&
1440                                rf_type == RTL8712_RF_2T2R)
1441                                max_rate = (bw_40MHz) ? ((short_GI) ? 300 :
1442                                            270) : ((short_GI) ? 144 : 130);
1443                        else /* default MCS7 */
1444                                max_rate = (bw_40MHz) ? ((short_GI) ? 150 :
1445                                            135) : ((short_GI) ? 72 : 65);
1446                        max_rate *= 2; /* Mbps/2 */
1447                }
1448                wrqu->bitrate.value = max_rate * 500000;
1449        } else {
1450                return -ENOLINK;
1451        }
1452        return 0;
1453}
1454
1455static int r8711_wx_get_rts(struct net_device *dev,
1456                                struct iw_request_info *info,
1457                                union iwreq_data *wrqu, char *extra)
1458{
1459        struct _adapter *padapter = netdev_priv(dev);
1460
1461        wrqu->rts.value = padapter->registrypriv.rts_thresh;
1462        wrqu->rts.fixed = 0;    /* no auto select */
1463        return 0;
1464}
1465
1466static int r8711_wx_set_frag(struct net_device *dev,
1467                                struct iw_request_info *info,
1468                                union iwreq_data *wrqu, char *extra)
1469{
1470        struct _adapter *padapter = netdev_priv(dev);
1471
1472        if (wrqu->frag.disabled) {
1473                padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD;
1474        } else {
1475                if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
1476                    wrqu->frag.value > MAX_FRAG_THRESHOLD)
1477                        return -EINVAL;
1478                padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1;
1479        }
1480        return 0;
1481}
1482
1483static int r8711_wx_get_frag(struct net_device *dev,
1484                                struct iw_request_info *info,
1485                                union iwreq_data *wrqu, char *extra)
1486{
1487        struct _adapter *padapter = netdev_priv(dev);
1488
1489        wrqu->frag.value = padapter->xmitpriv.frag_len;
1490        wrqu->frag.fixed = 0;   /* no auto select */
1491        return 0;
1492}
1493
1494static int r8711_wx_get_retry(struct net_device *dev,
1495                                struct iw_request_info *info,
1496                                union iwreq_data *wrqu, char *extra)
1497{
1498        wrqu->retry.value = 7;
1499        wrqu->retry.fixed = 0;  /* no auto select */
1500        wrqu->retry.disabled = 1;
1501        return 0;
1502}
1503
1504static int r8711_wx_set_enc(struct net_device *dev,
1505                                struct iw_request_info *info,
1506                                union iwreq_data *wrqu, char *keybuf)
1507{
1508        u32 key;
1509        u32 keyindex_provided;
1510        struct NDIS_802_11_WEP   wep;
1511        enum NDIS_802_11_AUTHENTICATION_MODE authmode;
1512        struct iw_point *erq = &(wrqu->encoding);
1513        struct _adapter *padapter = netdev_priv(dev);
1514
1515        key = erq->flags & IW_ENCODE_INDEX;
1516        memset(&wep, 0, sizeof(struct NDIS_802_11_WEP));
1517        if (erq->flags & IW_ENCODE_DISABLED) {
1518                netdev_info(dev, "r8712u: %s: EncryptionDisabled\n", __func__);
1519                padapter->securitypriv.ndisencryptstatus =
1520                                 Ndis802_11EncryptionDisabled;
1521                padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_;
1522                padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_;
1523                padapter->securitypriv.AuthAlgrthm = 0; /* open system */
1524                authmode = Ndis802_11AuthModeOpen;
1525                padapter->securitypriv.ndisauthtype = authmode;
1526                return 0;
1527        }
1528        if (key) {
1529                if (key > WEP_KEYS)
1530                        return -EINVAL;
1531                key--;
1532                keyindex_provided = 1;
1533        } else {
1534                keyindex_provided = 0;
1535                key = padapter->securitypriv.PrivacyKeyIndex;
1536        }
1537        /* set authentication mode */
1538        if (erq->flags & IW_ENCODE_OPEN) {
1539                netdev_info(dev, "r8712u: %s: IW_ENCODE_OPEN\n", __func__);
1540                padapter->securitypriv.ndisencryptstatus =
1541                                 Ndis802_11Encryption1Enabled;
1542                padapter->securitypriv.AuthAlgrthm = 0; /* open system */
1543                padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_;
1544                padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_;
1545                authmode = Ndis802_11AuthModeOpen;
1546                padapter->securitypriv.ndisauthtype = authmode;
1547        } else if (erq->flags & IW_ENCODE_RESTRICTED) {
1548                netdev_info(dev,
1549                                "r8712u: %s: IW_ENCODE_RESTRICTED\n", __func__);
1550                padapter->securitypriv.ndisencryptstatus =
1551                                 Ndis802_11Encryption1Enabled;
1552                padapter->securitypriv.AuthAlgrthm = 1; /* shared system */
1553                padapter->securitypriv.PrivacyAlgrthm = _WEP40_;
1554                padapter->securitypriv.XGrpPrivacy = _WEP40_;
1555                authmode = Ndis802_11AuthModeShared;
1556                padapter->securitypriv.ndisauthtype = authmode;
1557        } else {
1558                padapter->securitypriv.ndisencryptstatus =
1559                                 Ndis802_11Encryption1Enabled;
1560                padapter->securitypriv.AuthAlgrthm = 0; /* open system */
1561                padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_;
1562                padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_;
1563                authmode = Ndis802_11AuthModeOpen;
1564                padapter->securitypriv.ndisauthtype = authmode;
1565        }
1566        wep.KeyIndex = key;
1567        if (erq->length > 0) {
1568                wep.KeyLength = erq->length <= 5 ? 5 : 13;
1569                wep.Length = wep.KeyLength +
1570                             FIELD_OFFSET(struct NDIS_802_11_WEP, KeyMaterial);
1571        } else {
1572                wep.KeyLength = 0;
1573                if (keyindex_provided == 1) { /* set key_id only, no given
1574                                               * KeyMaterial(erq->length==0).
1575                                               */
1576                        padapter->securitypriv.PrivacyKeyIndex = key;
1577                        switch (padapter->securitypriv.DefKeylen[key]) {
1578                        case 5:
1579                                padapter->securitypriv.PrivacyAlgrthm =
1580                                                 _WEP40_;
1581                                break;
1582                        case 13:
1583                                padapter->securitypriv.PrivacyAlgrthm =
1584                                                 _WEP104_;
1585                                break;
1586                        default:
1587                                padapter->securitypriv.PrivacyAlgrthm =
1588                                                 _NO_PRIVACY_;
1589                                break;
1590                        }
1591                        return 0;
1592                }
1593        }
1594        wep.KeyIndex |= 0x80000000;     /* transmit key */
1595        memcpy(wep.KeyMaterial, keybuf, wep.KeyLength);
1596        if (r8712_set_802_11_add_wep(padapter, &wep) == _FAIL)
1597                return -EOPNOTSUPP;
1598        return 0;
1599}
1600
1601static int r8711_wx_get_enc(struct net_device *dev,
1602                                struct iw_request_info *info,
1603                                union iwreq_data *wrqu, char *keybuf)
1604{
1605        uint key, ret = 0;
1606        struct _adapter *padapter = netdev_priv(dev);
1607        struct iw_point *erq = &(wrqu->encoding);
1608        struct  mlme_priv       *pmlmepriv = &(padapter->mlmepriv);
1609
1610        if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
1611                if (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
1612                        erq->length = 0;
1613                        erq->flags |= IW_ENCODE_DISABLED;
1614                        return 0;
1615                }
1616        }
1617        key = erq->flags & IW_ENCODE_INDEX;
1618        if (key) {
1619                if (key > WEP_KEYS)
1620                        return -EINVAL;
1621                key--;
1622        } else {
1623                key = padapter->securitypriv.PrivacyKeyIndex;
1624        }
1625        erq->flags = key + 1;
1626        switch (padapter->securitypriv.ndisencryptstatus) {
1627        case Ndis802_11EncryptionNotSupported:
1628        case Ndis802_11EncryptionDisabled:
1629                erq->length = 0;
1630                erq->flags |= IW_ENCODE_DISABLED;
1631                break;
1632        case Ndis802_11Encryption1Enabled:
1633                erq->length = padapter->securitypriv.DefKeylen[key];
1634                if (erq->length) {
1635                        memcpy(keybuf, padapter->securitypriv.DefKey[
1636                                key].skey, padapter->securitypriv.
1637                                DefKeylen[key]);
1638                        erq->flags |= IW_ENCODE_ENABLED;
1639                        if (padapter->securitypriv.ndisauthtype ==
1640                            Ndis802_11AuthModeOpen)
1641                                erq->flags |= IW_ENCODE_OPEN;
1642                        else if (padapter->securitypriv.ndisauthtype ==
1643                                 Ndis802_11AuthModeShared)
1644                                erq->flags |= IW_ENCODE_RESTRICTED;
1645                } else {
1646                        erq->length = 0;
1647                        erq->flags |= IW_ENCODE_DISABLED;
1648                }
1649                break;
1650        case Ndis802_11Encryption2Enabled:
1651        case Ndis802_11Encryption3Enabled:
1652                erq->length = 16;
1653                erq->flags |= (IW_ENCODE_ENABLED | IW_ENCODE_OPEN |
1654                               IW_ENCODE_NOKEY);
1655                break;
1656        default:
1657                erq->length = 0;
1658                erq->flags |= IW_ENCODE_DISABLED;
1659                break;
1660        }
1661        return ret;
1662}
1663
1664static int r8711_wx_get_power(struct net_device *dev,
1665                                struct iw_request_info *info,
1666                                union iwreq_data *wrqu, char *extra)
1667{
1668        wrqu->power.value = 0;
1669        wrqu->power.fixed = 0;  /* no auto select */
1670        wrqu->power.disabled = 1;
1671        return 0;
1672}
1673
1674static int r871x_wx_set_gen_ie(struct net_device *dev,
1675                                struct iw_request_info *info,
1676                                union iwreq_data *wrqu, char *extra)
1677{
1678        struct _adapter *padapter = netdev_priv(dev);
1679
1680        return r871x_set_wpa_ie(padapter, extra, wrqu->data.length);
1681}
1682
1683static int r871x_wx_set_auth(struct net_device *dev,
1684                                struct iw_request_info *info,
1685                                union iwreq_data *wrqu, char *extra)
1686{
1687        struct _adapter *padapter = netdev_priv(dev);
1688        struct iw_param *param = (struct iw_param *)&(wrqu->param);
1689        int paramid;
1690        int paramval;
1691        int ret = 0;
1692
1693        paramid = param->flags & IW_AUTH_INDEX;
1694        paramval = param->value;
1695        switch (paramid) {
1696        case IW_AUTH_WPA_VERSION:
1697                break;
1698        case IW_AUTH_CIPHER_PAIRWISE:
1699                break;
1700        case IW_AUTH_CIPHER_GROUP:
1701                break;
1702        case IW_AUTH_KEY_MGMT:
1703                /*
1704                 *  ??? does not use these parameters
1705                 */
1706                break;
1707        case IW_AUTH_TKIP_COUNTERMEASURES:
1708                if (paramval) {
1709                        /* wpa_supplicant is enabling tkip countermeasure. */
1710                        padapter->securitypriv.btkip_countermeasure = true;
1711                } else {
1712                        /* wpa_supplicant is disabling tkip countermeasure. */
1713                        padapter->securitypriv.btkip_countermeasure = false;
1714                }
1715                break;
1716        case IW_AUTH_DROP_UNENCRYPTED:
1717                /* HACK:
1718                 *
1719                 * wpa_supplicant calls set_wpa_enabled when the driver
1720                 * is loaded and unloaded, regardless of if WPA is being
1721                 * used.  No other calls are made which can be used to
1722                 * determine if encryption will be used or not prior to
1723                 * association being expected.  If encryption is not being
1724                 * used, drop_unencrypted is set to false, else true -- we
1725                 * can use this to determine if the CAP_PRIVACY_ON bit should
1726                 * be set.
1727                 */
1728                if (padapter->securitypriv.ndisencryptstatus ==
1729                    Ndis802_11Encryption1Enabled) {
1730                                /* it means init value, or using wep,
1731                                 * ndisencryptstatus =
1732                                 *      Ndis802_11Encryption1Enabled,
1733                                 * then it needn't reset it;
1734                                 */
1735                                break;
1736                }
1737
1738                if (paramval) {
1739                        padapter->securitypriv.ndisencryptstatus =
1740                                   Ndis802_11EncryptionDisabled;
1741                        padapter->securitypriv.PrivacyAlgrthm =
1742                                  _NO_PRIVACY_;
1743                        padapter->securitypriv.XGrpPrivacy =
1744                                  _NO_PRIVACY_;
1745                        padapter->securitypriv.AuthAlgrthm = 0;
1746                        padapter->securitypriv.ndisauthtype =
1747                                  Ndis802_11AuthModeOpen;
1748                }
1749                break;
1750        case IW_AUTH_80211_AUTH_ALG:
1751                ret = wpa_set_auth_algs(dev, (u32)paramval);
1752                break;
1753        case IW_AUTH_WPA_ENABLED:
1754                break;
1755        case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1756                break;
1757        case IW_AUTH_PRIVACY_INVOKED:
1758                break;
1759        default:
1760                return -EOPNOTSUPP;
1761        }
1762
1763        return ret;
1764}
1765
1766static int r871x_wx_set_enc_ext(struct net_device *dev,
1767                             struct iw_request_info *info,
1768                             union iwreq_data *wrqu, char *extra)
1769{
1770        struct iw_point *pencoding = &wrqu->encoding;
1771        struct iw_encode_ext *pext = (struct iw_encode_ext *)extra;
1772        struct ieee_param *param = NULL;
1773        char *alg_name;
1774        u32 param_len;
1775        int ret = 0;
1776
1777        switch (pext->alg) {
1778        case IW_ENCODE_ALG_NONE:
1779                alg_name = "none";
1780                break;
1781        case IW_ENCODE_ALG_WEP:
1782                alg_name = "WEP";
1783                break;
1784        case IW_ENCODE_ALG_TKIP:
1785                alg_name = "TKIP";
1786                break;
1787        case IW_ENCODE_ALG_CCMP:
1788                alg_name = "CCMP";
1789                break;
1790        default:
1791                return -EINVAL;
1792        }
1793
1794        param_len = sizeof(struct ieee_param) + pext->key_len;
1795        param = kzalloc(param_len, GFP_ATOMIC);
1796        if (param == NULL)
1797                return -ENOMEM;
1798        param->cmd = IEEE_CMD_SET_ENCRYPTION;
1799        eth_broadcast_addr(param->sta_addr);
1800        strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);
1801        if (pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
1802                param->u.crypt.set_tx = 0;
1803        if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
1804                param->u.crypt.set_tx = 1;
1805        param->u.crypt.idx = (pencoding->flags & 0x00FF) - 1;
1806        if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
1807                memcpy(param->u.crypt.seq, pext->rx_seq, 8);
1808        if (pext->key_len) {
1809                param->u.crypt.key_len = pext->key_len;
1810                memcpy(param + 1, pext + 1, pext->key_len);
1811        }
1812        ret = wpa_set_encryption(dev, param, param_len);
1813        kfree(param);
1814        return ret;
1815}
1816
1817static int r871x_wx_get_nick(struct net_device *dev,
1818                             struct iw_request_info *info,
1819                             union iwreq_data *wrqu, char *extra)
1820{
1821        if (extra) {
1822                wrqu->data.length = 8;
1823                wrqu->data.flags = 1;
1824                memcpy(extra, "rtl_wifi", 8);
1825        }
1826        return 0;
1827}
1828
1829static int r8711_wx_read32(struct net_device *dev,
1830                                struct iw_request_info *info,
1831                                union iwreq_data *wrqu, char *keybuf)
1832{
1833        struct _adapter *padapter = netdev_priv(dev);
1834        u32 addr;
1835        u32 data32;
1836
1837        get_user(addr, (u32 __user *)wrqu->data.pointer);
1838        data32 = r8712_read32(padapter, addr);
1839        put_user(data32, (u32 __user *)wrqu->data.pointer);
1840        wrqu->data.length = (data32 & 0xffff0000) >> 16;
1841        wrqu->data.flags = data32 & 0xffff;
1842        get_user(addr, (u32 __user *)wrqu->data.pointer);
1843        return 0;
1844}
1845
1846static int r8711_wx_write32(struct net_device *dev,
1847                                 struct iw_request_info *info,
1848                                 union iwreq_data *wrqu, char *keybuf)
1849{
1850        struct _adapter *padapter = netdev_priv(dev);
1851        u32 addr;
1852        u32 data32;
1853
1854        get_user(addr, (u32 __user *)wrqu->data.pointer);
1855        data32 = ((u32)wrqu->data.length << 16) | (u32)wrqu->data.flags;
1856        r8712_write32(padapter, addr, data32);
1857        return 0;
1858}
1859
1860static int dummy(struct net_device *dev,
1861                struct iw_request_info *a,
1862                union iwreq_data *wrqu, char *b)
1863{
1864        return -ENOSYS;
1865}
1866
1867static int r8711_drvext_hdl(struct net_device *dev,
1868                                struct iw_request_info *info,
1869                                union iwreq_data *wrqu, char *extra)
1870{
1871        return 0;
1872}
1873
1874static int r871x_mp_ioctl_hdl(struct net_device *dev,
1875                                struct iw_request_info *info,
1876                                union iwreq_data *wrqu, char *extra)
1877{
1878        struct _adapter *padapter = netdev_priv(dev);
1879        struct iw_point *p = &wrqu->data;
1880        struct oid_par_priv oid_par;
1881        struct mp_ioctl_handler *phandler;
1882        struct mp_ioctl_param *poidparam;
1883        unsigned long BytesRead, BytesWritten, BytesNeeded;
1884        u8 *pparmbuf, bset;
1885        u16 len;
1886        uint status;
1887        int ret = 0;
1888
1889        if ((!p->length) || (!p->pointer))
1890                return -EINVAL;
1891
1892        bset = (u8)(p->flags & 0xFFFF);
1893        len = p->length;
1894        pparmbuf = memdup_user(p->pointer, len);
1895        if (IS_ERR(pparmbuf))
1896                return PTR_ERR(pparmbuf);
1897
1898        poidparam = (struct mp_ioctl_param *)pparmbuf;
1899        if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) {
1900                ret = -EINVAL;
1901                goto _r871x_mp_ioctl_hdl_exit;
1902        }
1903        phandler = mp_ioctl_hdl + poidparam->subcode;
1904        if ((phandler->paramsize != 0) &&
1905            (poidparam->len < phandler->paramsize)) {
1906                ret = -EINVAL;
1907                goto _r871x_mp_ioctl_hdl_exit;
1908        }
1909        if (phandler->oid == 0 && phandler->handler) {
1910                status = phandler->handler(&oid_par);
1911        } else if (phandler->handler) {
1912                oid_par.adapter_context = padapter;
1913                oid_par.oid = phandler->oid;
1914                oid_par.information_buf = poidparam->data;
1915                oid_par.information_buf_len = poidparam->len;
1916                oid_par.dbg = 0;
1917                BytesWritten = 0;
1918                BytesNeeded = 0;
1919                if (bset) {
1920                        oid_par.bytes_rw = &BytesRead;
1921                        oid_par.bytes_needed = &BytesNeeded;
1922                        oid_par.type_of_oid = SET_OID;
1923                } else {
1924                        oid_par.bytes_rw = &BytesWritten;
1925                        oid_par.bytes_needed = &BytesNeeded;
1926                        oid_par.type_of_oid = QUERY_OID;
1927                }
1928                status = phandler->handler(&oid_par);
1929                /* todo:check status, BytesNeeded, etc. */
1930        } else {
1931                netdev_info(dev, "r8712u: %s: err!, subcode=%d, oid=%d, handler=%p\n",
1932                            __func__, poidparam->subcode, phandler->oid,
1933                            phandler->handler);
1934                ret = -EFAULT;
1935                goto _r871x_mp_ioctl_hdl_exit;
1936        }
1937        if (bset == 0x00) { /* query info */
1938                if (copy_to_user(p->pointer, pparmbuf, len))
1939                        ret = -EFAULT;
1940        }
1941        if (status) {
1942                ret = -EFAULT;
1943                goto _r871x_mp_ioctl_hdl_exit;
1944        }
1945_r871x_mp_ioctl_hdl_exit:
1946        kfree(pparmbuf);
1947        return ret;
1948}
1949
1950static int r871x_get_ap_info(struct net_device *dev,
1951                                struct iw_request_info *info,
1952                                union iwreq_data *wrqu, char *extra)
1953{
1954        struct _adapter *padapter = netdev_priv(dev);
1955        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1956        struct  __queue *queue = &pmlmepriv->scanned_queue;
1957        struct iw_point *pdata = &wrqu->data;
1958        struct wlan_network *pnetwork = NULL;
1959        u32 cnt = 0, wpa_ielen;
1960        unsigned long irqL;
1961        struct list_head *plist, *phead;
1962        unsigned char *pbuf;
1963        u8 bssid[ETH_ALEN];
1964        char data[33];
1965
1966        if (padapter->bDriverStopped || (pdata == NULL))
1967                return -EINVAL;
1968        while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY |
1969                             _FW_UNDER_LINKING)) {
1970                msleep(30);
1971                cnt++;
1972                if (cnt > 100)
1973                        break;
1974        }
1975        pdata->flags = 0;
1976        if (pdata->length >= 32) {
1977                if (copy_from_user(data, pdata->pointer, 32))
1978                        return -EINVAL;
1979                data[32] = 0;
1980        } else {
1981                 return -EINVAL;
1982        }
1983        spin_lock_irqsave(&(pmlmepriv->scanned_queue.lock), irqL);
1984        phead = &queue->queue;
1985        plist = phead->next;
1986        while (1) {
1987                if (end_of_queue_search(phead, plist))
1988                        break;
1989                pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
1990                if (!mac_pton(data, bssid)) {
1991                        netdev_info(dev, "r8712u: Invalid BSSID '%s'.\n",
1992                                    (u8 *)data);
1993                        spin_unlock_irqrestore(&(pmlmepriv->scanned_queue.lock),
1994                                               irqL);
1995                        return -EINVAL;
1996                }
1997                netdev_info(dev, "r8712u: BSSID:%pM\n", bssid);
1998                if (ether_addr_equal(bssid, pnetwork->network.MacAddress)) {
1999                        /* BSSID match, then check if supporting wpa/wpa2 */
2000                        pbuf = r8712_get_wpa_ie(&pnetwork->network.IEs[12],
2001                               &wpa_ielen, pnetwork->network.IELength - 12);
2002                        if (pbuf && (wpa_ielen > 0)) {
2003                                pdata->flags = 1;
2004                                break;
2005                        }
2006                        pbuf = r8712_get_wpa2_ie(&pnetwork->network.IEs[12],
2007                               &wpa_ielen, pnetwork->network.IELength - 12);
2008                        if (pbuf && (wpa_ielen > 0)) {
2009                                pdata->flags = 2;
2010                                break;
2011                        }
2012                }
2013                plist = plist->next;
2014        }
2015        spin_unlock_irqrestore(&(pmlmepriv->scanned_queue.lock), irqL);
2016        if (pdata->length >= 34) {
2017                if (copy_to_user((u8 __user *)pdata->pointer + 32,
2018                    (u8 *)&pdata->flags, 1))
2019                        return -EINVAL;
2020        }
2021        return 0;
2022}
2023
2024static int r871x_set_pid(struct net_device *dev,
2025                                struct iw_request_info *info,
2026                                union iwreq_data *wrqu, char *extra)
2027{
2028        struct _adapter *padapter = netdev_priv(dev);
2029        struct iw_point *pdata = &wrqu->data;
2030
2031        if ((padapter->bDriverStopped) || (pdata == NULL))
2032                return -EINVAL;
2033        if (copy_from_user(&padapter->pid, pdata->pointer, sizeof(int)))
2034                return -EINVAL;
2035        return 0;
2036}
2037
2038static int r871x_set_chplan(struct net_device *dev,
2039                                struct iw_request_info *info,
2040                                union iwreq_data *wrqu, char *extra)
2041{
2042        int ret = 0;
2043        struct _adapter *padapter = netdev_priv(dev);
2044        struct iw_point *pdata = &wrqu->data;
2045        int ch_plan = -1;
2046
2047        if ((padapter->bDriverStopped) || (pdata == NULL)) {
2048                ret = -EINVAL;
2049                goto exit;
2050        }
2051        ch_plan = (int)*extra;
2052        r8712_set_chplan_cmd(padapter, ch_plan);
2053
2054exit:
2055
2056        return ret;
2057}
2058
2059static int r871x_wps_start(struct net_device *dev,
2060                           struct iw_request_info *info,
2061                           union iwreq_data *wrqu, char *extra)
2062{
2063        struct _adapter *padapter = netdev_priv(dev);
2064        struct iw_point *pdata = &wrqu->data;
2065        u32   u32wps_start = 0;
2066
2067        if ((padapter->bDriverStopped) || (pdata == NULL))
2068                return -EINVAL;
2069        if (copy_from_user((void *)&u32wps_start, pdata->pointer, 4))
2070                return -EFAULT;
2071        if (u32wps_start == 0)
2072                u32wps_start = *extra;
2073        if (u32wps_start == 1) /* WPS Start */
2074                padapter->ledpriv.LedControlHandler(padapter,
2075                           LED_CTL_START_WPS);
2076        else if (u32wps_start == 2) /* WPS Stop because of wps success */
2077                padapter->ledpriv.LedControlHandler(padapter,
2078                           LED_CTL_STOP_WPS);
2079        else if (u32wps_start == 3) /* WPS Stop because of wps fail */
2080                padapter->ledpriv.LedControlHandler(padapter,
2081                           LED_CTL_STOP_WPS_FAIL);
2082        return 0;
2083}
2084
2085static int wpa_set_param(struct net_device *dev, u8 name, u32 value)
2086{
2087        struct _adapter *padapter = netdev_priv(dev);
2088
2089        switch (name) {
2090        case IEEE_PARAM_WPA_ENABLED:
2091                padapter->securitypriv.AuthAlgrthm = 2; /* 802.1x */
2092                switch ((value) & 0xff) {
2093                case 1: /* WPA */
2094                        padapter->securitypriv.ndisauthtype =
2095                                Ndis802_11AuthModeWPAPSK; /* WPA_PSK */
2096                        padapter->securitypriv.ndisencryptstatus =
2097                                Ndis802_11Encryption2Enabled;
2098                        break;
2099                case 2: /* WPA2 */
2100                        padapter->securitypriv.ndisauthtype =
2101                                Ndis802_11AuthModeWPA2PSK; /* WPA2_PSK */
2102                        padapter->securitypriv.ndisencryptstatus =
2103                                Ndis802_11Encryption3Enabled;
2104                        break;
2105                }
2106                break;
2107        case IEEE_PARAM_TKIP_COUNTERMEASURES:
2108                break;
2109        case IEEE_PARAM_DROP_UNENCRYPTED:
2110                /* HACK:
2111                 *
2112                 * wpa_supplicant calls set_wpa_enabled when the driver
2113                 * is loaded and unloaded, regardless of if WPA is being
2114                 * used.  No other calls are made which can be used to
2115                 * determine if encryption will be used or not prior to
2116                 * association being expected.  If encryption is not being
2117                 * used, drop_unencrypted is set to false, else true -- we
2118                 * can use this to determine if the CAP_PRIVACY_ON bit should
2119                 * be set.
2120                 */
2121                break;
2122        case IEEE_PARAM_PRIVACY_INVOKED:
2123                break;
2124        case IEEE_PARAM_AUTH_ALGS:
2125                return wpa_set_auth_algs(dev, value);
2126        case IEEE_PARAM_IEEE_802_1X:
2127                break;
2128        case IEEE_PARAM_WPAX_SELECT:
2129                /* added for WPA2 mixed mode */
2130                break;
2131        default:
2132                return -EOPNOTSUPP;
2133        }
2134        return 0;
2135}
2136
2137static int wpa_mlme(struct net_device *dev, u32 command, u32 reason)
2138{
2139        struct _adapter *padapter = netdev_priv(dev);
2140
2141        switch (command) {
2142        case IEEE_MLME_STA_DEAUTH:
2143                if (!r8712_set_802_11_disassociate(padapter))
2144                        return -1;
2145                break;
2146        case IEEE_MLME_STA_DISASSOC:
2147                if (!r8712_set_802_11_disassociate(padapter))
2148                        return -1;
2149                break;
2150        default:
2151                return -EOPNOTSUPP;
2152        }
2153        return 0;
2154}
2155
2156static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p)
2157{
2158        struct ieee_param *param;
2159        int ret = 0;
2160        struct _adapter *padapter = netdev_priv(dev);
2161
2162        if (p->length < sizeof(struct ieee_param) || !p->pointer)
2163                return -EINVAL;
2164        param = memdup_user(p->pointer, p->length);
2165        if (IS_ERR(param))
2166                return PTR_ERR(param);
2167        switch (param->cmd) {
2168        case IEEE_CMD_SET_WPA_PARAM:
2169                ret = wpa_set_param(dev, param->u.wpa_param.name,
2170                      param->u.wpa_param.value);
2171                break;
2172        case IEEE_CMD_SET_WPA_IE:
2173                ret =  r871x_set_wpa_ie(padapter, (char *)param->u.wpa_ie.data,
2174                       (u16)param->u.wpa_ie.len);
2175                break;
2176        case IEEE_CMD_SET_ENCRYPTION:
2177                ret = wpa_set_encryption(dev, param, p->length);
2178                break;
2179        case IEEE_CMD_MLME:
2180                ret = wpa_mlme(dev, param->u.mlme.command,
2181                      param->u.mlme.reason_code);
2182                break;
2183        default:
2184                ret = -EOPNOTSUPP;
2185                break;
2186        }
2187        if (ret == 0 && copy_to_user(p->pointer, param, p->length))
2188                ret = -EFAULT;
2189        kfree(param);
2190        return ret;
2191}
2192
2193/* based on "driver_ipw" and for hostapd */
2194int r871x_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
2195{
2196        struct iwreq *wrq = (struct iwreq *)rq;
2197
2198        switch (cmd) {
2199        case RTL_IOCTL_WPA_SUPPLICANT:
2200                return wpa_supplicant_ioctl(dev, &wrq->u.data);
2201        default:
2202                return -EOPNOTSUPP;
2203        }
2204        return 0;
2205}
2206
2207static iw_handler r8711_handlers[] = {
2208        NULL,                           /* SIOCSIWCOMMIT */
2209        r8711_wx_get_name,              /* SIOCGIWNAME */
2210        dummy,                          /* SIOCSIWNWID */
2211        dummy,                          /* SIOCGIWNWID */
2212        r8711_wx_set_freq,              /* SIOCSIWFREQ */
2213        r8711_wx_get_freq,              /* SIOCGIWFREQ */
2214        r8711_wx_set_mode,              /* SIOCSIWMODE */
2215        r8711_wx_get_mode,              /* SIOCGIWMODE */
2216        dummy,                          /* SIOCSIWSENS */
2217        r8711_wx_get_sens,              /* SIOCGIWSENS */
2218        NULL,                           /* SIOCSIWRANGE */
2219        r8711_wx_get_range,             /* SIOCGIWRANGE */
2220        r871x_wx_set_priv,              /* SIOCSIWPRIV */
2221        NULL,                           /* SIOCGIWPRIV */
2222        NULL,                           /* SIOCSIWSTATS */
2223        NULL,                           /* SIOCGIWSTATS */
2224        dummy,                          /* SIOCSIWSPY */
2225        dummy,                          /* SIOCGIWSPY */
2226        NULL,                           /* SIOCGIWTHRSPY */
2227        NULL,                           /* SIOCWIWTHRSPY */
2228        r8711_wx_set_wap,               /* SIOCSIWAP */
2229        r8711_wx_get_wap,               /* SIOCGIWAP */
2230        r871x_wx_set_mlme,              /* request MLME operation;
2231                                         *  uses struct iw_mlme
2232                                         */
2233        dummy,                          /* SIOCGIWAPLIST -- deprecated */
2234        r8711_wx_set_scan,              /* SIOCSIWSCAN */
2235        r8711_wx_get_scan,              /* SIOCGIWSCAN */
2236        r8711_wx_set_essid,             /* SIOCSIWESSID */
2237        r8711_wx_get_essid,             /* SIOCGIWESSID */
2238        dummy,                          /* SIOCSIWNICKN */
2239        r871x_wx_get_nick,              /* SIOCGIWNICKN */
2240        NULL,                           /* -- hole -- */
2241        NULL,                           /* -- hole -- */
2242        r8711_wx_set_rate,              /* SIOCSIWRATE */
2243        r8711_wx_get_rate,              /* SIOCGIWRATE */
2244        dummy,                          /* SIOCSIWRTS */
2245        r8711_wx_get_rts,               /* SIOCGIWRTS */
2246        r8711_wx_set_frag,              /* SIOCSIWFRAG */
2247        r8711_wx_get_frag,              /* SIOCGIWFRAG */
2248        dummy,                          /* SIOCSIWTXPOW */
2249        dummy,                          /* SIOCGIWTXPOW */
2250        dummy,                          /* SIOCSIWRETRY */
2251        r8711_wx_get_retry,             /* SIOCGIWRETRY */
2252        r8711_wx_set_enc,               /* SIOCSIWENCODE */
2253        r8711_wx_get_enc,               /* SIOCGIWENCODE */
2254        dummy,                          /* SIOCSIWPOWER */
2255        r8711_wx_get_power,             /* SIOCGIWPOWER */
2256        NULL,                           /*---hole---*/
2257        NULL,                           /*---hole---*/
2258        r871x_wx_set_gen_ie,            /* SIOCSIWGENIE */
2259        NULL,                           /* SIOCGIWGENIE */
2260        r871x_wx_set_auth,              /* SIOCSIWAUTH */
2261        NULL,                           /* SIOCGIWAUTH */
2262        r871x_wx_set_enc_ext,           /* SIOCSIWENCODEEXT */
2263        NULL,                           /* SIOCGIWENCODEEXT */
2264        r871x_wx_set_pmkid,             /* SIOCSIWPMKSA */
2265        NULL,                           /*---hole---*/
2266};
2267
2268static const struct iw_priv_args r8711_private_args[] = {
2269        {
2270                SIOCIWFIRSTPRIV + 0x0,
2271                IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "read32"
2272        },
2273        {
2274                SIOCIWFIRSTPRIV + 0x1,
2275                IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "write32"
2276        },
2277        {
2278                SIOCIWFIRSTPRIV + 0x2, 0, 0, "driver_ext"
2279        },
2280        {
2281                SIOCIWFIRSTPRIV + 0x3, 0, 0, "mp_ioctl"
2282        },
2283        {
2284                SIOCIWFIRSTPRIV + 0x4,
2285                IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo"
2286        },
2287        {
2288                SIOCIWFIRSTPRIV + 0x5,
2289                IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setpid"
2290        },
2291        {
2292                SIOCIWFIRSTPRIV + 0x6,
2293                IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_start"
2294        },
2295        {
2296                SIOCIWFIRSTPRIV + 0x7,
2297                IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "chplan"
2298        }
2299};
2300
2301static iw_handler r8711_private_handler[] = {
2302        r8711_wx_read32,
2303        r8711_wx_write32,
2304        r8711_drvext_hdl,
2305        r871x_mp_ioctl_hdl,
2306        r871x_get_ap_info, /*for MM DTV platform*/
2307        r871x_set_pid,
2308        r871x_wps_start,
2309        r871x_set_chplan
2310};
2311
2312static struct iw_statistics *r871x_get_wireless_stats(struct net_device *dev)
2313{
2314        struct _adapter *padapter = netdev_priv(dev);
2315        struct iw_statistics *piwstats = &padapter->iwstats;
2316        int tmp_level = 0;
2317        int tmp_qual = 0;
2318        int tmp_noise = 0;
2319
2320        if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) != true) {
2321                piwstats->qual.qual = 0;
2322                piwstats->qual.level = 0;
2323                piwstats->qual.noise = 0;
2324        } else {
2325                /* show percentage, we need transfer dbm to orignal value. */
2326                tmp_level = padapter->recvpriv.fw_rssi;
2327                tmp_qual = padapter->recvpriv.signal;
2328                tmp_noise = padapter->recvpriv.noise;
2329                piwstats->qual.level = tmp_level;
2330                piwstats->qual.qual = tmp_qual;
2331                piwstats->qual.noise = tmp_noise;
2332        }
2333        piwstats->qual.updated = IW_QUAL_ALL_UPDATED;
2334        return &padapter->iwstats;
2335}
2336
2337struct iw_handler_def r871x_handlers_def = {
2338        .standard = r8711_handlers,
2339        .num_standard = ARRAY_SIZE(r8711_handlers),
2340        .private = r8711_private_handler,
2341        .private_args = (struct iw_priv_args *)r8711_private_args,
2342        .num_private = ARRAY_SIZE(r8711_private_handler),
2343        .num_private_args = sizeof(r8711_private_args) /
2344                            sizeof(struct iw_priv_args),
2345        .get_wireless_stats = r871x_get_wireless_stats
2346};
2347