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