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