linux/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/******************************************************************************
   3 *
   4 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
   5 *
   6 ******************************************************************************/
   7#define _RTW_IOCTL_SET_C_
   8
   9#include <osdep_service.h>
  10#include <drv_types.h>
  11#include <rtw_ioctl_set.h>
  12#include <hal_intf.h>
  13
  14static const struct {
  15        int channel_plan;
  16        char *name;
  17} channel_table[] = { { RT_CHANNEL_DOMAIN_FCC, "US" },
  18        { RT_CHANNEL_DOMAIN_ETSI, "EU" },
  19        { RT_CHANNEL_DOMAIN_MKK, "JP" },
  20        { RT_CHANNEL_DOMAIN_CHINA, "CN"} };
  21
  22extern void indicate_wx_scan_complete_event(struct adapter *padapter);
  23
  24u8 rtw_do_join(struct adapter *padapter)
  25{
  26        struct list_head *plist, *phead;
  27        u8 *pibss = NULL;
  28        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
  29        struct __queue *queue = &pmlmepriv->scanned_queue;
  30        u8 ret = _SUCCESS;
  31
  32        spin_lock_bh(&pmlmepriv->scanned_queue.lock);
  33        phead = get_list_head(queue);
  34        plist = phead->next;
  35
  36        pmlmepriv->cur_network.join_res = -2;
  37
  38        set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
  39
  40        pmlmepriv->pscanned = plist;
  41
  42        pmlmepriv->to_join = true;
  43
  44        if (list_empty(&queue->queue)) {
  45                spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
  46                _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
  47
  48                /* when set_ssid/set_bssid for rtw_do_join(), but scanning queue is empty */
  49                /* we try to issue sitesurvey firstly */
  50
  51                if (!pmlmepriv->LinkDetectInfo.bBusyTraffic ||
  52                    pmlmepriv->to_roaming > 0) {
  53                        /*  submit site_survey_cmd */
  54                        ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
  55                        if (ret != _SUCCESS)
  56                                pmlmepriv->to_join = false;
  57                } else {
  58                        pmlmepriv->to_join = false;
  59                        ret = _FAIL;
  60                }
  61
  62                goto exit;
  63        } else {
  64                int select_ret;
  65
  66                spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
  67                select_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv);
  68                if (select_ret == _SUCCESS) {
  69                        pmlmepriv->to_join = false;
  70                        mod_timer(&pmlmepriv->assoc_timer,
  71                                  jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT));
  72                } else {
  73                        if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
  74                                /*  submit createbss_cmd to change to a ADHOC_MASTER */
  75
  76                                /* pmlmepriv->lock has been acquired by caller... */
  77                                struct wlan_bssid_ex    *pdev_network = &padapter->registrypriv.dev_network;
  78
  79                                pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
  80
  81                                pibss = padapter->registrypriv.dev_network.MacAddress;
  82
  83                                memcpy(&pdev_network->ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid));
  84
  85                                rtw_update_registrypriv_dev_network(padapter);
  86
  87                                rtw_generate_random_ibss(pibss);
  88
  89                                if (rtw_createbss_cmd(padapter) != _SUCCESS) {
  90                                        ret =  false;
  91                                        goto exit;
  92                                }
  93                                pmlmepriv->to_join = false;
  94                        } else {
  95                                /*  can't associate ; reset under-linking */
  96                                _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
  97
  98                                /* when set_ssid/set_bssid for rtw_do_join(), but there are no desired bss in scanning queue */
  99                                /* we try to issue sitesurvey firstly */
 100                                if (!pmlmepriv->LinkDetectInfo.bBusyTraffic ||
 101                                    pmlmepriv->to_roaming > 0) {
 102                                        ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
 103                                        if (ret != _SUCCESS)
 104                                                pmlmepriv->to_join = false;
 105                                } else {
 106                                        ret = _FAIL;
 107                                        pmlmepriv->to_join = false;
 108                                }
 109                        }
 110                }
 111        }
 112
 113exit:
 114        return ret;
 115}
 116
 117u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid)
 118{
 119        u8 status = _SUCCESS;
 120        u32 cur_time = 0;
 121        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 122
 123        if ((bssid[0] == 0x00 && bssid[1] == 0x00 && bssid[2] == 0x00 &&
 124             bssid[3] == 0x00 && bssid[4] == 0x00 && bssid[5] == 0x00) ||
 125            (bssid[0] == 0xFF && bssid[1] == 0xFF && bssid[2] == 0xFF &&
 126             bssid[3] == 0xFF && bssid[4] == 0xFF && bssid[5] == 0xFF)) {
 127                status = _FAIL;
 128                goto exit;
 129        }
 130
 131        spin_lock_bh(&pmlmepriv->lock);
 132
 133        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
 134                goto handle_tkip_countermeasure;
 135        else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
 136                goto release_mlme_lock;
 137
 138        if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) {
 139                if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN)) {
 140                        if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE))
 141                                goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
 142                } else {
 143                        rtw_disassoc_cmd(padapter, 0, true);
 144
 145                        if (check_fwstate(pmlmepriv, _FW_LINKED))
 146                                rtw_indicate_disconnect(padapter);
 147
 148                        rtw_free_assoc_resources(padapter);
 149
 150                        if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
 151                                _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
 152                                set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
 153                        }
 154                }
 155        }
 156
 157handle_tkip_countermeasure:
 158        /* should we add something here...? */
 159
 160        if (padapter->securitypriv.btkip_countermeasure) {
 161                cur_time = jiffies;
 162
 163                if (cur_time - padapter->securitypriv.btkip_countermeasure_time > 60 * HZ) {
 164                        padapter->securitypriv.btkip_countermeasure = false;
 165                        padapter->securitypriv.btkip_countermeasure_time = 0;
 166                } else {
 167                        status = _FAIL;
 168                        goto release_mlme_lock;
 169                }
 170        }
 171
 172        memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN);
 173        pmlmepriv->assoc_by_bssid = true;
 174
 175        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
 176                pmlmepriv->to_join = true;
 177        else
 178                status = rtw_do_join(padapter);
 179
 180release_mlme_lock:
 181        spin_unlock_bh(&pmlmepriv->lock);
 182
 183exit:
 184        return status;
 185}
 186
 187u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid)
 188{
 189        u8 status = _SUCCESS;
 190        u32 cur_time = 0;
 191
 192        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 193        struct wlan_network *pnetwork = &pmlmepriv->cur_network;
 194
 195        if (!padapter->hw_init_completed) {
 196                status = _FAIL;
 197                goto exit;
 198        }
 199
 200        spin_lock_bh(&pmlmepriv->lock);
 201
 202        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
 203                goto handle_tkip_countermeasure;
 204        else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
 205                goto release_mlme_lock;
 206
 207        if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) {
 208                if (pmlmepriv->assoc_ssid.ssid_length == ssid->ssid_length &&
 209                    !memcmp(&pmlmepriv->assoc_ssid.ssid, ssid->ssid, ssid->ssid_length)) {
 210                        if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
 211                                if (!rtw_is_same_ibss(padapter, pnetwork)) {
 212                                        /* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */
 213                                        rtw_disassoc_cmd(padapter, 0, true);
 214
 215                                        if (check_fwstate(pmlmepriv, _FW_LINKED))
 216                                                rtw_indicate_disconnect(padapter);
 217
 218                                        rtw_free_assoc_resources(padapter);
 219
 220                                        if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
 221                                                _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
 222                                                set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
 223                                        }
 224                                } else {
 225                                        goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
 226                                }
 227                        } else {
 228                                rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_JOINBSS, 1);
 229                        }
 230                } else {
 231                        rtw_disassoc_cmd(padapter, 0, true);
 232
 233                        if (check_fwstate(pmlmepriv, _FW_LINKED))
 234                                rtw_indicate_disconnect(padapter);
 235
 236                        rtw_free_assoc_resources(padapter);
 237
 238                        if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
 239                                _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
 240                                set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
 241                        }
 242                }
 243        }
 244
 245handle_tkip_countermeasure:
 246
 247        if (padapter->securitypriv.btkip_countermeasure) {
 248                cur_time = jiffies;
 249
 250                if (cur_time - padapter->securitypriv.btkip_countermeasure_time > 60 * HZ) {
 251                        padapter->securitypriv.btkip_countermeasure = false;
 252                        padapter->securitypriv.btkip_countermeasure_time = 0;
 253                } else {
 254                        status = _FAIL;
 255                        goto release_mlme_lock;
 256                }
 257        }
 258
 259        memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid));
 260        pmlmepriv->assoc_by_bssid = false;
 261
 262        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
 263                pmlmepriv->to_join = true;
 264        else
 265                status = rtw_do_join(padapter);
 266
 267release_mlme_lock:
 268        spin_unlock_bh(&pmlmepriv->lock);
 269
 270exit:
 271        return status;
 272}
 273
 274u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter,
 275                                      enum ndis_802_11_network_infra networktype)
 276{
 277        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 278        struct wlan_network *cur_network = &pmlmepriv->cur_network;
 279        enum ndis_802_11_network_infra *pold_state = &cur_network->network.InfrastructureMode;
 280
 281        if (*pold_state != networktype) {
 282                spin_lock_bh(&pmlmepriv->lock);
 283
 284                if (*pold_state == Ndis802_11APMode) {
 285                        /* change to other mode from Ndis802_11APMode */
 286                        cur_network->join_res = -1;
 287
 288#ifdef CONFIG_88EU_AP_MODE
 289                        stop_ap_mode(padapter);
 290#endif
 291                }
 292
 293                if (check_fwstate(pmlmepriv, _FW_LINKED) ||
 294                    *pold_state == Ndis802_11IBSS)
 295                        rtw_disassoc_cmd(padapter, 0, true);
 296
 297                if (check_fwstate(pmlmepriv, _FW_LINKED) ||
 298                    check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
 299                        rtw_free_assoc_resources(padapter);
 300
 301                if (*pold_state == Ndis802_11Infrastructure ||
 302                    *pold_state == Ndis802_11IBSS) {
 303                        if (check_fwstate(pmlmepriv, _FW_LINKED))
 304                                rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have checked whether  issue dis-assoc_cmd or not */
 305                }
 306
 307                *pold_state = networktype;
 308
 309                _clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE);
 310
 311                switch (networktype) {
 312                case Ndis802_11IBSS:
 313                        set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
 314                        break;
 315                case Ndis802_11Infrastructure:
 316                        set_fwstate(pmlmepriv, WIFI_STATION_STATE);
 317                        break;
 318                case Ndis802_11APMode:
 319                        set_fwstate(pmlmepriv, WIFI_AP_STATE);
 320#ifdef CONFIG_88EU_AP_MODE
 321                        start_ap_mode(padapter);
 322#endif
 323                        break;
 324                case Ndis802_11AutoUnknown:
 325                case Ndis802_11InfrastructureMax:
 326                        break;
 327                }
 328                spin_unlock_bh(&pmlmepriv->lock);
 329        }
 330
 331        return true;
 332}
 333
 334u8 rtw_set_802_11_disassociate(struct adapter *padapter)
 335{
 336        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 337
 338        spin_lock_bh(&pmlmepriv->lock);
 339
 340        if (check_fwstate(pmlmepriv, _FW_LINKED)) {
 341                rtw_disassoc_cmd(padapter, 0, true);
 342                rtw_indicate_disconnect(padapter);
 343                rtw_free_assoc_resources(padapter);
 344                rtw_pwr_wakeup(padapter);
 345        }
 346
 347        spin_unlock_bh(&pmlmepriv->lock);
 348
 349        return true;
 350}
 351
 352u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_ssid *pssid, int ssid_max_num)
 353{
 354        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 355        u8 res = true;
 356
 357        if (!padapter) {
 358                res = false;
 359                goto exit;
 360        }
 361        if (!padapter->hw_init_completed) {
 362                res = false;
 363                goto exit;
 364        }
 365
 366        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) ||
 367            pmlmepriv->LinkDetectInfo.bBusyTraffic) {
 368                /*  Scan or linking is in progress, do nothing. */
 369                res = true;
 370        } else {
 371                if (rtw_is_scan_deny(padapter)) {
 372                        indicate_wx_scan_complete_event(padapter);
 373                        return _SUCCESS;
 374                }
 375
 376                spin_lock_bh(&pmlmepriv->lock);
 377
 378                res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, NULL, 0);
 379
 380                spin_unlock_bh(&pmlmepriv->lock);
 381        }
 382exit:
 383        return res;
 384}
 385
 386u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11_auth_mode authmode)
 387{
 388        struct security_priv *psecuritypriv = &padapter->securitypriv;
 389        int res;
 390        u8 ret;
 391
 392        psecuritypriv->ndisauthtype = authmode;
 393
 394        if (psecuritypriv->ndisauthtype > 3)
 395                psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
 396
 397        res = rtw_set_auth(padapter, psecuritypriv);
 398
 399        if (res == _SUCCESS)
 400                ret = true;
 401        else
 402                ret = false;
 403
 404        return ret;
 405}
 406
 407u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep)
 408{
 409        int keyid, res;
 410        struct security_priv *psecuritypriv = &padapter->securitypriv;
 411        u8 ret = _SUCCESS;
 412
 413        keyid = wep->KeyIndex & 0x3fffffff;
 414
 415        if (keyid >= 4) {
 416                ret = false;
 417                goto exit;
 418        }
 419
 420        switch (wep->KeyLength) {
 421        case 5:
 422                psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
 423                break;
 424        case 13:
 425                psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
 426                break;
 427        default:
 428                psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
 429                break;
 430        }
 431
 432        memcpy(&psecuritypriv->dot11DefKey[keyid].skey[0],
 433               &wep->KeyMaterial, wep->KeyLength);
 434
 435        psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength;
 436
 437        psecuritypriv->dot11PrivacyKeyIndex = keyid;
 438
 439        res = rtw_set_key(padapter, psecuritypriv, keyid, 1);
 440
 441        if (res == _FAIL)
 442                ret = false;
 443exit:
 444        return ret;
 445}
 446
 447/* Return 0 or 100Kbps */
 448u16 rtw_get_cur_max_rate(struct adapter *adapter)
 449{
 450        int i = 0;
 451        u8 *p;
 452        u16 rate = 0, max_rate = 0;
 453        struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
 454        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
 455        struct registry_priv *pregistrypriv = &adapter->registrypriv;
 456        struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
 457        struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
 458        u8 bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0;
 459        u32 ht_ielen = 0;
 460
 461        if (!check_fwstate(pmlmepriv, _FW_LINKED) &&
 462            !check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
 463                return 0;
 464
 465        if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N | WIRELESS_11_5N)) {
 466                p = rtw_get_ie(&pcur_bss->ies[12], WLAN_EID_HT_CAPABILITY,
 467                               &ht_ielen, pcur_bss->ie_length - 12);
 468                if (p && ht_ielen > 0) {
 469                        /* cur_bwmod is updated by beacon, pmlmeinfo is updated by association response */
 470                        bw_40MHz = (pmlmeext->cur_bwmode && (HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH & pmlmeinfo->HT_info.infos[0])) ? 1 : 0;
 471
 472                        short_GI_20 = (le16_to_cpu(pmlmeinfo->HT_caps.cap_info) & IEEE80211_HT_CAP_SGI_20) ? 1 : 0;
 473                        short_GI_40 = (le16_to_cpu(pmlmeinfo->HT_caps.cap_info) & IEEE80211_HT_CAP_SGI_40) ? 1 : 0;
 474
 475                        max_rate = rtw_mcs_rate(
 476                                RF_1T1R,
 477                                bw_40MHz & pregistrypriv->cbw40_enable,
 478                                short_GI_20,
 479                                short_GI_40,
 480                                pmlmeinfo->HT_caps.mcs.rx_mask
 481                        );
 482                }
 483        } else {
 484                while (pcur_bss->SupportedRates[i] != 0 &&
 485                       pcur_bss->SupportedRates[i] != 0xFF) {
 486                        rate = pcur_bss->SupportedRates[i] & 0x7F;
 487                        if (rate > max_rate)
 488                                max_rate = rate;
 489                        i++;
 490                }
 491
 492                max_rate *= 5;
 493        }
 494
 495        return max_rate;
 496}
 497
 498/* Return _SUCCESS or _FAIL */
 499int rtw_set_country(struct adapter *adapter, const char *country_code)
 500{
 501        int i;
 502        int channel_plan = RT_CHANNEL_DOMAIN_WORLD_WIDE_5G;
 503
 504        for (i = 0; i < ARRAY_SIZE(channel_table); i++) {
 505                if (strcmp(channel_table[i].name, country_code) == 0) {
 506                        channel_plan = channel_table[i].channel_plan;
 507                        break;
 508                }
 509        }
 510
 511        return rtw_set_chplan_cmd(adapter, channel_plan, 1);
 512}
 513