1e24c1f86SMichael Straube // SPDX-License-Identifier: GPL-2.0 22865d42cSLarry Finger /****************************************************************************** 32865d42cSLarry Finger * ieee80211.c 42865d42cSLarry Finger * 52865d42cSLarry Finger * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. 62865d42cSLarry Finger * Linux device driver for RTL8192SU 72865d42cSLarry Finger * 82865d42cSLarry Finger * Modifications for inclusion into the Linux staging tree are 92865d42cSLarry Finger * Copyright(c) 2010 Larry Finger. All rights reserved. 102865d42cSLarry Finger * 112865d42cSLarry Finger * Contact information: 122865d42cSLarry Finger * WLAN FAE <wlanfae@realtek.com>. 132865d42cSLarry Finger * Larry Finger <Larry.Finger@lwfinger.net> 142865d42cSLarry Finger * 152865d42cSLarry Finger ******************************************************************************/ 162865d42cSLarry Finger 172865d42cSLarry Finger #define _IEEE80211_C 182865d42cSLarry Finger 192865d42cSLarry Finger #include "drv_types.h" 202865d42cSLarry Finger #include "ieee80211.h" 212865d42cSLarry Finger #include "wifi.h" 222865d42cSLarry Finger #include "osdep_service.h" 232865d42cSLarry Finger #include "wlan_bssdef.h" 242865d42cSLarry Finger 252865d42cSLarry Finger static const u8 WPA_OUI_TYPE[] = {0x00, 0x50, 0xf2, 1}; 262865d42cSLarry Finger static const u8 WPA_CIPHER_SUITE_NONE[] = {0x00, 0x50, 0xf2, 0}; 272865d42cSLarry Finger static const u8 WPA_CIPHER_SUITE_WEP40[] = {0x00, 0x50, 0xf2, 1}; 282865d42cSLarry Finger static const u8 WPA_CIPHER_SUITE_TKIP[] = {0x00, 0x50, 0xf2, 2}; 292865d42cSLarry Finger static const u8 WPA_CIPHER_SUITE_CCMP[] = {0x00, 0x50, 0xf2, 4}; 302865d42cSLarry Finger static const u8 WPA_CIPHER_SUITE_WEP104[] = {0x00, 0x50, 0xf2, 5}; 312865d42cSLarry Finger 322865d42cSLarry Finger static const u8 RSN_CIPHER_SUITE_NONE[] = {0x00, 0x0f, 0xac, 0}; 332865d42cSLarry Finger static const u8 RSN_CIPHER_SUITE_WEP40[] = {0x00, 0x0f, 0xac, 1}; 342865d42cSLarry Finger static const u8 RSN_CIPHER_SUITE_TKIP[] = {0x00, 0x0f, 0xac, 2}; 352865d42cSLarry Finger static const u8 RSN_CIPHER_SUITE_CCMP[] = {0x00, 0x0f, 0xac, 4}; 362865d42cSLarry Finger static const u8 RSN_CIPHER_SUITE_WEP104[] = {0x00, 0x0f, 0xac, 5}; 372865d42cSLarry Finger 382865d42cSLarry Finger /*----------------------------------------------------------- 392865d42cSLarry Finger * for adhoc-master to generate ie and provide supported-rate to fw 402865d42cSLarry Finger *----------------------------------------------------------- 412865d42cSLarry Finger */ 422865d42cSLarry Finger 432865d42cSLarry Finger static u8 WIFI_CCKRATES[] = { 442865d42cSLarry Finger (IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK), 452865d42cSLarry Finger (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK), 462865d42cSLarry Finger (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK), 472865d42cSLarry Finger (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK) 482865d42cSLarry Finger }; 492865d42cSLarry Finger 502865d42cSLarry Finger static u8 WIFI_OFDMRATES[] = { 512865d42cSLarry Finger (IEEE80211_OFDM_RATE_6MB), 522865d42cSLarry Finger (IEEE80211_OFDM_RATE_9MB), 532865d42cSLarry Finger (IEEE80211_OFDM_RATE_12MB), 542865d42cSLarry Finger (IEEE80211_OFDM_RATE_18MB), 552865d42cSLarry Finger (IEEE80211_OFDM_RATE_24MB), 562865d42cSLarry Finger (IEEE80211_OFDM_RATE_36MB), 572865d42cSLarry Finger (IEEE80211_OFDM_RATE_48MB), 582865d42cSLarry Finger (IEEE80211_OFDM_RATE_54MB) 592865d42cSLarry Finger }; 602865d42cSLarry Finger 612865d42cSLarry Finger uint r8712_is_cckrates_included(u8 *rate) 622865d42cSLarry Finger { 632865d42cSLarry Finger u32 i = 0; 642865d42cSLarry Finger 652865d42cSLarry Finger while (rate[i] != 0) { 662865d42cSLarry Finger if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || 672865d42cSLarry Finger (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) 682865d42cSLarry Finger return true; 692865d42cSLarry Finger i++; 702865d42cSLarry Finger } 712865d42cSLarry Finger return false; 722865d42cSLarry Finger } 732865d42cSLarry Finger 742865d42cSLarry Finger uint r8712_is_cckratesonly_included(u8 *rate) 752865d42cSLarry Finger { 762865d42cSLarry Finger u32 i = 0; 772865d42cSLarry Finger 782865d42cSLarry Finger while (rate[i] != 0) { 792865d42cSLarry Finger if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && 802865d42cSLarry Finger (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) 812865d42cSLarry Finger return false; 822865d42cSLarry Finger i++; 832865d42cSLarry Finger } 842865d42cSLarry Finger return true; 852865d42cSLarry Finger } 862865d42cSLarry Finger 872865d42cSLarry Finger /* r8712_set_ie will update frame length */ 882865d42cSLarry Finger u8 *r8712_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen) 892865d42cSLarry Finger { 902865d42cSLarry Finger *pbuf = (u8)index; 912865d42cSLarry Finger *(pbuf + 1) = (u8)len; 922865d42cSLarry Finger if (len > 0) 932865d42cSLarry Finger memcpy((void *)(pbuf + 2), (void *)source, len); 942865d42cSLarry Finger *frlen = *frlen + (len + 2); 952865d42cSLarry Finger return pbuf + len + 2; 962865d42cSLarry Finger } 972865d42cSLarry Finger 984fd8cba1SPunit Vara /* --------------------------------------------------------------------------- 994fd8cba1SPunit Vara * index: the information element id index, limit is the limit for search 1004fd8cba1SPunit Vara * --------------------------------------------------------------------------- 1014fd8cba1SPunit Vara */ 10274f15056SStefano Manni u8 *r8712_get_ie(u8 *pbuf, sint index, uint *len, sint limit) 1032865d42cSLarry Finger { 1042865d42cSLarry Finger sint tmp, i; 1052865d42cSLarry Finger u8 *p; 1062865d42cSLarry Finger 1072865d42cSLarry Finger if (limit < 1) 1082865d42cSLarry Finger return NULL; 1092865d42cSLarry Finger p = pbuf; 1102865d42cSLarry Finger i = 0; 1112865d42cSLarry Finger *len = 0; 1122865d42cSLarry Finger while (1) { 1132865d42cSLarry Finger if (*p == index) { 1142865d42cSLarry Finger *len = *(p + 1); 1152865d42cSLarry Finger return p; 116e92c3511SNitin Kuppelur } 1172865d42cSLarry Finger tmp = *(p + 1); 1182865d42cSLarry Finger p += (tmp + 2); 1192865d42cSLarry Finger i += (tmp + 2); 1202865d42cSLarry Finger if (i >= limit) 1212865d42cSLarry Finger break; 1222865d42cSLarry Finger } 1232865d42cSLarry Finger return NULL; 1242865d42cSLarry Finger } 1252865d42cSLarry Finger 1267fb539edSJoshua Clayton static void set_supported_rate(u8 *rates, uint mode) 1272865d42cSLarry Finger { 1287fb539edSJoshua Clayton memset(rates, 0, NDIS_802_11_LENGTH_RATES_EX); 1292865d42cSLarry Finger switch (mode) { 1302865d42cSLarry Finger case WIRELESS_11B: 1317fb539edSJoshua Clayton memcpy(rates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); 1322865d42cSLarry Finger break; 1332865d42cSLarry Finger case WIRELESS_11G: 1342865d42cSLarry Finger case WIRELESS_11A: 1357fb539edSJoshua Clayton memcpy(rates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN); 1362865d42cSLarry Finger break; 1372865d42cSLarry Finger case WIRELESS_11BG: 1387fb539edSJoshua Clayton memcpy(rates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); 1397fb539edSJoshua Clayton memcpy(rates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, 1402865d42cSLarry Finger IEEE80211_NUM_OFDM_RATESLEN); 1412865d42cSLarry Finger break; 1422865d42cSLarry Finger } 1432865d42cSLarry Finger } 1442865d42cSLarry Finger 1452865d42cSLarry Finger static uint r8712_get_rateset_len(u8 *rateset) 1462865d42cSLarry Finger { 1472865d42cSLarry Finger uint i = 0; 1482865d42cSLarry Finger 1492865d42cSLarry Finger while (1) { 1502865d42cSLarry Finger if ((rateset[i]) == 0) 1512865d42cSLarry Finger break; 1522865d42cSLarry Finger if (i > 12) 1532865d42cSLarry Finger break; 1542865d42cSLarry Finger i++; 1552865d42cSLarry Finger } 1562865d42cSLarry Finger return i; 1572865d42cSLarry Finger } 1582865d42cSLarry Finger 1597ec3ff69SNishka Dasgupta int r8712_generate_ie(struct registry_priv *registrypriv) 1602865d42cSLarry Finger { 161fd161c61SStefano Manni int rate_len; 162fd161c61SStefano Manni uint sz = 0; 1637ec3ff69SNishka Dasgupta struct wlan_bssid_ex *dev_network = ®istrypriv->dev_network; 1647ec3ff69SNishka Dasgupta u8 *ie = dev_network->IEs; 1657ec3ff69SNishka Dasgupta u16 beaconPeriod = (u16)dev_network->Configuration.BeaconPeriod; 1662865d42cSLarry Finger 1672865d42cSLarry Finger /*timestamp will be inserted by hardware*/ 1682865d42cSLarry Finger sz += 8; 1692865d42cSLarry Finger ie += sz; 1702865d42cSLarry Finger /*beacon interval : 2bytes*/ 1713be4fdf6SMartin Homuth *(__le16 *)ie = cpu_to_le16(beaconPeriod); 1722865d42cSLarry Finger sz += 2; 1732865d42cSLarry Finger ie += 2; 1742865d42cSLarry Finger /*capability info*/ 1752865d42cSLarry Finger *(u16 *)ie = 0; 176*5fc95c40SIvan Safonov *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_IBSS); 1777ec3ff69SNishka Dasgupta if (registrypriv->preamble == PREAMBLE_SHORT) 178*5fc95c40SIvan Safonov *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); 1797ec3ff69SNishka Dasgupta if (dev_network->Privacy) 180*5fc95c40SIvan Safonov *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); 1812865d42cSLarry Finger sz += 2; 1822865d42cSLarry Finger ie += 2; 1832865d42cSLarry Finger /*SSID*/ 1847ec3ff69SNishka Dasgupta ie = r8712_set_ie(ie, _SSID_IE_, dev_network->Ssid.SsidLength, 1857ec3ff69SNishka Dasgupta dev_network->Ssid.Ssid, &sz); 1862865d42cSLarry Finger /*supported rates*/ 1877ec3ff69SNishka Dasgupta set_supported_rate(dev_network->rates, registrypriv->wireless_mode); 1887ec3ff69SNishka Dasgupta rate_len = r8712_get_rateset_len(dev_network->rates); 18992abe42bSJaya Durga if (rate_len > 8) { 1902865d42cSLarry Finger ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_, 8, 1917ec3ff69SNishka Dasgupta dev_network->rates, &sz); 19292abe42bSJaya Durga ie = r8712_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), 1937ec3ff69SNishka Dasgupta (dev_network->rates + 8), &sz); 1943bca7cf8SJaya Durga } else { 1952865d42cSLarry Finger ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_, 1967ec3ff69SNishka Dasgupta rate_len, dev_network->rates, &sz); 1973bca7cf8SJaya Durga } 1982865d42cSLarry Finger /*DS parameter set*/ 1992865d42cSLarry Finger ie = r8712_set_ie(ie, _DSSET_IE_, 1, 2007ec3ff69SNishka Dasgupta (u8 *)&dev_network->Configuration.DSConfig, &sz); 2012865d42cSLarry Finger /*IBSS Parameter Set*/ 2022865d42cSLarry Finger ie = r8712_set_ie(ie, _IBSS_PARA_IE_, 2, 2037ec3ff69SNishka Dasgupta (u8 *)&dev_network->Configuration.ATIMWindow, &sz); 2042865d42cSLarry Finger return sz; 2052865d42cSLarry Finger } 2062865d42cSLarry Finger 2077ec3ff69SNishka Dasgupta unsigned char *r8712_get_wpa_ie(unsigned char *ie, uint *wpa_ie_len, int limit) 2082865d42cSLarry Finger { 20974f15056SStefano Manni u32 len; 2102865d42cSLarry Finger u16 val16; 2112865d42cSLarry Finger unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; 2127ec3ff69SNishka Dasgupta u8 *buf = ie; 2132865d42cSLarry Finger 2142865d42cSLarry Finger while (1) { 2157ec3ff69SNishka Dasgupta buf = r8712_get_ie(buf, _WPA_IE_ID_, &len, limit); 2167ec3ff69SNishka Dasgupta if (buf) { 2172865d42cSLarry Finger /*check if oui matches...*/ 2187ec3ff69SNishka Dasgupta if (memcmp((buf + 2), wpa_oui_type, 2193be4fdf6SMartin Homuth sizeof(wpa_oui_type))) 2202865d42cSLarry Finger goto check_next_ie; 2212865d42cSLarry Finger /*check version...*/ 2227ec3ff69SNishka Dasgupta memcpy((u8 *)&val16, (buf + 6), sizeof(val16)); 22356384ad6SJannik Becher le16_to_cpus(&val16); 2242865d42cSLarry Finger if (val16 != 0x0001) 2252865d42cSLarry Finger goto check_next_ie; 2267ec3ff69SNishka Dasgupta *wpa_ie_len = *(buf + 1); 2277ec3ff69SNishka Dasgupta return buf; 228e92c3511SNitin Kuppelur } 2292865d42cSLarry Finger *wpa_ie_len = 0; 2302865d42cSLarry Finger return NULL; 2312865d42cSLarry Finger check_next_ie: 2327ec3ff69SNishka Dasgupta limit = limit - (buf - ie) - 2 - len; 2332865d42cSLarry Finger if (limit <= 0) 2342865d42cSLarry Finger break; 2357ec3ff69SNishka Dasgupta buf += (2 + len); 2362865d42cSLarry Finger } 2372865d42cSLarry Finger *wpa_ie_len = 0; 2382865d42cSLarry Finger return NULL; 2392865d42cSLarry Finger } 2402865d42cSLarry Finger 241a77a40cfSBhagyashri Dighole unsigned char *r8712_get_wpa2_ie(unsigned char *pie, uint *rsn_ie_len, 242a77a40cfSBhagyashri Dighole int limit) 2432865d42cSLarry Finger { 2442865d42cSLarry Finger return r8712_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit); 2452865d42cSLarry Finger } 2462865d42cSLarry Finger 2472865d42cSLarry Finger static int r8712_get_wpa_cipher_suite(u8 *s) 2482865d42cSLarry Finger { 2492865d42cSLarry Finger if (!memcmp(s, (void *)WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN)) 2502865d42cSLarry Finger return WPA_CIPHER_NONE; 2512865d42cSLarry Finger if (!memcmp(s, (void *)WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN)) 2522865d42cSLarry Finger return WPA_CIPHER_WEP40; 2532865d42cSLarry Finger if (!memcmp(s, (void *)WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN)) 2542865d42cSLarry Finger return WPA_CIPHER_TKIP; 2552865d42cSLarry Finger if (!memcmp(s, (void *)WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN)) 2562865d42cSLarry Finger return WPA_CIPHER_CCMP; 2572865d42cSLarry Finger if (!memcmp(s, (void *)WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN)) 2582865d42cSLarry Finger return WPA_CIPHER_WEP104; 2592865d42cSLarry Finger return 0; 2602865d42cSLarry Finger } 2612865d42cSLarry Finger 2622865d42cSLarry Finger static int r8712_get_wpa2_cipher_suite(u8 *s) 2632865d42cSLarry Finger { 2642865d42cSLarry Finger if (!memcmp(s, (void *)RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN)) 2652865d42cSLarry Finger return WPA_CIPHER_NONE; 2662865d42cSLarry Finger if (!memcmp(s, (void *)RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN)) 2672865d42cSLarry Finger return WPA_CIPHER_WEP40; 2682865d42cSLarry Finger if (!memcmp(s, (void *)RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN)) 2692865d42cSLarry Finger return WPA_CIPHER_TKIP; 2702865d42cSLarry Finger if (!memcmp(s, (void *)RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN)) 2712865d42cSLarry Finger return WPA_CIPHER_CCMP; 2722865d42cSLarry Finger if (!memcmp(s, (void *)RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN)) 2732865d42cSLarry Finger return WPA_CIPHER_WEP104; 2742865d42cSLarry Finger return 0; 2752865d42cSLarry Finger } 2762865d42cSLarry Finger 2772865d42cSLarry Finger int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, 2782865d42cSLarry Finger int *pairwise_cipher) 2792865d42cSLarry Finger { 2808ffca9eaSPeter Senna Tschudin int i; 2812865d42cSLarry Finger int left, count; 2822865d42cSLarry Finger u8 *pos; 2832865d42cSLarry Finger 2842865d42cSLarry Finger if (wpa_ie_len <= 0) { 2852865d42cSLarry Finger /* No WPA IE - fail silently */ 2861ef20d57SNishka Dasgupta return -EINVAL; 2872865d42cSLarry Finger } 28895ee706eSVarsha Rao if ((*wpa_ie != _WPA_IE_ID_) || 28995ee706eSVarsha Rao (*(wpa_ie + 1) != (u8)(wpa_ie_len - 2)) || 29095ee706eSVarsha Rao (memcmp(wpa_ie + 2, (void *)WPA_OUI_TYPE, WPA_SELECTOR_LEN))) 2911ef20d57SNishka Dasgupta return -EINVAL; 2922865d42cSLarry Finger pos = wpa_ie; 2932865d42cSLarry Finger pos += 8; 2942865d42cSLarry Finger left = wpa_ie_len - 8; 2952865d42cSLarry Finger /*group_cipher*/ 2962865d42cSLarry Finger if (left >= WPA_SELECTOR_LEN) { 2972865d42cSLarry Finger *group_cipher = r8712_get_wpa_cipher_suite(pos); 2982865d42cSLarry Finger pos += WPA_SELECTOR_LEN; 2992865d42cSLarry Finger left -= WPA_SELECTOR_LEN; 300168a2c10SLuis de Bethencourt } else if (left > 0) { 3011ef20d57SNishka Dasgupta return -EINVAL; 302168a2c10SLuis de Bethencourt } 3032865d42cSLarry Finger /*pairwise_cipher*/ 3042865d42cSLarry Finger if (left >= 2) { 30556384ad6SJannik Becher count = le16_to_cpu(*(__le16 *)pos); 3062865d42cSLarry Finger pos += 2; 3072865d42cSLarry Finger left -= 2; 3082865d42cSLarry Finger if (count == 0 || left < count * WPA_SELECTOR_LEN) 3091ef20d57SNishka Dasgupta return -EINVAL; 3102865d42cSLarry Finger for (i = 0; i < count; i++) { 3112865d42cSLarry Finger *pairwise_cipher |= r8712_get_wpa_cipher_suite(pos); 3122865d42cSLarry Finger pos += WPA_SELECTOR_LEN; 3132865d42cSLarry Finger left -= WPA_SELECTOR_LEN; 3142865d42cSLarry Finger } 315168a2c10SLuis de Bethencourt } else if (left == 1) { 3161ef20d57SNishka Dasgupta return -EINVAL; 317168a2c10SLuis de Bethencourt } 3181ef20d57SNishka Dasgupta return 0; 3192865d42cSLarry Finger } 3202865d42cSLarry Finger 3212865d42cSLarry Finger int r8712_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, 3222865d42cSLarry Finger int *pairwise_cipher) 3232865d42cSLarry Finger { 3248ffca9eaSPeter Senna Tschudin int i; 3252865d42cSLarry Finger int left, count; 3262865d42cSLarry Finger u8 *pos; 3272865d42cSLarry Finger 3282865d42cSLarry Finger if (rsn_ie_len <= 0) { 3292865d42cSLarry Finger /* No RSN IE - fail silently */ 330f5e5eaefSNishka Dasgupta return -EINVAL; 3312865d42cSLarry Finger } 3324ef2de5aSLuis de Bethencourt if ((*rsn_ie != _WPA2_IE_ID_) || 3334ef2de5aSLuis de Bethencourt (*(rsn_ie + 1) != (u8)(rsn_ie_len - 2))) 334f5e5eaefSNishka Dasgupta return -EINVAL; 3352865d42cSLarry Finger pos = rsn_ie; 3362865d42cSLarry Finger pos += 4; 3372865d42cSLarry Finger left = rsn_ie_len - 4; 3382865d42cSLarry Finger /*group_cipher*/ 3392865d42cSLarry Finger if (left >= RSN_SELECTOR_LEN) { 3402865d42cSLarry Finger *group_cipher = r8712_get_wpa2_cipher_suite(pos); 3412865d42cSLarry Finger pos += RSN_SELECTOR_LEN; 3422865d42cSLarry Finger left -= RSN_SELECTOR_LEN; 343168a2c10SLuis de Bethencourt } else if (left > 0) { 344f5e5eaefSNishka Dasgupta return -EINVAL; 345168a2c10SLuis de Bethencourt } 3462865d42cSLarry Finger /*pairwise_cipher*/ 3472865d42cSLarry Finger if (left >= 2) { 34856384ad6SJannik Becher count = le16_to_cpu(*(__le16 *)pos); 3492865d42cSLarry Finger pos += 2; 3502865d42cSLarry Finger left -= 2; 3512865d42cSLarry Finger if (count == 0 || left < count * RSN_SELECTOR_LEN) 352f5e5eaefSNishka Dasgupta return -EINVAL; 3532865d42cSLarry Finger for (i = 0; i < count; i++) { 3542865d42cSLarry Finger *pairwise_cipher |= r8712_get_wpa2_cipher_suite(pos); 3552865d42cSLarry Finger pos += RSN_SELECTOR_LEN; 3562865d42cSLarry Finger left -= RSN_SELECTOR_LEN; 3572865d42cSLarry Finger } 358168a2c10SLuis de Bethencourt } else if (left == 1) { 359f5e5eaefSNishka Dasgupta return -EINVAL; 360168a2c10SLuis de Bethencourt } 361f5e5eaefSNishka Dasgupta return 0; 3622865d42cSLarry Finger } 3632865d42cSLarry Finger 3642865d42cSLarry Finger int r8712_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, 3652865d42cSLarry Finger u8 *wpa_ie, u16 *wpa_len) 3662865d42cSLarry Finger { 367e29d3ebcSSudip Mukherjee u8 authmode; 3682865d42cSLarry Finger u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; 3692865d42cSLarry Finger uint cnt; 3702865d42cSLarry Finger 3712865d42cSLarry Finger /*Search required WPA or WPA2 IE and copy to sec_ie[ ]*/ 372bb106dc0SBhaktipriya Shridhar cnt = _TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_; 3732865d42cSLarry Finger while (cnt < in_len) { 3742865d42cSLarry Finger authmode = in_ie[cnt]; 3752865d42cSLarry Finger if ((authmode == _WPA_IE_ID_) && 3762865d42cSLarry Finger (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) { 3772865d42cSLarry Finger memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); 3782865d42cSLarry Finger *wpa_len = in_ie[cnt + 1] + 2; 3792865d42cSLarry Finger cnt += in_ie[cnt + 1] + 2; /*get next */ 3802865d42cSLarry Finger } else { 3812865d42cSLarry Finger if (authmode == _WPA2_IE_ID_) { 3822865d42cSLarry Finger memcpy(rsn_ie, &in_ie[cnt], 3832865d42cSLarry Finger in_ie[cnt + 1] + 2); 3842865d42cSLarry Finger *rsn_len = in_ie[cnt + 1] + 2; 3852865d42cSLarry Finger cnt += in_ie[cnt + 1] + 2; /*get next*/ 386168a2c10SLuis de Bethencourt } else { 3872865d42cSLarry Finger cnt += in_ie[cnt + 1] + 2; /*get next*/ 3882865d42cSLarry Finger } 3892865d42cSLarry Finger } 390168a2c10SLuis de Bethencourt } 3912865d42cSLarry Finger return *rsn_len + *wpa_len; 3922865d42cSLarry Finger } 3932865d42cSLarry Finger 3942865d42cSLarry Finger int r8712_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) 3952865d42cSLarry Finger { 3962865d42cSLarry Finger int match; 3972865d42cSLarry Finger uint cnt; 3982865d42cSLarry Finger u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; 3992865d42cSLarry Finger 4002865d42cSLarry Finger cnt = 12; 4012865d42cSLarry Finger match = false; 4022865d42cSLarry Finger while (cnt < in_len) { 4032865d42cSLarry Finger eid = in_ie[cnt]; 4042865d42cSLarry Finger if ((eid == _WPA_IE_ID_) && 4052865d42cSLarry Finger (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) { 4062865d42cSLarry Finger memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); 4072865d42cSLarry Finger *wps_ielen = in_ie[cnt + 1] + 2; 4082865d42cSLarry Finger cnt += in_ie[cnt + 1] + 2; 4092865d42cSLarry Finger match = true; 4102865d42cSLarry Finger break; 411e92c3511SNitin Kuppelur } 4122865d42cSLarry Finger cnt += in_ie[cnt + 1] + 2; /* goto next */ 4132865d42cSLarry Finger } 4142865d42cSLarry Finger return match; 4152865d42cSLarry Finger } 416