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