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_validate_ssid(struct ndis_802_11_ssid *ssid)
  17{
  18        u8       i;
  19        u8      ret = true;
  20
  21        if (ssid->SsidLength > 32) {
  22                ret = false;
  23                goto exit;
  24        }
  25
  26        for (i = 0; i < ssid->SsidLength; i++) {
  27                /* wifi, printable ascii code must be supported */
  28                if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) {
  29                        ret = false;
  30                        break;
  31                }
  32        }
  33
  34exit:
  35
  36        return ret;
  37}
  38
  39u8 rtw_do_join(struct adapter *padapter)
  40{
  41        struct list_head *plist, *phead;
  42        u8 *pibss = NULL;
  43        struct  mlme_priv       *pmlmepriv = &padapter->mlmepriv;
  44        struct __queue *queue   = &pmlmepriv->scanned_queue;
  45        u8 ret = _SUCCESS;
  46
  47        spin_lock_bh(&pmlmepriv->scanned_queue.lock);
  48        phead = get_list_head(queue);
  49        plist = phead->next;
  50
  51        pmlmepriv->cur_network.join_res = -2;
  52
  53        set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
  54
  55        pmlmepriv->pscanned = plist;
  56
  57        pmlmepriv->to_join = true;
  58
  59        if (list_empty(&queue->queue)) {
  60                spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
  61                _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
  62
  63                /* when set_ssid/set_bssid for rtw_do_join(), but scanning queue is empty */
  64                /* we try to issue sitesurvey firstly */
  65
  66                if (!pmlmepriv->LinkDetectInfo.bBusyTraffic ||
  67                    pmlmepriv->to_roaming > 0) {
  68                        /*  submit site_survey_cmd */
  69                        ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
  70                        if (_SUCCESS != ret)
  71                                pmlmepriv->to_join = false;
  72                } else {
  73                        pmlmepriv->to_join = false;
  74                        ret = _FAIL;
  75                }
  76
  77                goto exit;
  78        } else {
  79                int select_ret;
  80
  81                spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
  82                select_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv);
  83                if (select_ret == _SUCCESS) {
  84                        pmlmepriv->to_join = false;
  85                        _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT);
  86                } else {
  87                        if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
  88                                /*  submit createbss_cmd to change to a ADHOC_MASTER */
  89
  90                                /* pmlmepriv->lock has been acquired by caller... */
  91                                struct wlan_bssid_ex    *pdev_network = &padapter->registrypriv.dev_network;
  92
  93                                pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
  94
  95                                pibss = padapter->registrypriv.dev_network.MacAddress;
  96
  97                                memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid));
  98                                memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid));
  99
 100                                rtw_update_registrypriv_dev_network(padapter);
 101
 102                                rtw_generate_random_ibss(pibss);
 103
 104                                if (rtw_createbss_cmd(padapter) != _SUCCESS) {
 105                                        ret =  false;
 106                                        goto exit;
 107                                }
 108                                pmlmepriv->to_join = false;
 109                        } else {
 110                                /*  can't associate ; reset under-linking */
 111                                _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
 112
 113                                /* when set_ssid/set_bssid for rtw_do_join(), but there are no desired bss in scanning queue */
 114                                /* we try to issue sitesurvey firstly */
 115                                if (!pmlmepriv->LinkDetectInfo.bBusyTraffic ||
 116                                    pmlmepriv->to_roaming > 0) {
 117                                        ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
 118                                        if (_SUCCESS != ret)
 119                                                pmlmepriv->to_join = false;
 120                                } else {
 121                                        ret = _FAIL;
 122                                        pmlmepriv->to_join = false;
 123                                }
 124                        }
 125                }
 126        }
 127
 128exit:
 129
 130        return ret;
 131}
 132
 133u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid)
 134{
 135        u8 status = _SUCCESS;
 136        u32 cur_time = 0;
 137        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 138
 139        DBG_88E_LEVEL(_drv_info_, "set bssid:%pM\n", bssid);
 140
 141        if ((bssid[0] == 0x00 && bssid[1] == 0x00 && bssid[2] == 0x00 &&
 142             bssid[3] == 0x00 && bssid[4] == 0x00 && bssid[5] == 0x00) ||
 143            (bssid[0] == 0xFF && bssid[1] == 0xFF && bssid[2] == 0xFF &&
 144             bssid[3] == 0xFF && bssid[4] == 0xFF && bssid[5] == 0xFF)) {
 145                status = _FAIL;
 146                goto exit;
 147        }
 148
 149        spin_lock_bh(&pmlmepriv->lock);
 150
 151        DBG_88E("Set BSSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv));
 152        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
 153                goto handle_tkip_countermeasure;
 154        else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
 155                goto release_mlme_lock;
 156
 157        if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) {
 158                if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN)) {
 159                        if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE))
 160                                goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
 161                } else {
 162                        rtw_disassoc_cmd(padapter, 0, true);
 163
 164                        if (check_fwstate(pmlmepriv, _FW_LINKED))
 165                                rtw_indicate_disconnect(padapter);
 166
 167                        rtw_free_assoc_resources(padapter, 1);
 168
 169                        if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
 170                                _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
 171                                set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
 172                        }
 173                }
 174        }
 175
 176handle_tkip_countermeasure:
 177        /* should we add something here...? */
 178
 179        if (padapter->securitypriv.btkip_countermeasure) {
 180                cur_time = jiffies;
 181
 182                if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) {
 183                        padapter->securitypriv.btkip_countermeasure = false;
 184                        padapter->securitypriv.btkip_countermeasure_time = 0;
 185                } else {
 186                        status = _FAIL;
 187                        goto release_mlme_lock;
 188                }
 189        }
 190
 191        memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN);
 192        pmlmepriv->assoc_by_bssid = true;
 193
 194        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
 195                pmlmepriv->to_join = true;
 196        else
 197                status = rtw_do_join(padapter);
 198
 199release_mlme_lock:
 200        spin_unlock_bh(&pmlmepriv->lock);
 201
 202exit:
 203        return status;
 204}
 205
 206u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid)
 207{
 208        u8 status = _SUCCESS;
 209        u32 cur_time = 0;
 210
 211        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 212        struct wlan_network *pnetwork = &pmlmepriv->cur_network;
 213
 214        DBG_88E_LEVEL(_drv_info_, "set ssid [%s] fw_state=0x%08x\n",
 215                      ssid->Ssid, get_fwstate(pmlmepriv));
 216
 217        if (!padapter->hw_init_completed) {
 218                status = _FAIL;
 219                goto exit;
 220        }
 221
 222        spin_lock_bh(&pmlmepriv->lock);
 223
 224        DBG_88E("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv));
 225        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
 226                goto handle_tkip_countermeasure;
 227        } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
 228                goto release_mlme_lock;
 229        }
 230
 231        if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) {
 232                if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) &&
 233                    (!memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength))) {
 234                        if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
 235                                if (!rtw_is_same_ibss(padapter, pnetwork)) {
 236                                        /* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */
 237                                        rtw_disassoc_cmd(padapter, 0, true);
 238
 239                                        if (check_fwstate(pmlmepriv, _FW_LINKED))
 240                                                rtw_indicate_disconnect(padapter);
 241
 242                                        rtw_free_assoc_resources(padapter, 1);
 243
 244                                        if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
 245                                                _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
 246                                                set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
 247                                        }
 248                                } else {
 249                                        goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
 250                                }
 251                        } else {
 252                                rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_JOINBSS, 1);
 253                        }
 254                } else {
 255                        rtw_disassoc_cmd(padapter, 0, true);
 256
 257                        if (check_fwstate(pmlmepriv, _FW_LINKED))
 258                                rtw_indicate_disconnect(padapter);
 259
 260                        rtw_free_assoc_resources(padapter, 1);
 261
 262                        if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
 263                                _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
 264                                set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
 265                        }
 266                }
 267        }
 268
 269handle_tkip_countermeasure:
 270
 271        if (padapter->securitypriv.btkip_countermeasure) {
 272                cur_time = jiffies;
 273
 274                if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) {
 275                        padapter->securitypriv.btkip_countermeasure = false;
 276                        padapter->securitypriv.btkip_countermeasure_time = 0;
 277                } else {
 278                        status = _FAIL;
 279                        goto release_mlme_lock;
 280                }
 281        }
 282
 283        memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid));
 284        pmlmepriv->assoc_by_bssid = false;
 285
 286        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
 287                pmlmepriv->to_join = true;
 288        } else {
 289                status = rtw_do_join(padapter);
 290        }
 291
 292release_mlme_lock:
 293        spin_unlock_bh(&pmlmepriv->lock);
 294
 295exit:
 296        return status;
 297}
 298
 299u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter,
 300        enum ndis_802_11_network_infra networktype)
 301{
 302        struct  mlme_priv       *pmlmepriv = &padapter->mlmepriv;
 303        struct  wlan_network    *cur_network = &pmlmepriv->cur_network;
 304        enum ndis_802_11_network_infra *pold_state = &cur_network->network.InfrastructureMode;
 305
 306        if (*pold_state != networktype) {
 307                spin_lock_bh(&pmlmepriv->lock);
 308
 309                /* DBG_88E("change mode, old_mode =%d, new_mode =%d, fw_state = 0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */
 310
 311                if (*pold_state == Ndis802_11APMode) {
 312                        /* change to other mode from Ndis802_11APMode */
 313                        cur_network->join_res = -1;
 314
 315#ifdef CONFIG_88EU_AP_MODE
 316                        stop_ap_mode(padapter);
 317#endif
 318                }
 319
 320                if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
 321                    (*pold_state == Ndis802_11IBSS))
 322                        rtw_disassoc_cmd(padapter, 0, true);
 323
 324                if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
 325                    (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)))
 326                        rtw_free_assoc_resources(padapter, 1);
 327
 328                if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) {
 329                        if (check_fwstate(pmlmepriv, _FW_LINKED))
 330                                rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have chked whether  issue dis-assoc_cmd or not */
 331               }
 332
 333                *pold_state = networktype;
 334
 335                _clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE);
 336
 337                switch (networktype) {
 338                case Ndis802_11IBSS:
 339                        set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
 340                        break;
 341                case Ndis802_11Infrastructure:
 342                        set_fwstate(pmlmepriv, WIFI_STATION_STATE);
 343                        break;
 344                case Ndis802_11APMode:
 345                        set_fwstate(pmlmepriv, WIFI_AP_STATE);
 346#ifdef CONFIG_88EU_AP_MODE
 347                        start_ap_mode(padapter);
 348#endif
 349                        break;
 350                case Ndis802_11AutoUnknown:
 351                case Ndis802_11InfrastructureMax:
 352                        break;
 353                }
 354                spin_unlock_bh(&pmlmepriv->lock);
 355        }
 356
 357        return true;
 358}
 359
 360u8 rtw_set_802_11_disassociate(struct adapter *padapter)
 361{
 362        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 363
 364        spin_lock_bh(&pmlmepriv->lock);
 365
 366        if (check_fwstate(pmlmepriv, _FW_LINKED)) {
 367                rtw_disassoc_cmd(padapter, 0, true);
 368                rtw_indicate_disconnect(padapter);
 369                rtw_free_assoc_resources(padapter, 1);
 370                rtw_pwr_wakeup(padapter);
 371        }
 372
 373        spin_unlock_bh(&pmlmepriv->lock);
 374
 375        return true;
 376}
 377
 378u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_ssid *pssid, int ssid_max_num)
 379{
 380        struct  mlme_priv               *pmlmepriv = &padapter->mlmepriv;
 381        u8      res = true;
 382
 383        if (!padapter) {
 384                res = false;
 385                goto exit;
 386        }
 387        if (!padapter->hw_init_completed) {
 388                res = false;
 389                goto exit;
 390        }
 391
 392        if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING)) ||
 393            (pmlmepriv->LinkDetectInfo.bBusyTraffic)) {
 394                /*  Scan or linking is in progress, do nothing. */
 395                res = true;
 396        } else {
 397                if (rtw_is_scan_deny(padapter)) {
 398                        DBG_88E(FUNC_ADPT_FMT": scan deny\n", FUNC_ADPT_ARG(padapter));
 399                        indicate_wx_scan_complete_event(padapter);
 400                        return _SUCCESS;
 401                }
 402
 403                spin_lock_bh(&pmlmepriv->lock);
 404
 405                res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, NULL, 0);
 406
 407                spin_unlock_bh(&pmlmepriv->lock);
 408        }
 409exit:
 410
 411        return res;
 412}
 413
 414u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11_auth_mode authmode)
 415{
 416        struct security_priv *psecuritypriv = &padapter->securitypriv;
 417        int res;
 418        u8 ret;
 419
 420        psecuritypriv->ndisauthtype = authmode;
 421
 422        if (psecuritypriv->ndisauthtype > 3)
 423                psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
 424
 425        res = rtw_set_auth(padapter, psecuritypriv);
 426
 427        if (res == _SUCCESS)
 428                ret = true;
 429        else
 430                ret = false;
 431
 432        return ret;
 433}
 434
 435u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep)
 436{
 437        int             keyid, res;
 438        struct security_priv *psecuritypriv = &padapter->securitypriv;
 439        u8              ret = _SUCCESS;
 440
 441        keyid = wep->KeyIndex & 0x3fffffff;
 442
 443        if (keyid >= 4) {
 444                ret = false;
 445                goto exit;
 446        }
 447
 448        switch (wep->KeyLength) {
 449        case 5:
 450                psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
 451                break;
 452        case 13:
 453                psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
 454                break;
 455        default:
 456                psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
 457                break;
 458        }
 459
 460        memcpy(&psecuritypriv->dot11DefKey[keyid].skey[0], &wep->KeyMaterial, wep->KeyLength);
 461
 462        psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength;
 463
 464        psecuritypriv->dot11PrivacyKeyIndex = keyid;
 465
 466        res = rtw_set_key(padapter, psecuritypriv, keyid, 1);
 467
 468        if (res == _FAIL)
 469                ret = false;
 470exit:
 471
 472        return ret;
 473}
 474
 475u8 rtw_set_802_11_remove_wep(struct adapter *padapter, u32 keyindex)
 476{
 477        u8 ret = _SUCCESS;
 478
 479        if (keyindex >= 0x80000000 || !padapter) {
 480                ret = false;
 481                goto exit;
 482        } else {
 483                int res;
 484                struct security_priv *psecuritypriv = &padapter->securitypriv;
 485                if (keyindex < 4) {
 486                        memset(&psecuritypriv->dot11DefKey[keyindex], 0, 16);
 487                        res = rtw_set_key(padapter, psecuritypriv, keyindex, 0);
 488                        psecuritypriv->dot11DefKeylen[keyindex] = 0;
 489                        if (res == _FAIL)
 490                                ret = _FAIL;
 491                } else {
 492                        ret = _FAIL;
 493                }
 494        }
 495exit:
 496
 497        return ret;
 498}
 499
 500u8 rtw_set_802_11_add_key(struct adapter *padapter, struct ndis_802_11_key *key)
 501{
 502        uint    encryptionalgo;
 503        u8 *pbssid;
 504        struct sta_info *stainfo;
 505        u8      bgroup = false;
 506        u8      bgrouptkey = false;/* can be removed later */
 507        u8      ret = _SUCCESS;
 508
 509        if (((key->KeyIndex & 0x80000000) == 0) && ((key->KeyIndex & 0x40000000) > 0)) {
 510                /*  It is invalid to clear bit 31 and set bit 30. If the miniport driver encounters this combination, */
 511                /*  it must fail the request and return NDIS_STATUS_INVALID_DATA. */
 512                ret = _FAIL;
 513                goto exit;
 514        }
 515
 516        if (key->KeyIndex & 0x40000000) {
 517                /*  Pairwise key */
 518
 519                pbssid = get_bssid(&padapter->mlmepriv);
 520                stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid);
 521
 522                if (stainfo && padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
 523                        encryptionalgo = stainfo->dot118021XPrivacy;
 524                else
 525                        encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm;
 526
 527                if (key->KeyIndex & 0x000000FF) {
 528                        /*  The key index is specified in the lower 8 bits by values of zero to 255. */
 529                        /*  The key index should be set to zero for a Pairwise key, and the driver should fail with */
 530                        /*  NDIS_STATUS_INVALID_DATA if the lower 8 bits is not zero */
 531                        ret = _FAIL;
 532                        goto exit;
 533                }
 534
 535                /*  check BSSID */
 536                if (is_broadcast_ether_addr(key->BSSID)) {
 537                        ret = false;
 538                        goto exit;
 539                }
 540
 541                /*  Check key length for TKIP. */
 542                if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) {
 543                        ret = _FAIL;
 544                        goto exit;
 545                }
 546
 547                /*  Check key length for AES. */
 548                if ((encryptionalgo == _AES_) && (key->KeyLength != 16)) {
 549                        /*  For our supplicant, EAPPkt9x.vxd, cannot differentiate TKIP and AES case. */
 550                        if (key->KeyLength == 32) {
 551                                key->KeyLength = 16;
 552                        } else {
 553                                ret = _FAIL;
 554                                goto exit;
 555                        }
 556                }
 557
 558                /*  Check key length for WEP. For NDTEST, 2005.01.27, by rcnjko. */
 559                if ((encryptionalgo == _WEP40_ || encryptionalgo == _WEP104_) &&
 560                    (key->KeyLength != 5 && key->KeyLength != 13)) {
 561                        ret = _FAIL;
 562                        goto exit;
 563                }
 564
 565                bgroup = false;
 566        } else {
 567                /*  Group key - KeyIndex(BIT(30) == 0) */
 568                /*  when add wep key through add key and didn't assigned encryption type before */
 569                if ((padapter->securitypriv.ndisauthtype <= 3) &&
 570                    (padapter->securitypriv.dot118021XGrpPrivacy == 0)) {
 571                        switch (key->KeyLength) {
 572                        case 5:
 573                                padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
 574                                break;
 575                        case 13:
 576                                padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
 577                                break;
 578                        default:
 579                                padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
 580                                break;
 581                        }
 582
 583                        encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm;
 584                } else {
 585                        encryptionalgo = padapter->securitypriv.dot118021XGrpPrivacy;
 586                }
 587
 588                if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE) && !is_broadcast_ether_addr(key->BSSID)) {
 589                        ret = _FAIL;
 590                        goto exit;
 591                }
 592
 593                /*  Check key length for TKIP */
 594                if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) {
 595                        ret = _FAIL;
 596                        goto exit;
 597                } else if (encryptionalgo == _AES_ && (key->KeyLength != 16 && key->KeyLength != 32)) {
 598                        /*  Check key length for AES */
 599                        /*  For NDTEST, we allow keylen = 32 in this case. 2005.01.27, by rcnjko. */
 600                        ret = _FAIL;
 601                        goto exit;
 602                }
 603
 604                /*  Change the key length for EAPPkt9x.vxd. Added by Annie, 2005-11-03. */
 605                if ((encryptionalgo ==  _AES_) && (key->KeyLength == 32))
 606                        key->KeyLength = 16;
 607
 608                if (key->KeyIndex & 0x8000000) {/* error ??? 0x8000_0000 */
 609                        bgrouptkey = true;
 610                }
 611
 612                if ((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE)) &&
 613                    (check_fwstate(&padapter->mlmepriv, _FW_LINKED)))
 614                        bgrouptkey = true;
 615                bgroup = true;
 616        }
 617
 618        /*  If WEP encryption algorithm, just call rtw_set_802_11_add_wep(). */
 619        if ((padapter->securitypriv.dot11AuthAlgrthm != dot11AuthAlgrthm_8021X) &&
 620            (encryptionalgo == _WEP40_ || encryptionalgo == _WEP104_)) {
 621                u32 keyindex;
 622                u32 len = FIELD_OFFSET(struct ndis_802_11_key, KeyMaterial) + key->KeyLength;
 623                struct ndis_802_11_wep *wep = &padapter->securitypriv.ndiswep;
 624
 625                wep->Length = len;
 626                keyindex = key->KeyIndex & 0x7fffffff;
 627                wep->KeyIndex = keyindex;
 628                wep->KeyLength = key->KeyLength;
 629
 630                memcpy(wep->KeyMaterial, key->KeyMaterial, key->KeyLength);
 631                memcpy(&padapter->securitypriv.dot11DefKey[keyindex].skey[0], key->KeyMaterial, key->KeyLength);
 632
 633                padapter->securitypriv.dot11DefKeylen[keyindex] = key->KeyLength;
 634                padapter->securitypriv.dot11PrivacyKeyIndex = keyindex;
 635
 636                ret = rtw_set_802_11_add_wep(padapter, wep);
 637                goto exit;
 638        }
 639        if (key->KeyIndex & 0x20000000) {
 640                /*  SetRSC */
 641                if (bgroup) {
 642                        unsigned long long keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL;
 643                        memcpy(&padapter->securitypriv.dot11Grprxpn, &keysrc, 8);
 644                } else {
 645                        unsigned long long keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL;
 646                        memcpy(&padapter->securitypriv.dot11Grptxpn, &keysrc, 8);
 647                }
 648        }
 649
 650        /*  Indicate this key idx is used for TX */
 651        /*  Save the key in KeyMaterial */
 652        if (bgroup) { /*  Group transmit key */
 653                int res;
 654
 655                if (bgrouptkey)
 656                        padapter->securitypriv.dot118021XGrpKeyid = (u8)key->KeyIndex;
 657                if ((key->KeyIndex & 0x3) == 0) {
 658                        ret = _FAIL;
 659                        goto exit;
 660                }
 661                memset(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], 0, 16);
 662                memset(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16);
 663                memset(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16);
 664
 665                if ((key->KeyIndex & 0x10000000)) {
 666                        memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8);
 667                        memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8);
 668                } else {
 669                        memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8);
 670                        memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8);
 671                }
 672
 673                /* set group key by index */
 674                memcpy(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial, key->KeyLength);
 675
 676                key->KeyIndex = key->KeyIndex & 0x03;
 677
 678                padapter->securitypriv.binstallGrpkey = true;
 679
 680                padapter->securitypriv.bcheck_grpkey = false;
 681
 682                res = rtw_set_key(padapter, &padapter->securitypriv, key->KeyIndex, 1);
 683
 684                if (res == _FAIL)
 685                        ret = _FAIL;
 686
 687                goto exit;
 688
 689        } else { /*  Pairwise Key */
 690                u8 res;
 691
 692                pbssid = get_bssid(&padapter->mlmepriv);
 693                stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid);
 694
 695                if (stainfo) {
 696                        memset(&stainfo->dot118021x_UncstKey, 0, 16);/*  clear keybuffer */
 697
 698                        memcpy(&stainfo->dot118021x_UncstKey, key->KeyMaterial, 16);
 699
 700                        if (encryptionalgo == _TKIP_) {
 701                                padapter->securitypriv.busetkipkey = false;
 702
 703                                /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */
 704
 705                                /*  if TKIP, save the Receive/Transmit MIC key in KeyMaterial[128-255] */
 706                                if ((key->KeyIndex & 0x10000000)) {
 707                                        memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 16, 8);
 708                                        memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 24, 8);
 709
 710                                } else {
 711                                        memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 24, 8);
 712                                        memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 16, 8);
 713                                }
 714                        }
 715
 716                        /* Set key to CAM through H2C command */
 717                        if (bgrouptkey) /* never go to here */
 718                                res = rtw_setstakey_cmd(padapter, (unsigned char *)stainfo, false);
 719                        else
 720                                res = rtw_setstakey_cmd(padapter, (unsigned char *)stainfo, true);
 721                        if (!res)
 722                                ret = _FAIL;
 723                }
 724        }
 725exit:
 726
 727        return ret;
 728}
 729
 730u8 rtw_set_802_11_remove_key(struct adapter *padapter, struct ndis_802_11_remove_key *key)
 731{
 732        u8 *pbssid;
 733        struct sta_info *stainfo;
 734        u8      bgroup = (key->KeyIndex & 0x4000000) > 0 ? false : true;
 735        u8      keyIndex = (u8)key->KeyIndex & 0x03;
 736        u8      ret = _SUCCESS;
 737
 738        if ((key->KeyIndex & 0xbffffffc) > 0) {
 739                ret = _FAIL;
 740                goto exit;
 741        }
 742
 743        if (bgroup) {
 744                /*  clear group key by index */
 745
 746                memset(&padapter->securitypriv.dot118021XGrpKey[keyIndex], 0, 16);
 747
 748                /*  \todo Send a H2C Command to Firmware for removing this Key in CAM Entry. */
 749        } else {
 750                pbssid = get_bssid(&padapter->mlmepriv);
 751                stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid);
 752                if (stainfo) {
 753                        /*  clear key by BSSID */
 754                        memset(&stainfo->dot118021x_UncstKey, 0, 16);
 755
 756                        /*  \todo Send a H2C Command to Firmware for disable this Key in CAM Entry. */
 757                } else {
 758                        ret = _FAIL;
 759                        goto exit;
 760                }
 761        }
 762exit:
 763
 764        return ret;
 765}
 766
 767/*
 768* rtw_get_cur_max_rate -
 769* @adapter: pointer to struct adapter structure
 770*
 771* Return 0 or 100Kbps
 772*/
 773u16 rtw_get_cur_max_rate(struct adapter *adapter)
 774{
 775        int     i = 0;
 776        u8      *p;
 777        u16     rate = 0, max_rate = 0;
 778        struct mlme_ext_priv    *pmlmeext = &adapter->mlmeextpriv;
 779        struct mlme_ext_info    *pmlmeinfo = &pmlmeext->mlmext_info;
 780        struct registry_priv *pregistrypriv = &adapter->registrypriv;
 781        struct mlme_priv        *pmlmepriv = &adapter->mlmepriv;
 782        struct wlan_bssid_ex  *pcur_bss = &pmlmepriv->cur_network.network;
 783        struct ieee80211_ht_cap *pht_capie;
 784        u8      rf_type = 0;
 785        u8      bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0;
 786        u16     mcs_rate = 0;
 787        u32     ht_ielen = 0;
 788
 789        if (adapter->registrypriv.mp_mode == 1) {
 790                if (check_fwstate(pmlmepriv, WIFI_MP_STATE))
 791                        return 0;
 792        }
 793
 794        if ((!check_fwstate(pmlmepriv, _FW_LINKED)) &&
 795            (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)))
 796                return 0;
 797
 798        if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N)) {
 799                p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength - 12);
 800                if (p && ht_ielen > 0) {
 801                        pht_capie = (struct ieee80211_ht_cap *)(p + 2);
 802
 803                        memcpy(&mcs_rate, pht_capie->mcs.rx_mask, 2);
 804
 805                        /* cur_bwmod is updated by beacon, pmlmeinfo is updated by association response */
 806                        bw_40MHz = (pmlmeext->cur_bwmode && (HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH & pmlmeinfo->HT_info.infos[0])) ? 1 : 0;
 807
 808                        short_GI_20 = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & IEEE80211_HT_CAP_SGI_20) ? 1 : 0;
 809                        short_GI_40 = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & IEEE80211_HT_CAP_SGI_40) ? 1 : 0;
 810
 811                        rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
 812                        max_rate = rtw_mcs_rate(
 813                                rf_type,
 814                                bw_40MHz & (pregistrypriv->cbw40_enable),
 815                                short_GI_20,
 816                                short_GI_40,
 817                                pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate
 818                        );
 819                }
 820        } else {
 821                while ((pcur_bss->SupportedRates[i] != 0) && (pcur_bss->SupportedRates[i] != 0xFF)) {
 822                        rate = pcur_bss->SupportedRates[i] & 0x7F;
 823                        if (rate > max_rate)
 824                                max_rate = rate;
 825                        i++;
 826                }
 827
 828                max_rate *= 5;
 829        }
 830
 831        return max_rate;
 832}
 833
 834/*
 835* rtw_set_scan_mode -
 836* @adapter: pointer to struct adapter structure
 837* @scan_mode:
 838*
 839* Return _SUCCESS or _FAIL
 840*/
 841int rtw_set_scan_mode(struct adapter *adapter, enum rt_scan_type scan_mode)
 842{
 843        if (scan_mode != SCAN_ACTIVE && scan_mode != SCAN_PASSIVE)
 844                return _FAIL;
 845
 846        adapter->mlmepriv.scan_mode = scan_mode;
 847
 848        return _SUCCESS;
 849}
 850
 851/*
 852* rtw_set_channel_plan -
 853* @adapter: pointer to struct adapter structure
 854* @channel_plan:
 855*
 856* Return _SUCCESS or _FAIL
 857*/
 858int rtw_set_channel_plan(struct adapter *adapter, u8 channel_plan)
 859{
 860        /* handle by cmd_thread to sync with scan operation */
 861        return rtw_set_chplan_cmd(adapter, channel_plan, 1);
 862}
 863
 864/*
 865* rtw_set_country -
 866* @adapter: pointer to struct adapter structure
 867* @country_code: string of country code
 868*
 869* Return _SUCCESS or _FAIL
 870*/
 871int rtw_set_country(struct adapter *adapter, const char *country_code)
 872{
 873        int channel_plan = RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G;
 874
 875        DBG_88E("%s country_code:%s\n", __func__, country_code);
 876
 877        /* TODO: should have a table to match country code and RT_CHANNEL_DOMAIN */
 878        /* TODO: should consider 2-character and 3-character country code */
 879        if (0 == strcmp(country_code, "US"))
 880                channel_plan = RT_CHANNEL_DOMAIN_FCC;
 881        else if (0 == strcmp(country_code, "EU"))
 882                channel_plan = RT_CHANNEL_DOMAIN_ETSI;
 883        else if (0 == strcmp(country_code, "JP"))
 884                channel_plan = RT_CHANNEL_DOMAIN_MKK;
 885        else if (0 == strcmp(country_code, "CN"))
 886                channel_plan = RT_CHANNEL_DOMAIN_CHINA;
 887        else
 888                DBG_88E("%s unknown country_code:%s\n", __func__, country_code);
 889
 890        return rtw_set_channel_plan(adapter, channel_plan);
 891}
 892