linux/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/******************************************************************************
   3 *
   4 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
   5 *
   6 ******************************************************************************/
   7#define _IEEE80211_C
   8
   9#include <linux/ieee80211.h>
  10
  11#include <drv_types.h>
  12#include <osdep_intf.h>
  13#include <ieee80211.h>
  14#include <wifi.h>
  15#include <osdep_service.h>
  16#include <wlan_bssdef.h>
  17
  18u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
  19u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 };
  20u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 };
  21u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 };
  22u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 };
  23u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 };
  24u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 };
  25u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 };
  26u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 };
  27u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
  28
  29u16 RSN_VERSION_BSD = 1;
  30u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 };
  31u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 };
  32u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 };
  33u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 };
  34u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 };
  35u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 };
  36u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 };
  37u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 };
  38/*  */
  39/*  for adhoc-master to generate ie and provide supported-rate to fw */
  40/*  */
  41
  42static u8 WIFI_CCKRATES[] = {
  43        IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK,
  44        IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK,
  45        IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK,
  46        IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK
  47};
  48
  49static u8 WIFI_OFDMRATES[] = {
  50         IEEE80211_OFDM_RATE_6MB,
  51         IEEE80211_OFDM_RATE_9MB,
  52         IEEE80211_OFDM_RATE_12MB,
  53         IEEE80211_OFDM_RATE_18MB,
  54         IEEE80211_OFDM_RATE_24MB,
  55         IEEE80211_OFDM_RATE_36MB,
  56         IEEE80211_OFDM_RATE_48MB,
  57         IEEE80211_OFDM_RATE_54MB
  58};
  59
  60int rtw_get_bit_value_from_ieee_value(u8 val)
  61{
  62        static const unsigned char dot11_rate_table[] = {
  63                2, 4, 11, 22, 12, 18, 24, 36, 48,
  64                72, 96, 108, 0}; /*  last element must be zero!! */
  65        int i = 0;
  66
  67        while (dot11_rate_table[i] != 0) {
  68                if (dot11_rate_table[i] == val)
  69                        return BIT(i);
  70                i++;
  71        }
  72        return 0;
  73}
  74
  75bool rtw_is_cckrates_included(u8 *rate)
  76{
  77        while (*rate) {
  78                u8 r = *rate & 0x7f;
  79
  80                if (r == 2 || r == 4 || r == 11 || r == 22)
  81                        return true;
  82                rate++;
  83        }
  84
  85        return false;
  86}
  87
  88bool rtw_is_cckratesonly_included(u8 *rate)
  89{
  90        while (*rate) {
  91                u8 r = *rate & 0x7f;
  92
  93                if (r != 2 && r != 4 && r != 11 && r != 22)
  94                        return false;
  95                rate++;
  96        }
  97
  98        return true;
  99}
 100
 101int rtw_check_network_type(unsigned char *rate)
 102{
 103        /*  could be pure B, pure G, or B/G */
 104        if (rtw_is_cckratesonly_included(rate))
 105                return WIRELESS_11B;
 106        else if (rtw_is_cckrates_included(rate))
 107                return  WIRELESS_11BG;
 108        else
 109                return WIRELESS_11G;
 110}
 111
 112u8 *rtw_set_fixed_ie(void *pbuf, unsigned int len, void *source,
 113                     unsigned int *frlen)
 114{
 115        memcpy(pbuf, source, len);
 116        *frlen = *frlen + len;
 117        return ((u8 *)pbuf) + len;
 118}
 119
 120/*  rtw_set_ie will update frame length */
 121u8 *rtw_set_ie
 122(
 123        u8 *pbuf,
 124        int index,
 125        uint len,
 126        u8 *source,
 127        uint *frlen /* frame length */
 128)
 129{
 130        *pbuf = (u8)index;
 131
 132        *(pbuf + 1) = (u8)len;
 133
 134        if (len > 0)
 135                memcpy((void *)(pbuf + 2), (void *)source, len);
 136
 137        *frlen = *frlen + (len + 2);
 138
 139        return pbuf + len + 2;
 140}
 141
 142/*
 143 * ----------------------------------------------------------------------------
 144 * index: the information element id index, limit is the limit for search
 145 * ----------------------------------------------------------------------------
 146 */
 147u8 *rtw_get_ie(u8 *pbuf, int index, uint *len, int limit)
 148{
 149        int tmp, i;
 150        u8 *p;
 151
 152        if (limit < 1)
 153                return NULL;
 154
 155        p = pbuf;
 156        i = 0;
 157        *len = 0;
 158        while (1) {
 159                if (*p == index) {
 160                        *len = *(p + 1);
 161                        return p;
 162                }
 163                tmp = *(p + 1);
 164                p += (tmp + 2);
 165                i += (tmp + 2);
 166                if (i >= limit)
 167                        break;
 168        }
 169        return NULL;
 170}
 171
 172void rtw_set_supported_rate(u8 *SupportedRates, uint mode)
 173{
 174        memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
 175
 176        switch (mode) {
 177        case WIRELESS_11B:
 178                memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
 179                break;
 180        case WIRELESS_11G:
 181        case WIRELESS_11A:
 182        case WIRELESS_11_5N:
 183        case WIRELESS_11A_5N:/* Todo: no basic rate for ofdm ? */
 184                memcpy(SupportedRates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
 185                break;
 186        case WIRELESS_11BG:
 187        case WIRELESS_11G_24N:
 188        case WIRELESS_11_24N:
 189        case WIRELESS_11BG_24N:
 190                memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
 191                memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
 192                break;
 193        }
 194}
 195
 196uint rtw_get_rateset_len(u8 *rateset)
 197{
 198        uint i;
 199
 200        for (i = 0; i < 13; i++)
 201                if (rateset[i] == 0)
 202                        break;
 203        return i;
 204}
 205
 206int rtw_generate_ie(struct registry_priv *pregistrypriv)
 207{
 208        u8 wireless_mode;
 209        int rateLen;
 210        uint sz = 0;
 211        struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
 212        u8 *ie = pdev_network->ies;
 213
 214        /* timestamp will be inserted by hardware */
 215        sz += 8;
 216        ie += sz;
 217
 218        /* beacon interval : 2bytes */
 219        *(__le16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);/* BCN_INTERVAL; */
 220        sz += 2;
 221        ie += 2;
 222
 223        /* capability info */
 224        *(u16 *)ie = 0;
 225
 226        *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_IBSS);
 227
 228        if (pregistrypriv->preamble == PREAMBLE_SHORT)
 229                *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
 230
 231        if (pdev_network->Privacy)
 232                *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
 233
 234        sz += 2;
 235        ie += 2;
 236
 237        /* SSID */
 238        ie = rtw_set_ie(ie, WLAN_EID_SSID, pdev_network->ssid.ssid_length, pdev_network->ssid.ssid, &sz);
 239
 240        /* supported rates */
 241        if (pregistrypriv->wireless_mode == WIRELESS_11ABGN)
 242                wireless_mode = WIRELESS_11BG_24N;
 243        else
 244                wireless_mode = pregistrypriv->wireless_mode;
 245
 246        rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode);
 247
 248        rateLen = rtw_get_rateset_len(pdev_network->SupportedRates);
 249
 250        if (rateLen > 8) {
 251                ie = rtw_set_ie(ie, WLAN_EID_SUPP_RATES, 8, pdev_network->SupportedRates, &sz);
 252                /* ie = rtw_set_ie(ie, WLAN_EID_EXT_SUPP_RATES, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); */
 253        } else {
 254                ie = rtw_set_ie(ie, WLAN_EID_SUPP_RATES, rateLen, pdev_network->SupportedRates, &sz);
 255        }
 256
 257        /* DS parameter set */
 258        ie = rtw_set_ie(ie, WLAN_EID_DS_PARAMS, 1, (u8 *)&pdev_network->Configuration.DSConfig, &sz);
 259
 260        /* IBSS Parameter Set */
 261
 262        ie = rtw_set_ie(ie, WLAN_EID_IBSS_PARAMS, 2, (u8 *)&pdev_network->Configuration.ATIMWindow, &sz);
 263
 264        if (rateLen > 8)
 265                ie = rtw_set_ie(ie, WLAN_EID_EXT_SUPP_RATES, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz);
 266
 267        return sz;
 268}
 269
 270unsigned char *rtw_get_wpa_ie(unsigned char *pie, uint *wpa_ie_len, int limit)
 271{
 272        uint len;
 273        u16 val16;
 274        __le16 le_tmp;
 275        static const unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
 276        u8 *pbuf = pie;
 277        int limit_new = limit;
 278
 279        while (1) {
 280                pbuf = rtw_get_ie(pbuf, WLAN_EID_VENDOR_SPECIFIC, &len, limit_new);
 281
 282                if (pbuf) {
 283                        /* check if oui matches... */
 284                        if (memcmp((pbuf + 2), wpa_oui_type, sizeof(wpa_oui_type)))
 285                                goto check_next_ie;
 286
 287                        /* check version... */
 288                        memcpy((u8 *)&le_tmp, (pbuf + 6), sizeof(val16));
 289
 290                        val16 = le16_to_cpu(le_tmp);
 291                        if (val16 != 0x0001)
 292                                goto check_next_ie;
 293                        *wpa_ie_len = *(pbuf + 1);
 294                        return pbuf;
 295                }
 296                *wpa_ie_len = 0;
 297                return NULL;
 298
 299check_next_ie:
 300                limit_new = limit - (pbuf - pie) - 2 - len;
 301                if (limit_new <= 0)
 302                        break;
 303                pbuf += (2 + len);
 304        }
 305        *wpa_ie_len = 0;
 306        return NULL;
 307}
 308
 309unsigned char *rtw_get_wpa2_ie(unsigned char *pie, uint *rsn_ie_len, int limit)
 310{
 311        return rtw_get_ie(pie, WLAN_EID_RSN, rsn_ie_len, limit);
 312}
 313
 314int rtw_get_wpa_cipher_suite(u8 *s)
 315{
 316        if (!memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN))
 317                return WPA_CIPHER_NONE;
 318        if (!memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN))
 319                return WPA_CIPHER_WEP40;
 320        if (!memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN))
 321                return WPA_CIPHER_TKIP;
 322        if (!memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN))
 323                return WPA_CIPHER_CCMP;
 324        if (!memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN))
 325                return WPA_CIPHER_WEP104;
 326
 327        return 0;
 328}
 329
 330int rtw_get_wpa2_cipher_suite(u8 *s)
 331{
 332        if (!memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN))
 333                return WPA_CIPHER_NONE;
 334        if (!memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN))
 335                return WPA_CIPHER_WEP40;
 336        if (!memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN))
 337                return WPA_CIPHER_TKIP;
 338        if (!memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN))
 339                return WPA_CIPHER_CCMP;
 340        if (!memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN))
 341                return WPA_CIPHER_WEP104;
 342
 343        return 0;
 344}
 345
 346int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
 347{
 348        int i, ret = _SUCCESS;
 349        int left, count;
 350        u8 *pos;
 351        u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1};
 352
 353        if (wpa_ie_len <= 0) {
 354                /* No WPA IE - fail silently */
 355                return _FAIL;
 356        }
 357
 358        if ((*wpa_ie != WLAN_EID_VENDOR_SPECIFIC) || (*(wpa_ie + 1) != (u8)(wpa_ie_len - 2)) ||
 359            (memcmp(wpa_ie + 2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN)))
 360                return _FAIL;
 361
 362        pos = wpa_ie;
 363
 364        pos += 8;
 365        left = wpa_ie_len - 8;
 366
 367        /* group_cipher */
 368        if (left >= WPA_SELECTOR_LEN) {
 369                *group_cipher = rtw_get_wpa_cipher_suite(pos);
 370                pos += WPA_SELECTOR_LEN;
 371                left -= WPA_SELECTOR_LEN;
 372        } else if (left > 0) {
 373                return _FAIL;
 374        }
 375
 376        /* pairwise_cipher */
 377        if (left >= 2) {
 378                count = get_unaligned_le16(pos);
 379                pos += 2;
 380                left -= 2;
 381
 382                if (count == 0 || left < count * WPA_SELECTOR_LEN)
 383                        return _FAIL;
 384
 385                for (i = 0; i < count; i++) {
 386                        *pairwise_cipher |= rtw_get_wpa_cipher_suite(pos);
 387
 388                        pos += WPA_SELECTOR_LEN;
 389                        left -= WPA_SELECTOR_LEN;
 390                }
 391        } else if (left == 1) {
 392                return _FAIL;
 393        }
 394
 395        if (is_8021x) {
 396                if (left >= 6) {
 397                        pos += 2;
 398                        if (!memcmp(pos, SUITE_1X, 4))
 399                                *is_8021x = 1;
 400                }
 401        }
 402
 403        return ret;
 404}
 405
 406int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
 407{
 408        int i, ret = _SUCCESS;
 409        int left, count;
 410        u8 *pos;
 411        u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01};
 412
 413        if (rsn_ie_len <= 0) {
 414                /* No RSN IE - fail silently */
 415                return _FAIL;
 416        }
 417
 418        if ((*rsn_ie != WLAN_EID_RSN) || (*(rsn_ie + 1) != (u8)(rsn_ie_len - 2)))
 419                return _FAIL;
 420
 421        pos = rsn_ie;
 422        pos += 4;
 423        left = rsn_ie_len - 4;
 424
 425        /* group_cipher */
 426        if (left >= RSN_SELECTOR_LEN) {
 427                *group_cipher = rtw_get_wpa2_cipher_suite(pos);
 428
 429                pos += RSN_SELECTOR_LEN;
 430                left -= RSN_SELECTOR_LEN;
 431
 432        } else if (left > 0) {
 433                return _FAIL;
 434        }
 435
 436        /* pairwise_cipher */
 437        if (left >= 2) {
 438                count = get_unaligned_le16(pos);
 439                pos += 2;
 440                left -= 2;
 441
 442                if (count == 0 || left < count * RSN_SELECTOR_LEN)
 443                        return _FAIL;
 444
 445                for (i = 0; i < count; i++) {
 446                        *pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos);
 447
 448                        pos += RSN_SELECTOR_LEN;
 449                        left -= RSN_SELECTOR_LEN;
 450                }
 451
 452        } else if (left == 1) {
 453                return _FAIL;
 454        }
 455
 456        if (is_8021x) {
 457                if (left >= 6) {
 458                        pos += 2;
 459                        if (!memcmp(pos, SUITE_1X, 4))
 460                                *is_8021x = 1;
 461                }
 462        }
 463        return ret;
 464}
 465
 466void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
 467{
 468        u8 authmode, sec_idx;
 469        u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
 470        uint cnt;
 471
 472        /* Search required WPA or WPA2 IE and copy to sec_ie[] */
 473
 474        cnt = _TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_;
 475
 476        sec_idx = 0;
 477
 478        while (cnt < in_len) {
 479                authmode = in_ie[cnt];
 480
 481                if ((authmode == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) {
 482                        if (wpa_ie)
 483                                memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
 484
 485                        *wpa_len = in_ie[cnt + 1] + 2;
 486                        cnt += in_ie[cnt + 1] + 2;  /* get next */
 487                } else {
 488                        if (authmode == WLAN_EID_RSN) {
 489                                if (rsn_ie)
 490                                        memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
 491
 492                                *rsn_len = in_ie[cnt + 1] + 2;
 493                                cnt += in_ie[cnt + 1] + 2;  /* get next */
 494                        } else {
 495                                cnt += in_ie[cnt + 1] + 2;   /* get next */
 496                        }
 497                }
 498        }
 499}
 500
 501u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
 502{
 503        u8 match = false;
 504        u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
 505
 506        if (!ie_ptr)
 507                return match;
 508
 509        eid = ie_ptr[0];
 510
 511        if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&ie_ptr[2], wps_oui, 4))) {
 512                *wps_ielen = ie_ptr[1] + 2;
 513                match = true;
 514        }
 515        return match;
 516}
 517
 518/**
 519 * rtw_get_wps_ie - Search WPS IE from a series of ies
 520 * @in_ie: Address of ies to search
 521 * @in_len: Length limit from in_ie
 522 * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie
 523 * @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE
 524 *
 525 * Returns: The address of the WPS IE found, or NULL
 526 */
 527u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
 528{
 529        uint cnt;
 530        u8 *wpsie_ptr = NULL;
 531        u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
 532
 533        if (wps_ielen)
 534                *wps_ielen = 0;
 535
 536        if (!in_ie || in_len <= 0)
 537                return wpsie_ptr;
 538
 539        cnt = 0;
 540
 541        while (cnt < in_len) {
 542                eid = in_ie[cnt];
 543
 544                if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) {
 545                        wpsie_ptr = &in_ie[cnt];
 546
 547                        if (wps_ie)
 548                                memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
 549
 550                        if (wps_ielen)
 551                                *wps_ielen = in_ie[cnt + 1] + 2;
 552
 553                        cnt += in_ie[cnt + 1] + 2;
 554
 555                        break;
 556                }
 557                cnt += in_ie[cnt + 1] + 2; /* goto next */
 558        }
 559        return wpsie_ptr;
 560}
 561
 562/**
 563 * rtw_get_wps_attr - Search a specific WPS attribute from a given WPS IE
 564 * @wps_ie: Address of WPS IE to search
 565 * @wps_ielen: Length limit from wps_ie
 566 * @target_attr_id: The attribute ID of WPS attribute to search
 567 * @buf_attr: If not NULL and the WPS attribute is found, WPS attribute will be copied to the buf starting from buf_attr
 568 * @len_attr: If not NULL and the WPS attribute is found, will set to the length of the entire WPS attribute
 569 *
 570 * Returns: the address of the specific WPS attribute found, or NULL
 571 */
 572u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_attr, u32 *len_attr)
 573{
 574        u8 *attr_ptr = NULL;
 575        u8 *target_attr_ptr = NULL;
 576        u8 wps_oui[4] = {0x00, 0x50, 0xF2, 0x04};
 577
 578        if (len_attr)
 579                *len_attr = 0;
 580
 581        if ((wps_ie[0] != WLAN_EID_VENDOR_SPECIFIC) ||
 582            (memcmp(wps_ie + 2, wps_oui, 4)))
 583                return attr_ptr;
 584
 585        /*  6 = 1(Element ID) + 1(Length) + 4(WPS OUI) */
 586        attr_ptr = wps_ie + 6; /* goto first attr */
 587
 588        while (attr_ptr - wps_ie < wps_ielen) {
 589                /*  4 = 2(Attribute ID) + 2(Length) */
 590                u16 attr_id = get_unaligned_be16(attr_ptr);
 591                u16 attr_data_len = get_unaligned_be16(attr_ptr + 2);
 592                u16 attr_len = attr_data_len + 4;
 593
 594                if (attr_id == target_attr_id) {
 595                        target_attr_ptr = attr_ptr;
 596                        if (buf_attr)
 597                                memcpy(buf_attr, attr_ptr, attr_len);
 598                        if (len_attr)
 599                                *len_attr = attr_len;
 600                        break;
 601                }
 602                attr_ptr += attr_len; /* goto next */
 603        }
 604        return target_attr_ptr;
 605}
 606
 607/**
 608 * rtw_get_wps_attr_content - Search a specific WPS attribute content from a given WPS IE
 609 * @wps_ie: Address of WPS IE to search
 610 * @wps_ielen: Length limit from wps_ie
 611 * @target_attr_id: The attribute ID of WPS attribute to search
 612 * @buf_content: If not NULL and the WPS attribute is found, WPS attribute content will be copied to the buf starting from buf_content
 613 * @len_content: If not NULL and the WPS attribute is found, will set to the length of the WPS attribute content
 614 *
 615 * Returns: the address of the specific WPS attribute content found, or NULL
 616 */
 617u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_content, uint *len_content)
 618{
 619        u8 *attr_ptr;
 620        u32 attr_len;
 621
 622        if (len_content)
 623                *len_content = 0;
 624
 625        attr_ptr = rtw_get_wps_attr(wps_ie, wps_ielen, target_attr_id, NULL, &attr_len);
 626
 627        if (attr_ptr && attr_len) {
 628                if (buf_content)
 629                        memcpy(buf_content, attr_ptr + 4, attr_len - 4);
 630
 631                if (len_content)
 632                        *len_content = attr_len - 4;
 633
 634                return attr_ptr + 4;
 635        }
 636
 637        return NULL;
 638}
 639
 640static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
 641                                                struct rtw_ieee802_11_elems *elems, int show_errors)
 642{
 643        unsigned int oui;
 644
 645        /*
 646         * first 3 bytes in vendor specific information element are the IEEE
 647         * OUI of the vendor. The following byte is used a vendor specific
 648         * sub-type.
 649         */
 650        if (elen < 4)
 651                return -1;
 652
 653        oui = RTW_GET_BE24(pos);
 654        switch (oui) {
 655        case OUI_MICROSOFT:
 656                /*
 657                 * Microsoft/Wi-Fi information elements are further typed and
 658                 * subtyped
 659                 */
 660                switch (pos[3]) {
 661                case 1:
 662                        /*
 663                         * Microsoft OUI (00:50:F2) with OUI Type 1:
 664                         * real WPA information element
 665                         */
 666                        elems->wpa_ie = pos;
 667                        elems->wpa_ie_len = elen;
 668                        break;
 669                case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */
 670                        if (elen < 5)
 671                                return -1;
 672
 673                        switch (pos[4]) {
 674                        case WME_OUI_SUBTYPE_INFORMATION_ELEMENT:
 675                        case WME_OUI_SUBTYPE_PARAMETER_ELEMENT:
 676                                elems->wme = pos;
 677                                elems->wme_len = elen;
 678                                break;
 679                        case WME_OUI_SUBTYPE_TSPEC_ELEMENT:
 680                                elems->wme_tspec = pos;
 681                                elems->wme_tspec_len = elen;
 682                                break;
 683                        default:
 684                                return -1;
 685                        }
 686                        break;
 687                case 4:
 688                        /* Wi-Fi Protected Setup (WPS) IE */
 689                        elems->wps_ie = pos;
 690                        elems->wps_ie_len = elen;
 691                        break;
 692                default:
 693                        return -1;
 694                }
 695                break;
 696
 697        case OUI_BROADCOM:
 698                switch (pos[3]) {
 699                case VENDOR_HT_CAPAB_OUI_TYPE:
 700                        elems->vendor_ht_cap = pos;
 701                        elems->vendor_ht_cap_len = elen;
 702                        break;
 703                default:
 704                        return -1;
 705                }
 706                break;
 707        default:
 708                return -1;
 709        }
 710        return 0;
 711}
 712
 713/**
 714 * rtw_ieee802_11_parse_elems - Parse information elements in management frames
 715 * @start: Pointer to the start of ies
 716 * @len: Length of IE buffer in octets
 717 * @elems: Data structure for parsed elements
 718 * @show_errors: Whether to show parsing errors in debug log
 719 * Returns: Parsing result
 720 */
 721enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len,
 722                                          struct rtw_ieee802_11_elems *elems,
 723                                          int show_errors)
 724{
 725        uint left = len;
 726        u8 *pos = start;
 727        int unknown = 0;
 728
 729        memset(elems, 0, sizeof(*elems));
 730
 731        while (left >= 2) {
 732                u8 id, elen;
 733
 734                id = *pos++;
 735                elen = *pos++;
 736                left -= 2;
 737
 738                if (elen > left)
 739                        return ParseFailed;
 740
 741                switch (id) {
 742                case WLAN_EID_SSID:
 743                        elems->ssid = pos;
 744                        elems->ssid_len = elen;
 745                        break;
 746                case WLAN_EID_SUPP_RATES:
 747                        elems->supp_rates = pos;
 748                        elems->supp_rates_len = elen;
 749                        break;
 750                case WLAN_EID_FH_PARAMS:
 751                        elems->fh_params = pos;
 752                        elems->fh_params_len = elen;
 753                        break;
 754                case WLAN_EID_DS_PARAMS:
 755                        elems->ds_params = pos;
 756                        elems->ds_params_len = elen;
 757                        break;
 758                case WLAN_EID_CF_PARAMS:
 759                        elems->cf_params = pos;
 760                        elems->cf_params_len = elen;
 761                        break;
 762                case WLAN_EID_TIM:
 763                        elems->tim = pos;
 764                        elems->tim_len = elen;
 765                        break;
 766                case WLAN_EID_IBSS_PARAMS:
 767                        elems->ibss_params = pos;
 768                        elems->ibss_params_len = elen;
 769                        break;
 770                case WLAN_EID_CHALLENGE:
 771                        elems->challenge = pos;
 772                        elems->challenge_len = elen;
 773                        break;
 774                case WLAN_EID_ERP_INFO:
 775                        elems->erp_info = pos;
 776                        elems->erp_info_len = elen;
 777                        break;
 778                case WLAN_EID_EXT_SUPP_RATES:
 779                        elems->ext_supp_rates = pos;
 780                        elems->ext_supp_rates_len = elen;
 781                        break;
 782                case WLAN_EID_VENDOR_SPECIFIC:
 783                        if (rtw_ieee802_11_parse_vendor_specific(pos, elen, elems, show_errors))
 784                                unknown++;
 785                        break;
 786                case WLAN_EID_RSN:
 787                        elems->rsn_ie = pos;
 788                        elems->rsn_ie_len = elen;
 789                        break;
 790                case WLAN_EID_PWR_CAPABILITY:
 791                        elems->power_cap = pos;
 792                        elems->power_cap_len = elen;
 793                        break;
 794                case WLAN_EID_SUPPORTED_CHANNELS:
 795                        elems->supp_channels = pos;
 796                        elems->supp_channels_len = elen;
 797                        break;
 798                case WLAN_EID_MOBILITY_DOMAIN:
 799                        elems->mdie = pos;
 800                        elems->mdie_len = elen;
 801                        break;
 802                case WLAN_EID_FAST_BSS_TRANSITION:
 803                        elems->ftie = pos;
 804                        elems->ftie_len = elen;
 805                        break;
 806                case WLAN_EID_TIMEOUT_INTERVAL:
 807                        elems->timeout_int = pos;
 808                        elems->timeout_int_len = elen;
 809                        break;
 810                case WLAN_EID_HT_CAPABILITY:
 811                        elems->ht_capabilities = pos;
 812                        elems->ht_capabilities_len = elen;
 813                        break;
 814                case WLAN_EID_HT_OPERATION:
 815                        elems->ht_operation = pos;
 816                        elems->ht_operation_len = elen;
 817                        break;
 818                default:
 819                        unknown++;
 820                        break;
 821                }
 822                left -= elen;
 823                pos += elen;
 824        }
 825        if (left)
 826                return ParseFailed;
 827        return unknown ? ParseUnknown : ParseOK;
 828}
 829
 830void rtw_macaddr_cfg(u8 *mac_addr)
 831{
 832        u8 mac[ETH_ALEN];
 833
 834        if (!mac_addr)
 835                return;
 836
 837        if (rtw_initmac && mac_pton(rtw_initmac, mac)) {
 838                /* Users specify the mac address */
 839                ether_addr_copy(mac_addr, mac);
 840        } else {
 841                /* Use the mac address stored in the Efuse */
 842                ether_addr_copy(mac, mac_addr);
 843        }
 844
 845        if (is_broadcast_ether_addr(mac) || is_zero_ether_addr(mac))
 846                eth_random_addr(mac_addr);
 847}
 848
 849static int rtw_get_cipher_info(struct wlan_network *pnetwork)
 850{
 851        uint wpa_ielen;
 852        unsigned char *pbuf;
 853        int group_cipher = 0, pairwise_cipher = 0, is8021x = 0;
 854        int ret = _FAIL;
 855
 856        pbuf = rtw_get_wpa_ie(&pnetwork->network.ies[12], &wpa_ielen, pnetwork->network.ie_length - 12);
 857
 858        if (pbuf && (wpa_ielen > 0)) {
 859                if (rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x) == _SUCCESS) {
 860                        pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
 861                        pnetwork->BcnInfo.group_cipher = group_cipher;
 862                        pnetwork->BcnInfo.is_8021x = is8021x;
 863                        ret = _SUCCESS;
 864                }
 865        } else {
 866                pbuf = rtw_get_wpa2_ie(&pnetwork->network.ies[12], &wpa_ielen, pnetwork->network.ie_length - 12);
 867
 868                if (pbuf && (wpa_ielen > 0)) {
 869                        if (rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x) == _SUCCESS) {
 870                                pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
 871                                pnetwork->BcnInfo.group_cipher = group_cipher;
 872                                pnetwork->BcnInfo.is_8021x = is8021x;
 873                                ret = _SUCCESS;
 874                        }
 875                }
 876        }
 877
 878        return ret;
 879}
 880
 881void rtw_get_bcn_info(struct wlan_network *pnetwork)
 882{
 883        unsigned short cap = 0;
 884        u8 bencrypt = 0;
 885        __le16 le_tmp;
 886        u16 wpa_len = 0, rsn_len = 0;
 887        struct HT_info_element *pht_info = NULL;
 888        uint len;
 889        unsigned char *p;
 890
 891        memcpy(&le_tmp, rtw_get_capability_from_ie(pnetwork->network.ies), 2);
 892        cap = le16_to_cpu(le_tmp);
 893        if (cap & WLAN_CAPABILITY_PRIVACY) {
 894                bencrypt = 1;
 895                pnetwork->network.Privacy = 1;
 896        } else {
 897                pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS;
 898        }
 899        rtw_get_sec_ie(pnetwork->network.ies, pnetwork->network.ie_length, NULL, &rsn_len, NULL, &wpa_len);
 900
 901        if (rsn_len > 0) {
 902                pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2;
 903        } else if (wpa_len > 0) {
 904                pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA;
 905        } else {
 906                if (bencrypt)
 907                        pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP;
 908        }
 909        rtw_get_cipher_info(pnetwork);
 910
 911        /* get bwmode and ch_offset */
 912        /* parsing HT_CAP_IE */
 913        p = rtw_get_ie(pnetwork->network.ies + _FIXED_IE_LENGTH_, WLAN_EID_HT_CAPABILITY, &len, pnetwork->network.ie_length - _FIXED_IE_LENGTH_);
 914        if (p && len > 0) {
 915                struct ieee80211_ht_cap *ht_cap =
 916                        (struct ieee80211_ht_cap *)(p + 2);
 917
 918                pnetwork->BcnInfo.ht_cap_info = le16_to_cpu(ht_cap->cap_info);
 919        } else {
 920                pnetwork->BcnInfo.ht_cap_info = 0;
 921        }
 922        /* parsing HT_INFO_IE */
 923        p = rtw_get_ie(pnetwork->network.ies + _FIXED_IE_LENGTH_, WLAN_EID_HT_OPERATION, &len, pnetwork->network.ie_length - _FIXED_IE_LENGTH_);
 924        if (p && len > 0) {
 925                pht_info = (struct HT_info_element *)(p + 2);
 926                pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0];
 927        } else {
 928                pnetwork->BcnInfo.ht_info_infos_0 = 0;
 929        }
 930}
 931
 932/* show MCS rate, unit: 100Kbps */
 933u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, unsigned char *MCS_rate)
 934{
 935        u16 max_rate = 0;
 936
 937        if (rf_type == RF_1T1R) {
 938                if (MCS_rate[0] & BIT(7))
 939                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650);
 940                else if (MCS_rate[0] & BIT(6))
 941                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585);
 942                else if (MCS_rate[0] & BIT(5))
 943                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
 944                else if (MCS_rate[0] & BIT(4))
 945                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
 946                else if (MCS_rate[0] & BIT(3))
 947                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
 948                else if (MCS_rate[0] & BIT(2))
 949                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195);
 950                else if (MCS_rate[0] & BIT(1))
 951                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
 952                else if (MCS_rate[0] & BIT(0))
 953                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65);
 954        } else {
 955                if (MCS_rate[1]) {
 956                        if (MCS_rate[1] & BIT(7))
 957                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 3000 : 2700) : ((short_GI_20) ? 1444 : 1300);
 958                        else if (MCS_rate[1] & BIT(6))
 959                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 2700 : 2430) : ((short_GI_20) ? 1300 : 1170);
 960                        else if (MCS_rate[1] & BIT(5))
 961                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 2400 : 2160) : ((short_GI_20) ? 1156 : 1040);
 962                        else if (MCS_rate[1] & BIT(4))
 963                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 1800 : 1620) : ((short_GI_20) ? 867 : 780);
 964                        else if (MCS_rate[1] & BIT(3))
 965                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
 966                        else if (MCS_rate[1] & BIT(2))
 967                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
 968                        else if (MCS_rate[1] & BIT(1))
 969                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
 970                        else if (MCS_rate[1] & BIT(0))
 971                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
 972                } else {
 973                        if (MCS_rate[0] & BIT(7))
 974                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650);
 975                        else if (MCS_rate[0] & BIT(6))
 976                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585);
 977                        else if (MCS_rate[0] & BIT(5))
 978                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
 979                        else if (MCS_rate[0] & BIT(4))
 980                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
 981                        else if (MCS_rate[0] & BIT(3))
 982                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
 983                        else if (MCS_rate[0] & BIT(2))
 984                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195);
 985                        else if (MCS_rate[0] & BIT(1))
 986                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
 987                        else if (MCS_rate[0] & BIT(0))
 988                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65);
 989                }
 990        }
 991        return max_rate;
 992}
 993