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