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