linux/drivers/staging/r8188eu/core/rtw_ieee80211.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright(c) 2007 - 2011 Realtek Corporation. */
   3
   4#define _IEEE80211_C
   5
   6#include "../include/drv_types.h"
   7#include "../include/ieee80211.h"
   8#include "../include/wifi.h"
   9#include "../include/osdep_service.h"
  10#include "../include/wlan_bssdef.h"
  11#include "../include/usb_osintf.h"
  12
  13u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
  14u16 RTW_WPA_VERSION = 1;
  15u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 };
  16u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 };
  17u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 };
  18u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 };
  19u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 };
  20u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 };
  21u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 };
  22u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 };
  23u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
  24
  25u16 RSN_VERSION_BSD = 1;
  26u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 };
  27u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 };
  28u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 };
  29u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 };
  30u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 };
  31u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 };
  32u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 };
  33u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 };
  34/*  */
  35/*  for adhoc-master to generate ie and provide supported-rate to fw */
  36/*  */
  37
  38static u8       WIFI_CCKRATES[] = {
  39        (IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK),
  40        (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK),
  41        (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK),
  42        (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK)
  43        };
  44
  45static u8       WIFI_OFDMRATES[] = {
  46         (IEEE80211_OFDM_RATE_6MB),
  47         (IEEE80211_OFDM_RATE_9MB),
  48         (IEEE80211_OFDM_RATE_12MB),
  49         (IEEE80211_OFDM_RATE_18MB),
  50         (IEEE80211_OFDM_RATE_24MB),
  51         IEEE80211_OFDM_RATE_36MB,
  52         IEEE80211_OFDM_RATE_48MB,
  53         IEEE80211_OFDM_RATE_54MB
  54        };
  55
  56int rtw_get_bit_value_from_ieee_value(u8 val)
  57{
  58        unsigned char dot11_rate_table[] = {
  59                2, 4, 11, 22, 12, 18, 24, 36, 48,
  60                72, 96, 108, 0}; /*  last element must be zero!! */
  61
  62        int i = 0;
  63        while (dot11_rate_table[i] != 0) {
  64                if (dot11_rate_table[i] == val)
  65                        return BIT(i);
  66                i++;
  67        }
  68        return 0;
  69}
  70
  71uint    rtw_is_cckrates_included(u8 *rate)
  72{
  73        u32     i = 0;
  74
  75        while (rate[i] != 0) {
  76                if  ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) ||
  77                     (((rate[i]) & 0x7f) == 11)  || (((rate[i]) & 0x7f) == 22))
  78                        return true;
  79                i++;
  80        }
  81        return false;
  82}
  83
  84uint    rtw_is_cckratesonly_included(u8 *rate)
  85{
  86        u32 i = 0;
  87
  88        while (rate[i] != 0) {
  89                if  ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) &&
  90                     (((rate[i]) & 0x7f) != 11)  && (((rate[i]) & 0x7f) != 22))
  91                        return false;
  92                i++;
  93        }
  94
  95        return true;
  96}
  97
  98int rtw_check_network_type(unsigned char *rate, int ratelen, int channel)
  99{
 100        if (channel > 14) {
 101                return WIRELESS_INVALID;
 102        } else {  /*  could be pure B, pure G, or B/G */
 103                if (rtw_is_cckratesonly_included(rate))
 104                        return WIRELESS_11B;
 105                else if (rtw_is_cckrates_included(rate))
 106                        return  WIRELESS_11BG;
 107                else
 108                        return WIRELESS_11G;
 109        }
 110}
 111
 112u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source,
 113                                unsigned int *frlen)
 114{
 115        memcpy((void *)pbuf, (void *)source, len);
 116        *frlen = *frlen + len;
 117        return 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
 131        *pbuf = (u8)index;
 132
 133        *(pbuf + 1) = (u8)len;
 134
 135        if (len > 0)
 136                memcpy((void *)(pbuf + 2), (void *)source, len);
 137
 138        *frlen = *frlen + (len + 2);
 139
 140        return pbuf + len + 2;
 141}
 142
 143inline u8 *rtw_set_ie_ch_switch(u8 *buf, u32 *buf_len, u8 ch_switch_mode,
 144        u8 new_ch, u8 ch_switch_cnt)
 145{
 146        u8 ie_data[3];
 147
 148        ie_data[0] = ch_switch_mode;
 149        ie_data[1] = new_ch;
 150        ie_data[2] = ch_switch_cnt;
 151        return rtw_set_ie(buf, WLAN_EID_CHANNEL_SWITCH,  3, ie_data, buf_len);
 152}
 153
 154inline u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset)
 155{
 156        if (ch_offset == SCN)
 157                return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
 158        else if (ch_offset == SCA)
 159                return HAL_PRIME_CHNL_OFFSET_UPPER;
 160        else if (ch_offset == SCB)
 161                return HAL_PRIME_CHNL_OFFSET_LOWER;
 162
 163        return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
 164}
 165
 166inline u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset)
 167{
 168        if (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
 169                return SCN;
 170        else if (ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
 171                return SCB;
 172        else if (ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
 173                return SCA;
 174
 175        return SCN;
 176}
 177
 178inline u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len, u8 secondary_ch_offset)
 179{
 180        return rtw_set_ie(buf, WLAN_EID_SECONDARY_CHANNEL_OFFSET,  1, &secondary_ch_offset, buf_len);
 181}
 182
 183inline u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl,
 184        u8 flags, u16 reason, u16 precedence)
 185{
 186        u8 ie_data[6];
 187
 188        ie_data[0] = ttl;
 189        ie_data[1] = flags;
 190        *(u16 *)(ie_data + 2) = cpu_to_le16(reason);
 191        *(u16 *)(ie_data + 4) = cpu_to_le16(precedence);
 192
 193        return rtw_set_ie(buf, 0x118,  6, ie_data, buf_len);
 194}
 195
 196/*----------------------------------------------------------------------------
 197index: the information element id index, limit is the limit for search
 198-----------------------------------------------------------------------------*/
 199u8 *rtw_get_ie(u8 *pbuf, int index, int *len, int limit)
 200{
 201        int tmp, i;
 202        u8 *p;
 203
 204        if (limit < 1) {
 205
 206                return NULL;
 207        }
 208
 209        p = pbuf;
 210        i = 0;
 211        *len = 0;
 212        while (1) {
 213                if (*p == index) {
 214                        *len = *(p + 1);
 215                        return p;
 216                } else {
 217                        tmp = *(p + 1);
 218                        p += (tmp + 2);
 219                        i += (tmp + 2);
 220                }
 221                if (i >= limit)
 222                        break;
 223        }
 224
 225        return NULL;
 226}
 227
 228/**
 229 * rtw_get_ie_ex - Search specific IE from a series of IEs
 230 * @in_ie: Address of IEs to search
 231 * @in_len: Length limit from in_ie
 232 * @eid: Element ID to match
 233 * @oui: OUI to match
 234 * @oui_len: OUI length
 235 * @ie: If not NULL and the specific IE is found, the IE will be copied to the buf starting from the specific IE
 236 * @ielen: If not NULL and the specific IE is found, will set to the length of the entire IE
 237 *
 238 * Returns: The address of the specific IE found, or NULL
 239 */
 240u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen)
 241{
 242        uint cnt;
 243        u8 *target_ie = NULL;
 244
 245        if (ielen)
 246                *ielen = 0;
 247
 248        if (!in_ie || in_len <= 0)
 249                return target_ie;
 250
 251        cnt = 0;
 252
 253        while (cnt < in_len) {
 254                if (eid == in_ie[cnt] && (!oui || !memcmp(&in_ie[cnt + 2], oui, oui_len))) {
 255                        target_ie = &in_ie[cnt];
 256
 257                        if (ie)
 258                                memcpy(ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
 259
 260                        if (ielen)
 261                                *ielen = in_ie[cnt + 1] + 2;
 262
 263                        break;
 264                } else {
 265                        cnt += in_ie[cnt + 1] + 2; /* goto next */
 266                }
 267        }
 268        return target_ie;
 269}
 270
 271/**
 272 * rtw_ies_remove_ie - Find matching IEs and remove
 273 * @ies: Address of IEs to search
 274 * @ies_len: Pointer of length of ies, will update to new length
 275 * @offset: The offset to start scarch
 276 * @eid: Element ID to match
 277 * @oui: OUI to match
 278 * @oui_len: OUI length
 279 *
 280 * Returns: _SUCCESS: ies is updated, _FAIL: not updated
 281 */
 282int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len)
 283{
 284        int ret = _FAIL;
 285        u8 *target_ie;
 286        u32 target_ielen;
 287        u8 *start;
 288        uint search_len;
 289
 290        if (!ies || !ies_len || *ies_len <= offset)
 291                goto exit;
 292
 293        start = ies + offset;
 294        search_len = *ies_len - offset;
 295
 296        while (1) {
 297                target_ie = rtw_get_ie_ex(start, search_len, eid, oui, oui_len, NULL, &target_ielen);
 298                if (target_ie && target_ielen) {
 299                        u8 buf[MAX_IE_SZ] = {0};
 300                        u8 *remain_ies = target_ie + target_ielen;
 301                        uint remain_len = search_len - (remain_ies - start);
 302
 303                        memcpy(buf, remain_ies, remain_len);
 304                        memcpy(target_ie, buf, remain_len);
 305                        *ies_len = *ies_len - target_ielen;
 306                        ret = _SUCCESS;
 307
 308                        start = target_ie;
 309                        search_len = remain_len;
 310                } else {
 311                        break;
 312                }
 313        }
 314exit:
 315        return ret;
 316}
 317
 318void rtw_set_supported_rate(u8 *SupportedRates, uint mode)
 319{
 320
 321        memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
 322
 323        switch (mode) {
 324        case WIRELESS_11B:
 325                memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
 326                break;
 327        case WIRELESS_11G:
 328                memcpy(SupportedRates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
 329                break;
 330        case WIRELESS_11BG:
 331        case WIRELESS_11G_24N:
 332        case WIRELESS_11_24N:
 333        case WIRELESS_11BG_24N:
 334                memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
 335                memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
 336                break;
 337        }
 338
 339}
 340
 341uint    rtw_get_rateset_len(u8  *rateset)
 342{
 343        uint i = 0;
 344
 345        while (1) {
 346                if ((rateset[i]) == 0)
 347                        break;
 348                if (i > 12)
 349                        break;
 350                i++;
 351        }
 352
 353        return i;
 354}
 355
 356int rtw_generate_ie(struct registry_priv *pregistrypriv)
 357{
 358        u8      wireless_mode;
 359        int     sz = 0, rateLen;
 360        struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
 361        u8 *ie = pdev_network->IEs;
 362
 363        /* timestamp will be inserted by hardware */
 364        sz += 8;
 365        ie += sz;
 366
 367        /* beacon interval : 2bytes */
 368        *(__le16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);/* BCN_INTERVAL; */
 369        sz += 2;
 370        ie += 2;
 371
 372        /* capability info */
 373        *(u16 *)ie = 0;
 374
 375        *(__le16 *)ie |= cpu_to_le16(cap_IBSS);
 376
 377        if (pregistrypriv->preamble == PREAMBLE_SHORT)
 378                *(__le16 *)ie |= cpu_to_le16(cap_ShortPremble);
 379
 380        if (pdev_network->Privacy)
 381                *(__le16 *)ie |= cpu_to_le16(cap_Privacy);
 382
 383        sz += 2;
 384        ie += 2;
 385
 386        /* SSID */
 387        ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz);
 388
 389        /* supported rates */
 390        wireless_mode = pregistrypriv->wireless_mode;
 391
 392        rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode);
 393
 394        rateLen = rtw_get_rateset_len(pdev_network->SupportedRates);
 395
 396        if (rateLen > 8) {
 397                ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, pdev_network->SupportedRates, &sz);
 398                /* ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); */
 399        } else {
 400                ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, pdev_network->SupportedRates, &sz);
 401        }
 402
 403        /* DS parameter set */
 404        ie = rtw_set_ie(ie, _DSSET_IE_, 1, (u8 *)&pdev_network->Configuration.DSConfig, &sz);
 405
 406        /* IBSS Parameter Set */
 407
 408        ie = rtw_set_ie(ie, _IBSS_PARA_IE_, 2, (u8 *)&pdev_network->Configuration.ATIMWindow, &sz);
 409
 410        if (rateLen > 8)
 411                ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz);
 412
 413        return sz;
 414}
 415
 416unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit)
 417{
 418        int len;
 419        u16 val16;
 420        __le16 le_tmp;
 421        unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
 422        u8 *pbuf = pie;
 423        int limit_new = limit;
 424
 425        while (1) {
 426                pbuf = rtw_get_ie(pbuf, _WPA_IE_ID_, &len, limit_new);
 427
 428                if (pbuf) {
 429                        /* check if oui matches... */
 430                        if (memcmp((pbuf + 2), wpa_oui_type, sizeof(wpa_oui_type)))
 431                                goto check_next_ie;
 432
 433                        /* check version... */
 434                        memcpy((u8 *)&le_tmp, (pbuf + 6), sizeof(val16));
 435
 436                        val16 = le16_to_cpu(le_tmp);
 437                        if (val16 != 0x0001)
 438                                goto check_next_ie;
 439                        *wpa_ie_len = *(pbuf + 1);
 440                        return pbuf;
 441                } else {
 442                        *wpa_ie_len = 0;
 443                        return NULL;
 444                }
 445
 446check_next_ie:
 447                limit_new = limit - (pbuf - pie) - 2 - len;
 448                if (limit_new <= 0)
 449                        break;
 450                pbuf += (2 + len);
 451        }
 452        *wpa_ie_len = 0;
 453        return NULL;
 454}
 455
 456unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit)
 457{
 458
 459        return rtw_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit);
 460}
 461
 462int rtw_get_wpa_cipher_suite(u8 *s)
 463{
 464        if (!memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN))
 465                return WPA_CIPHER_NONE;
 466        if (!memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN))
 467                return WPA_CIPHER_WEP40;
 468        if (!memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN))
 469                return WPA_CIPHER_TKIP;
 470        if (!memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN))
 471                return WPA_CIPHER_CCMP;
 472        if (!memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN))
 473                return WPA_CIPHER_WEP104;
 474
 475        return 0;
 476}
 477
 478int rtw_get_wpa2_cipher_suite(u8 *s)
 479{
 480        if (!memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN))
 481                return WPA_CIPHER_NONE;
 482        if (!memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN))
 483                return WPA_CIPHER_WEP40;
 484        if (!memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN))
 485                return WPA_CIPHER_TKIP;
 486        if (!memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN))
 487                return WPA_CIPHER_CCMP;
 488        if (!memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN))
 489                return WPA_CIPHER_WEP104;
 490
 491        return 0;
 492}
 493
 494int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
 495{
 496        int i, ret = _SUCCESS;
 497        int left, count;
 498        u8 *pos;
 499        u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1};
 500
 501        if (wpa_ie_len <= 0) {
 502                /* No WPA IE - fail silently */
 503                return _FAIL;
 504        }
 505
 506        if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie + 1) != (u8)(wpa_ie_len - 2)) ||
 507            (memcmp(wpa_ie + 2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN)))
 508                return _FAIL;
 509
 510        pos = wpa_ie;
 511
 512        pos += 8;
 513        left = wpa_ie_len - 8;
 514
 515        /* group_cipher */
 516        if (left >= WPA_SELECTOR_LEN) {
 517                *group_cipher = rtw_get_wpa_cipher_suite(pos);
 518                pos += WPA_SELECTOR_LEN;
 519                left -= WPA_SELECTOR_LEN;
 520        } else if (left > 0) {
 521                return _FAIL;
 522        }
 523
 524        /* pairwise_cipher */
 525        if (left >= 2) {
 526                count = get_unaligned_le16(pos);
 527                pos += 2;
 528                left -= 2;
 529
 530                if (count == 0 || left < count * WPA_SELECTOR_LEN)
 531                        return _FAIL;
 532
 533                for (i = 0; i < count; i++) {
 534                        *pairwise_cipher |= rtw_get_wpa_cipher_suite(pos);
 535
 536                        pos += WPA_SELECTOR_LEN;
 537                        left -= WPA_SELECTOR_LEN;
 538                }
 539        } else if (left == 1) {
 540                return _FAIL;
 541        }
 542
 543        if (is_8021x) {
 544                if (left >= 6) {
 545                        pos += 2;
 546                        if (!memcmp(pos, SUITE_1X, 4))
 547                                *is_8021x = 1;
 548                }
 549        }
 550
 551        return ret;
 552}
 553
 554int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
 555{
 556        int i, ret = _SUCCESS;
 557        int left, count;
 558        u8 *pos;
 559        u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01};
 560
 561        if (rsn_ie_len <= 0) {
 562                /* No RSN IE - fail silently */
 563                return _FAIL;
 564        }
 565
 566        if ((*rsn_ie != _WPA2_IE_ID_) || (*(rsn_ie + 1) != (u8)(rsn_ie_len - 2)))
 567                return _FAIL;
 568
 569        pos = rsn_ie;
 570        pos += 4;
 571        left = rsn_ie_len - 4;
 572
 573        /* group_cipher */
 574        if (left >= RSN_SELECTOR_LEN) {
 575                *group_cipher = rtw_get_wpa2_cipher_suite(pos);
 576
 577                pos += RSN_SELECTOR_LEN;
 578                left -= RSN_SELECTOR_LEN;
 579
 580        } else if (left > 0) {
 581                return _FAIL;
 582        }
 583
 584        /* pairwise_cipher */
 585        if (left >= 2) {
 586                count = get_unaligned_le16(pos);
 587                pos += 2;
 588                left -= 2;
 589
 590                if (count == 0 || left < count * RSN_SELECTOR_LEN)
 591                        return _FAIL;
 592
 593                for (i = 0; i < count; i++) {
 594                        *pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos);
 595
 596                        pos += RSN_SELECTOR_LEN;
 597                        left -= RSN_SELECTOR_LEN;
 598                }
 599
 600        } else if (left == 1) {
 601                return _FAIL;
 602        }
 603
 604        if (is_8021x) {
 605                if (left >= 6) {
 606                        pos += 2;
 607                        if (!memcmp(pos, SUITE_1X, 4))
 608                                *is_8021x = 1;
 609                }
 610        }
 611        return ret;
 612}
 613
 614int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
 615{
 616        u8 authmode;
 617        u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
 618        uint    cnt;
 619
 620        /* Search required WPA or WPA2 IE and copy to sec_ie[] */
 621
 622        cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_);
 623
 624        while (cnt < in_len) {
 625                authmode = in_ie[cnt];
 626
 627                if ((authmode == _WPA_IE_ID_) && (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) {
 628                                if (wpa_ie)
 629                                        memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
 630
 631                                *wpa_len = in_ie[cnt + 1] + 2;
 632                                cnt += in_ie[cnt + 1] + 2;  /* get next */
 633                } else {
 634                        if (authmode == _WPA2_IE_ID_) {
 635                                if (rsn_ie)
 636                                        memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
 637
 638                                *rsn_len = in_ie[cnt + 1] + 2;
 639                                cnt += in_ie[cnt + 1] + 2;  /* get next */
 640                        } else {
 641                                cnt += in_ie[cnt + 1] + 2;   /* get next */
 642                        }
 643                }
 644        }
 645
 646        return *rsn_len + *wpa_len;
 647}
 648
 649u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
 650{
 651        u8 match = false;
 652        u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
 653
 654        if (!ie_ptr)
 655                return match;
 656
 657        eid = ie_ptr[0];
 658
 659        if ((eid == _WPA_IE_ID_) && (!memcmp(&ie_ptr[2], wps_oui, 4))) {
 660                *wps_ielen = ie_ptr[1] + 2;
 661                match = true;
 662        }
 663        return match;
 664}
 665
 666/**
 667 * rtw_get_wps_ie - Search WPS IE from a series of IEs
 668 * @in_ie: Address of IEs to search
 669 * @in_len: Length limit from in_ie
 670 * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie
 671 * @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE
 672 *
 673 * Returns: The address of the WPS IE found, or NULL
 674 */
 675u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
 676{
 677        uint cnt;
 678        u8 *wpsie_ptr = NULL;
 679        u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
 680
 681        if (wps_ielen)
 682                *wps_ielen = 0;
 683
 684        if (!in_ie || in_len <= 0)
 685                return wpsie_ptr;
 686
 687        cnt = 0;
 688
 689        while (cnt < in_len) {
 690                eid = in_ie[cnt];
 691
 692                if ((eid == _WPA_IE_ID_) && (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) {
 693                        wpsie_ptr = &in_ie[cnt];
 694
 695                        if (wps_ie)
 696                                memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
 697
 698                        if (wps_ielen)
 699                                *wps_ielen = in_ie[cnt + 1] + 2;
 700
 701                        cnt += in_ie[cnt + 1] + 2;
 702
 703                        break;
 704                } else {
 705                        cnt += in_ie[cnt + 1] + 2; /* goto next */
 706                }
 707        }
 708        return wpsie_ptr;
 709}
 710
 711/**
 712 * rtw_get_wps_attr - Search a specific WPS attribute from a given WPS IE
 713 * @wps_ie: Address of WPS IE to search
 714 * @wps_ielen: Length limit from wps_ie
 715 * @target_attr_id: The attribute ID of WPS attribute to search
 716 * @buf_attr: If not NULL and the WPS attribute is found, WPS attribute will be copied to the buf starting from buf_attr
 717 * @len_attr: If not NULL and the WPS attribute is found, will set to the length of the entire WPS attribute
 718 *
 719 * Returns: the address of the specific WPS attribute found, or NULL
 720 */
 721u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_attr, u32 *len_attr)
 722{
 723        u8 *attr_ptr = NULL;
 724        u8 *target_attr_ptr = NULL;
 725        u8 wps_oui[4] = {0x00, 0x50, 0xF2, 0x04};
 726
 727        if (len_attr)
 728                *len_attr = 0;
 729
 730        if ((wps_ie[0] != _VENDOR_SPECIFIC_IE_) ||
 731            (memcmp(wps_ie + 2, wps_oui, 4)))
 732                return attr_ptr;
 733
 734        /*  6 = 1(Element ID) + 1(Length) + 4(WPS OUI) */
 735        attr_ptr = wps_ie + 6; /* goto first attr */
 736
 737        while (attr_ptr - wps_ie < wps_ielen) {
 738                /*  4 = 2(Attribute ID) + 2(Length) */
 739                u16 attr_id = RTW_GET_BE16(attr_ptr);
 740                u16 attr_data_len = RTW_GET_BE16(attr_ptr + 2);
 741                u16 attr_len = attr_data_len + 4;
 742
 743                if (attr_id == target_attr_id) {
 744                        target_attr_ptr = attr_ptr;
 745                        if (buf_attr)
 746                                memcpy(buf_attr, attr_ptr, attr_len);
 747                        if (len_attr)
 748                                *len_attr = attr_len;
 749                        break;
 750                } else {
 751                        attr_ptr += attr_len; /* goto next */
 752                }
 753        }
 754        return target_attr_ptr;
 755}
 756
 757/**
 758 * rtw_get_wps_attr_content - Search a specific WPS attribute content from a given WPS IE
 759 * @wps_ie: Address of WPS IE to search
 760 * @wps_ielen: Length limit from wps_ie
 761 * @target_attr_id: The attribute ID of WPS attribute to search
 762 * @buf_content: If not NULL and the WPS attribute is found, WPS attribute content will be copied to the buf starting from buf_content
 763 * @len_content: If not NULL and the WPS attribute is found, will set to the length of the WPS attribute content
 764 *
 765 * Returns: the address of the specific WPS attribute content found, or NULL
 766 */
 767u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_content, uint *len_content)
 768{
 769        u8 *attr_ptr;
 770        u32 attr_len;
 771
 772        if (len_content)
 773                *len_content = 0;
 774
 775        attr_ptr = rtw_get_wps_attr(wps_ie, wps_ielen, target_attr_id, NULL, &attr_len);
 776
 777        if (attr_ptr && attr_len) {
 778                if (buf_content)
 779                        memcpy(buf_content, attr_ptr + 4, attr_len - 4);
 780
 781                if (len_content)
 782                        *len_content = attr_len - 4;
 783
 784                return attr_ptr + 4;
 785        }
 786
 787        return NULL;
 788}
 789
 790static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
 791                                            struct rtw_ieee802_11_elems *elems,
 792                                            int show_errors)
 793{
 794        unsigned int oui;
 795
 796        /* first 3 bytes in vendor specific information element are the IEEE
 797         * OUI of the vendor. The following byte is used a vendor specific
 798         * sub-type. */
 799        if (elen < 4) {
 800                if (show_errors) {
 801                        DBG_88E("short vendor specific information element ignored (len=%lu)\n",
 802                                (unsigned long)elen);
 803                }
 804                return -1;
 805        }
 806
 807        oui = RTW_GET_BE24(pos);
 808        switch (oui) {
 809        case OUI_MICROSOFT:
 810                /* Microsoft/Wi-Fi information elements are further typed and
 811                 * subtyped */
 812                switch (pos[3]) {
 813                case 1:
 814                        /* Microsoft OUI (00:50:F2) with OUI Type 1:
 815                         * real WPA information element */
 816                        elems->wpa_ie = pos;
 817                        elems->wpa_ie_len = elen;
 818                        break;
 819                case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */
 820                        if (elen < 5) {
 821                                DBG_88E("short WME information element ignored (len=%lu)\n",
 822                                        (unsigned long)elen);
 823                                return -1;
 824                        }
 825                        switch (pos[4]) {
 826                        case WME_OUI_SUBTYPE_INFORMATION_ELEMENT:
 827                        case WME_OUI_SUBTYPE_PARAMETER_ELEMENT:
 828                                elems->wme = pos;
 829                                elems->wme_len = elen;
 830                                break;
 831                        case WME_OUI_SUBTYPE_TSPEC_ELEMENT:
 832                                elems->wme_tspec = pos;
 833                                elems->wme_tspec_len = elen;
 834                                break;
 835                        default:
 836                                DBG_88E("unknown WME information element ignored (subtype=%d len=%lu)\n",
 837                                        pos[4], (unsigned long)elen);
 838                                return -1;
 839                        }
 840                        break;
 841                case 4:
 842                        /* Wi-Fi Protected Setup (WPS) IE */
 843                        elems->wps_ie = pos;
 844                        elems->wps_ie_len = elen;
 845                        break;
 846                default:
 847                        DBG_88E("Unknown Microsoft information element ignored (type=%d len=%lu)\n",
 848                                pos[3], (unsigned long)elen);
 849                        return -1;
 850                }
 851                break;
 852
 853        case OUI_BROADCOM:
 854                switch (pos[3]) {
 855                case VENDOR_HT_CAPAB_OUI_TYPE:
 856                        elems->vendor_ht_cap = pos;
 857                        elems->vendor_ht_cap_len = elen;
 858                        break;
 859                default:
 860                        DBG_88E("Unknown Broadcom information element ignored (type=%d len=%lu)\n",
 861                                pos[3], (unsigned long)elen);
 862                        return -1;
 863                }
 864                break;
 865        default:
 866                DBG_88E("unknown vendor specific information element ignored (vendor OUI %02x:%02x:%02x len=%lu)\n",
 867                        pos[0], pos[1], pos[2], (unsigned long)elen);
 868                return -1;
 869        }
 870        return 0;
 871}
 872
 873/**
 874 * ieee802_11_parse_elems - Parse information elements in management frames
 875 * @start: Pointer to the start of IEs
 876 * @len: Length of IE buffer in octets
 877 * @elems: Data structure for parsed elements
 878 * @show_errors: Whether to show parsing errors in debug log
 879 * Returns: Parsing result
 880 */
 881enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len,
 882                                struct rtw_ieee802_11_elems *elems,
 883                                int show_errors)
 884{
 885        uint left = len;
 886        u8 *pos = start;
 887        int unknown = 0;
 888
 889        memset(elems, 0, sizeof(*elems));
 890
 891        while (left >= 2) {
 892                u8 id, elen;
 893
 894                id = *pos++;
 895                elen = *pos++;
 896                left -= 2;
 897
 898                if (elen > left) {
 899                        if (show_errors) {
 900                                DBG_88E("IEEE 802.11 element parse failed (id=%d elen=%d left=%lu)\n",
 901                                        id, elen, (unsigned long)left);
 902                        }
 903                        return ParseFailed;
 904                }
 905
 906                switch (id) {
 907                case WLAN_EID_SSID:
 908                        elems->ssid = pos;
 909                        elems->ssid_len = elen;
 910                        break;
 911                case WLAN_EID_SUPP_RATES:
 912                        elems->supp_rates = pos;
 913                        elems->supp_rates_len = elen;
 914                        break;
 915                case WLAN_EID_FH_PARAMS:
 916                        elems->fh_params = pos;
 917                        elems->fh_params_len = elen;
 918                        break;
 919                case WLAN_EID_DS_PARAMS:
 920                        elems->ds_params = pos;
 921                        elems->ds_params_len = elen;
 922                        break;
 923                case WLAN_EID_CF_PARAMS:
 924                        elems->cf_params = pos;
 925                        elems->cf_params_len = elen;
 926                        break;
 927                case WLAN_EID_TIM:
 928                        elems->tim = pos;
 929                        elems->tim_len = elen;
 930                        break;
 931                case WLAN_EID_IBSS_PARAMS:
 932                        elems->ibss_params = pos;
 933                        elems->ibss_params_len = elen;
 934                        break;
 935                case WLAN_EID_CHALLENGE:
 936                        elems->challenge = pos;
 937                        elems->challenge_len = elen;
 938                        break;
 939                case WLAN_EID_ERP_INFO:
 940                        elems->erp_info = pos;
 941                        elems->erp_info_len = elen;
 942                        break;
 943                case WLAN_EID_EXT_SUPP_RATES:
 944                        elems->ext_supp_rates = pos;
 945                        elems->ext_supp_rates_len = elen;
 946                        break;
 947                case WLAN_EID_VENDOR_SPECIFIC:
 948                        if (rtw_ieee802_11_parse_vendor_specific(pos, elen, elems, show_errors))
 949                                unknown++;
 950                        break;
 951                case WLAN_EID_RSN:
 952                        elems->rsn_ie = pos;
 953                        elems->rsn_ie_len = elen;
 954                        break;
 955                case WLAN_EID_PWR_CAPABILITY:
 956                        elems->power_cap = pos;
 957                        elems->power_cap_len = elen;
 958                        break;
 959                case WLAN_EID_SUPPORTED_CHANNELS:
 960                        elems->supp_channels = pos;
 961                        elems->supp_channels_len = elen;
 962                        break;
 963                case WLAN_EID_MOBILITY_DOMAIN:
 964                        elems->mdie = pos;
 965                        elems->mdie_len = elen;
 966                        break;
 967                case WLAN_EID_FAST_BSS_TRANSITION:
 968                        elems->ftie = pos;
 969                        elems->ftie_len = elen;
 970                        break;
 971                case WLAN_EID_TIMEOUT_INTERVAL:
 972                        elems->timeout_int = pos;
 973                        elems->timeout_int_len = elen;
 974                        break;
 975                case WLAN_EID_HT_CAP:
 976                        elems->ht_capabilities = pos;
 977                        elems->ht_capabilities_len = elen;
 978                        break;
 979                case WLAN_EID_HT_OPERATION:
 980                        elems->ht_operation = pos;
 981                        elems->ht_operation_len = elen;
 982                        break;
 983                default:
 984                        unknown++;
 985                        if (!show_errors)
 986                                break;
 987                        DBG_88E("IEEE 802.11 element parse ignored unknown element (id=%d elen=%d)\n",
 988                                id, elen);
 989                        break;
 990                }
 991                left -= elen;
 992                pos += elen;
 993        }
 994        if (left)
 995                return ParseFailed;
 996        return unknown ? ParseUnknown : ParseOK;
 997}
 998
 999u8 key_char2num(u8 ch)
