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