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