1000{
1001        if ((ch >= '0') && (ch <= '9'))
1002                return ch - '0';
1003        else if ((ch >= 'a') && (ch <= 'f'))
1004                return ch - 'a' + 10;
1005        else if ((ch >= 'A') && (ch <= 'F'))
1006                return ch - 'A' + 10;
1007        else
1008                return 0xff;
1009}
1010
1011u8 str_2char2num(u8 hch, u8 lch)
1012{
1013    return (key_char2num(hch) * 10) + key_char2num(lch);
1014}
1015
1016u8 key_2char2num(u8 hch, u8 lch)
1017{
1018    return (key_char2num(hch) << 4) | key_char2num(lch);
1019}
1020
1021void rtw_macaddr_cfg(u8 *mac_addr)
1022{
1023        u8 mac[ETH_ALEN];
1024        if (!mac_addr)
1025                return;
1026
1027        if (rtw_initmac) {      /* Users specify the mac address */
1028                int jj, kk;
1029
1030                for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
1031                        mac[jj] = key_2char2num(rtw_initmac[kk], rtw_initmac[kk + 1]);
1032                memcpy(mac_addr, mac, ETH_ALEN);
1033        } else {        /* Use the mac address stored in the Efuse */
1034                memcpy(mac, mac_addr, ETH_ALEN);
1035        }
1036
1037        if (((mac[0] == 0xff) && (mac[1] == 0xff) && (mac[2] == 0xff) &&
1038             (mac[3] == 0xff) && (mac[4] == 0xff) && (mac[5] == 0xff)) ||
1039            ((mac[0] == 0x0) && (mac[1] == 0x0) && (mac[2] == 0x0) &&
1040             (mac[3] == 0x0) && (mac[4] == 0x0) && (mac[5] == 0x0))) {
1041                mac[0] = 0x00;
1042                mac[1] = 0xe0;
1043                mac[2] = 0x4c;
1044                mac[3] = 0x87;
1045                mac[4] = 0x00;
1046                mac[5] = 0x00;
1047                /*  use default mac addresss */
1048                memcpy(mac_addr, mac, ETH_ALEN);
1049                DBG_88E("MAC Address from efuse error, assign default one !!!\n");
1050        }
1051
1052        DBG_88E("rtw_macaddr_cfg MAC Address  = %pM\n", (mac_addr));
1053}
1054
1055void dump_ies(u8 *buf, u32 buf_len)
1056{
1057        u8 *pos = (u8 *)buf;
1058        u8 id, len;
1059
1060        while (pos - buf <= buf_len) {
1061                id = *pos;
1062                len = *(pos + 1);
1063
1064                DBG_88E("%s ID:%u, LEN:%u\n", __func__, id, len);
1065                #ifdef CONFIG_88EU_P2P
1066                dump_p2p_ie(pos, len);
1067                #endif
1068                dump_wps_ie(pos, len);
1069
1070                pos += (2 + len);
1071        }
1072}
1073
1074void dump_wps_ie(u8 *ie, u32 ie_len)
1075{
1076        u8 *pos = (u8 *)ie;
1077        u16 id;
1078        u16 len;
1079        u8 *wps_ie;
1080        uint wps_ielen;
1081
1082        wps_ie = rtw_get_wps_ie(ie, ie_len, NULL, &wps_ielen);
1083        if (wps_ie != ie || wps_ielen == 0)
1084                return;
1085
1086        pos += 6;
1087        while (pos - ie < ie_len) {
1088                id = RTW_GET_BE16(pos);
1089                len = RTW_GET_BE16(pos + 2);
1090                DBG_88E("%s ID:0x%04x, LEN:%u\n", __func__, id, len);
1091                pos += (4 + len);
1092        }
1093}
1094
1095#ifdef CONFIG_88EU_P2P
1096void dump_p2p_ie(u8 *ie, u32 ie_len)
1097{
1098        u8 *pos = (u8 *)ie;
1099        u8 id;
1100        u16 len;
1101        u8 *p2p_ie;
1102        uint p2p_ielen;
1103
1104        p2p_ie = rtw_get_p2p_ie(ie, ie_len, NULL, &p2p_ielen);
1105        if (p2p_ie != ie || p2p_ielen == 0)
1106                return;
1107
1108        pos += 6;
1109        while (pos - ie < ie_len) {
1110                id = *pos;
1111                len = get_unaligned_le16(pos + 1);
1112                DBG_88E("%s ID:%u, LEN:%u\n", __func__, id, len);
1113                pos += (3 + len);
1114        }
1115}
1116
1117/**
1118 * rtw_get_p2p_ie - Search P2P IE from a series of IEs
1119 * @in_ie: Address of IEs to search
1120 * @in_len: Length limit from in_ie
1121 * @p2p_ie: If not NULL and P2P IE is found, P2P IE will be copied to the buf starting from p2p_ie
1122 * @p2p_ielen: If not NULL and P2P IE is found, will set to the length of the entire P2P IE
1123 *
1124 * Returns: The address of the P2P IE found, or NULL
1125 */
1126u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen)
1127{
1128        uint cnt = 0;
1129        u8 *p2p_ie_ptr;
1130        u8 eid, p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09};
1131
1132        if (p2p_ielen)
1133                *p2p_ielen = 0;
1134
1135        while (cnt < in_len) {
1136                eid = in_ie[cnt];
1137                if ((in_len < 0) || (cnt > MAX_IE_SZ)) {
1138                        dump_stack();
1139                        return NULL;
1140                }
1141                if ((eid == _VENDOR_SPECIFIC_IE_) && !memcmp(&in_ie[cnt + 2], p2p_oui, 4)) {
1142                        p2p_ie_ptr = in_ie + cnt;
1143
1144                        if (p2p_ie)
1145                                memcpy(p2p_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
1146                        if (p2p_ielen)
1147                                *p2p_ielen = in_ie[cnt + 1] + 2;
1148                        return p2p_ie_ptr;
1149                } else {
1150                        cnt += in_ie[cnt + 1] + 2; /* goto next */
1151                }
1152        }
1153        return NULL;
1154}
1155
1156/**
1157 * rtw_get_p2p_attr - Search a specific P2P attribute from a given P2P IE
1158 * @p2p_ie: Address of P2P IE to search
1159 * @p2p_ielen: Length limit from p2p_ie
1160 * @target_attr_id: The attribute ID of P2P attribute to search
1161 * @buf_attr: If not NULL and the P2P attribute is found, P2P attribute will be copied to the buf starting from buf_attr
1162 * @len_attr: If not NULL and the P2P attribute is found, will set to the length of the entire P2P attribute
1163 *
1164 * Returns: the address of the specific WPS attribute found, or NULL
1165 */
1166u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id, u8 *buf_attr, u32 *len_attr)
1167{
1168        u8 *attr_ptr = NULL;
1169        u8 *target_attr_ptr = NULL;
1170        u8 p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09};
1171
1172        if (len_attr)
1173                *len_attr = 0;
1174
1175        if (!p2p_ie || (p2p_ie[0] != _VENDOR_SPECIFIC_IE_) ||
1176            memcmp(p2p_ie + 2, p2p_oui, 4))
1177                return attr_ptr;
1178
1179        /*  6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) */
1180        attr_ptr = p2p_ie + 6; /* goto first attr */
1181
1182        while (attr_ptr - p2p_ie < p2p_ielen) {
1183                /*  3 = 1(Attribute ID) + 2(Length) */
1184                u8 attr_id = *attr_ptr;
1185                u16 attr_data_len = get_unaligned_le16(attr_ptr + 1);
1186                u16 attr_len = attr_data_len + 3;
1187
1188                if (attr_id == target_attr_id) {
1189                        target_attr_ptr = attr_ptr;
1190
1191                        if (buf_attr)
1192                                memcpy(buf_attr, attr_ptr, attr_len);
1193                        if (len_attr)
1194                                *len_attr = attr_len;
1195                        break;
1196                } else {
1197                        attr_ptr += attr_len; /* goto next */
1198                }
1199        }
1200        return target_attr_ptr;
1201}
1202
1203/**
1204 * rtw_get_p2p_attr_content - Search a specific P2P attribute content from a given P2P IE
1205 * @p2p_ie: Address of P2P IE to search
1206 * @p2p_ielen: Length limit from p2p_ie
1207 * @target_attr_id: The attribute ID of P2P attribute to search
1208 * @buf_content: If not NULL and the P2P attribute is found, P2P attribute content will be copied to the buf starting from buf_content
1209 * @len_content: If not NULL and the P2P attribute is found, will set to the length of the P2P attribute content
1210 *
1211 * Returns: the address of the specific P2P attribute content found, or NULL
1212 */
1213u8 *rtw_get_p2p_attr_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id, u8 *buf_content, uint *len_content)
1214{
1215        u8 *attr_ptr;
1216        u32 attr_len;
1217
1218        if (len_content)
1219                *len_content = 0;
1220
1221        attr_ptr = rtw_get_p2p_attr(p2p_ie, p2p_ielen, target_attr_id, NULL, &attr_len);
1222
1223        if (attr_ptr && attr_len) {
1224                if (buf_content)
1225                        memcpy(buf_content, attr_ptr + 3, attr_len - 3);
1226
1227                if (len_content)
1228                        *len_content = attr_len - 3;
1229
1230                return attr_ptr + 3;
1231        }
1232
1233        return NULL;
1234}
1235
1236u32 rtw_set_p2p_attr_content(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr)
1237{
1238        u32 a_len;
1239
1240        *pbuf = attr_id;
1241
1242        /* u16*)(pbuf + 1) = cpu_to_le16(attr_len); */
1243        RTW_PUT_LE16(pbuf + 1, attr_len);
1244
1245        if (pdata_attr)
1246                memcpy(pbuf + 3, pdata_attr, attr_len);
1247
1248        a_len = attr_len + 3;
1249
1250        return a_len;
1251}
1252
1253static uint rtw_p2p_attr_remove(u8 *ie, uint ielen_ori, u8 attr_id)
1254{
1255        u8 *target_attr;
1256        u32 target_attr_len;
1257        uint ielen = ielen_ori;
1258
1259        while (1) {
1260                target_attr = rtw_get_p2p_attr(ie, ielen, attr_id, NULL, &target_attr_len);
1261                if (target_attr && target_attr_len) {
1262                        u8 *next_attr = target_attr + target_attr_len;
1263                        uint remain_len = ielen - (next_attr - ie);
1264
1265                        memset(target_attr, 0, target_attr_len);
1266                        memcpy(target_attr, next_attr, remain_len);
1267                        memset(target_attr + remain_len, 0, target_attr_len);
1268                        *(ie + 1) -= target_attr_len;
1269                        ielen -= target_attr_len;
1270                } else {
1271                        break;
1272                }
1273        }
1274        return ielen;
1275}
1276
1277void rtw_wlan_bssid_ex_remove_p2p_attr(struct wlan_bssid_ex *bss_ex, u8 attr_id)
1278{
1279        u8 *p2p_ie;
1280        uint p2p_ielen, p2p_ielen_ori;
1281
1282        p2p_ie = rtw_get_p2p_ie(bss_ex->IEs + _FIXED_IE_LENGTH_, bss_ex->IELength - _FIXED_IE_LENGTH_, NULL, &p2p_ielen_ori);
1283        if (p2p_ie) {
1284                p2p_ielen = rtw_p2p_attr_remove(p2p_ie, p2p_ielen_ori, attr_id);
1285                if (p2p_ielen != p2p_ielen_ori) {
1286                        u8 *next_ie_ori = p2p_ie + p2p_ielen_ori;
1287                        u8 *next_ie = p2p_ie + p2p_ielen;
1288                        uint remain_len = bss_ex->IELength - (next_ie_ori - bss_ex->IEs);
1289
1290                        memcpy(next_ie, next_ie_ori, remain_len);
1291                        memset(next_ie + remain_len, 0, p2p_ielen_ori - p2p_ielen);
1292                        bss_ex->IELength -= p2p_ielen_ori - p2p_ielen;
1293                }
1294        }
1295}
1296
1297#endif /* CONFIG_88EU_P2P */
1298
1299/* Baron adds to avoid FreeBSD warning */
1300int ieee80211_is_empty_essid(const char *essid, int essid_len)
1301{
1302        /* Single white space is for Linksys APs */
1303        if (essid_len == 1 && essid[0] == ' ')
1304                return 1;
1305
1306        /* Otherwise, if the entire essid is 0, we assume it is hidden */
1307        while (essid_len) {
1308                essid_len--;
1309                if (essid[essid_len] != '\0')
1310                        return 0;
1311        }
1312
1313        return 1;
1314}
1315
1316int ieee80211_get_hdrlen(u16 fc)
1317{
1318        int hdrlen = 24;
1319
1320        switch (WLAN_FC_GET_TYPE(fc)) {
1321        case RTW_IEEE80211_FTYPE_DATA:
1322                if (fc & RTW_IEEE80211_STYPE_QOS_DATA)
1323                        hdrlen += 2;
1324                if ((fc & RTW_IEEE80211_FCTL_FROMDS) && (fc & RTW_IEEE80211_FCTL_TODS))
1325                        hdrlen += 6; /* Addr4 */
1326                break;
1327        case RTW_IEEE80211_FTYPE_CTL:
1328                switch (WLAN_FC_GET_STYPE(fc)) {
1329                case RTW_IEEE80211_STYPE_CTS:
1330                case RTW_IEEE80211_STYPE_ACK:
1331                        hdrlen = 10;
1332                        break;
1333                default:
1334                        hdrlen = 16;
1335                        break;
1336                }
1337                break;
1338        }
1339
1340        return hdrlen;
1341}
1342
1343static int rtw_get_cipher_info(struct wlan_network *pnetwork)
1344{
1345        u32 wpa_ielen;
1346        unsigned char *pbuf;
1347        int group_cipher = 0, pairwise_cipher = 0, is8021x = 0;
1348        int ret = _FAIL;
1349        pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12);
1350
1351        if (pbuf && (wpa_ielen > 0)) {
1352                if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) {
1353                        pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
1354                        pnetwork->BcnInfo.group_cipher = group_cipher;
1355                        pnetwork->BcnInfo.is_8021x = is8021x;
1356                        ret = _SUCCESS;
1357                }
1358        } else {
1359                pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12);
1360
1361                if (pbuf && (wpa_ielen > 0)) {
1362                        if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) {
1363                                pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
1364                                pnetwork->BcnInfo.group_cipher = group_cipher;
1365                                pnetwork->BcnInfo.is_8021x = is8021x;
1366                                ret = _SUCCESS;
1367                        }
1368                }
1369        }
1370
1371        return ret;
1372}
1373
1374void rtw_get_bcn_info(struct wlan_network *pnetwork)
1375{
1376        unsigned short cap = 0;
1377        u8 bencrypt = 0;
1378        __le16 le_tmp;
1379        u16 wpa_len = 0, rsn_len = 0;
1380        struct HT_info_element *pht_info = NULL;
1381        struct ieee80211_ht_cap *pht_cap = NULL;
1382        unsigned int            len;
1383        unsigned char           *p;
1384
1385        memcpy(&le_tmp, rtw_get_capability_from_ie(pnetwork->network.IEs), 2);
1386        cap = le16_to_cpu(le_tmp);
1387        if (cap & WLAN_CAPABILITY_PRIVACY) {
1388                bencrypt = 1;
1389                pnetwork->network.Privacy = 1;
1390        } else {
1391                pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS;
1392        }
1393        rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &rsn_len, NULL, &wpa_len);
1394
1395        if (rsn_len > 0) {
1396                pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2;
1397        } else if (wpa_len > 0) {
1398                pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA;
1399        } else {
1400                if (bencrypt)
1401                        pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP;
1402        }
1403        rtw_get_cipher_info(pnetwork);
1404
1405        /* get bwmode and ch_offset */
1406        /* parsing HT_CAP_IE */
1407        p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_);
1408        if (p && len > 0) {
1409                        pht_cap = (struct ieee80211_ht_cap *)(p + 2);
1410                        pnetwork->BcnInfo.ht_cap_info = le16_to_cpu(pht_cap->cap_info);
1411        } else {
1412                        pnetwork->BcnInfo.ht_cap_info = 0;
1413        }
1414        /* parsing HT_INFO_IE */
1415        p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_);
1416        if (p && len > 0) {
1417                        pht_info = (struct HT_info_element *)(p + 2);
1418                        pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0];
1419        } else {
1420                        pnetwork->BcnInfo.ht_info_infos_0 = 0;
1421        }
1422}
1423
1424/* show MCS rate, unit: 100Kbps */
1425u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, unsigned char *MCS_rate)
1426{
1427        u16 max_rate = 0;
1428
1429        if (rf_type == RF_1T1R) {
1430                if (MCS_rate[0] & BIT(7))
1431                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650);
1432                else if (MCS_rate[0] & BIT(6))
1433                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585);
1434                else if (MCS_rate[0] & BIT(5))
1435                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
1436                else if (MCS_rate[0] & BIT(4))
1437                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
1438                else if (MCS_rate[0] & BIT(3))
1439                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
1440                else if (MCS_rate[0] & BIT(2))
1441                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195);
1442                else if (MCS_rate[0] & BIT(1))
1443                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
1444                else if (MCS_rate[0] & BIT(0))
1445                        max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65);
1446        } else {
1447                if (MCS_rate[1]) {
1448                        if (MCS_rate[1] & BIT(7))
1449                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 3000 : 2700) : ((short_GI_20) ? 1444 : 1300);
1450                        else if (MCS_rate[1] & BIT(6))
1451                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 2700 : 2430) : ((short_GI_20) ? 1300 : 1170);
1452                        else if (MCS_rate[1] & BIT(5))
1453                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 2400 : 2160) : ((short_GI_20) ? 1156 : 1040);
1454                        else if (MCS_rate[1] & BIT(4))
1455                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 1800 : 1620) : ((short_GI_20) ? 867 : 780);
1456                        else if (MCS_rate[1] & BIT(3))
1457                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
1458                        else if (MCS_rate[1] & BIT(2))
1459                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
1460                        else if (MCS_rate[1] & BIT(1))
1461                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
1462                        else if (MCS_rate[1] & BIT(0))
1463                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
1464                } else {
1465                        if (MCS_rate[0] & BIT(7))
1466                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650);
1467                        else if (MCS_rate[0] & BIT(6))
1468                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585);
1469                        else if (MCS_rate[0] & BIT(5))
1470                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
1471                        else if (MCS_rate[0] & BIT(4))
1472                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
1473                        else if (MCS_rate[0] & BIT(3))
1474                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
1475                        else if (MCS_rate[0] & BIT(2))
1476                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195);
1477                        else if (MCS_rate[0] & BIT(1))
1478                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
1479                        else if (MCS_rate[0] & BIT(0))
1480                                max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65);
1481                }
1482        }
1483        return max_rate;
1484}
1485
1486int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category, u8 *action)
1487{
1488        const u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr);
1489        u16 fc;
1490        u8 c, a = 0;
1491
1492        fc = le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)frame)->frame_ctl);
1493
1494        if ((fc & (RTW_IEEE80211_FCTL_FTYPE | RTW_IEEE80211_FCTL_STYPE)) !=
1495            (RTW_IEEE80211_FTYPE_MGMT | RTW_IEEE80211_STYPE_ACTION))
1496                return false;
1497
1498        c = frame_body[0];
1499
1500        switch (c) {
1501        case RTW_WLAN_CATEGORY_P2P: /* vendor-specific */
1502                break;
1503        default:
1504                a = frame_body[1];
1505        }
1506
1507        if (category)
1508                *category = c;
1509        if (action)
1510                *action = a;
1511
1512        return true;
1513}
1514
1515static const char *_action_public_str[] = {
1516        "ACT_PUB_BSSCOEXIST",
1517        "ACT_PUB_DSE_ENABLE",
1518        "ACT_PUB_DSE_DEENABLE",
1519        "ACT_PUB_DSE_REG_LOCATION",
1520        "ACT_PUB_EXT_CHL_SWITCH",
1521        "ACT_PUB_DSE_MSR_REQ",
1522        "ACT_PUB_DSE_MSR_RPRT",
1523        "ACT_PUB_MP",
1524        "ACT_PUB_DSE_PWR_CONSTRAINT",
1525        "ACT_PUB_VENDOR",
1526        "ACT_PUB_GAS_INITIAL_REQ",
1527        "ACT_PUB_GAS_INITIAL_RSP",
1528        "ACT_PUB_GAS_COMEBACK_REQ",
1529        "ACT_PUB_GAS_COMEBACK_RSP",
1530        "ACT_PUB_TDLS_DISCOVERY_RSP",
1531        "ACT_PUB_LOCATION_TRACK",
1532        "ACT_PUB_RSVD",
1533};
1534
1535const char *action_public_str(u8 action)
1536{
1537        action = (action >= ACT_PUBLIC_MAX) ? ACT_PUBLIC_MAX : action;
1538        return _action_public_str[action];
1539}
1540