12865d42cSLarry Finger /****************************************************************************** 22865d42cSLarry Finger * ieee80211.c 32865d42cSLarry Finger * 42865d42cSLarry Finger * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. 52865d42cSLarry Finger * Linux device driver for RTL8192SU 62865d42cSLarry Finger * 72865d42cSLarry Finger * This program is free software; you can redistribute it and/or modify it 82865d42cSLarry Finger * under the terms of version 2 of the GNU General Public License as 92865d42cSLarry Finger * published by the Free Software Foundation. 102865d42cSLarry Finger * 112865d42cSLarry Finger * This program is distributed in the hope that it will be useful, but WITHOUT 122865d42cSLarry Finger * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 132865d42cSLarry Finger * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 142865d42cSLarry Finger * more details. 152865d42cSLarry Finger * 162865d42cSLarry Finger * Modifications for inclusion into the Linux staging tree are 172865d42cSLarry Finger * Copyright(c) 2010 Larry Finger. All rights reserved. 182865d42cSLarry Finger * 192865d42cSLarry Finger * Contact information: 202865d42cSLarry Finger * WLAN FAE <wlanfae@realtek.com>. 212865d42cSLarry Finger * Larry Finger <Larry.Finger@lwfinger.net> 222865d42cSLarry Finger * 232865d42cSLarry Finger ******************************************************************************/ 242865d42cSLarry Finger 252865d42cSLarry Finger #define _IEEE80211_C 262865d42cSLarry Finger 272865d42cSLarry Finger #include "drv_types.h" 282865d42cSLarry Finger #include "ieee80211.h" 292865d42cSLarry Finger #include "wifi.h" 302865d42cSLarry Finger #include "osdep_service.h" 312865d42cSLarry Finger #include "wlan_bssdef.h" 322865d42cSLarry Finger 332865d42cSLarry Finger static const u8 WPA_OUI_TYPE[] = {0x00, 0x50, 0xf2, 1}; 342865d42cSLarry Finger static const u8 WPA_CIPHER_SUITE_NONE[] = {0x00, 0x50, 0xf2, 0}; 352865d42cSLarry Finger static const u8 WPA_CIPHER_SUITE_WEP40[] = {0x00, 0x50, 0xf2, 1}; 362865d42cSLarry Finger static const u8 WPA_CIPHER_SUITE_TKIP[] = {0x00, 0x50, 0xf2, 2}; 372865d42cSLarry Finger static const u8 WPA_CIPHER_SUITE_CCMP[] = {0x00, 0x50, 0xf2, 4}; 382865d42cSLarry Finger static const u8 WPA_CIPHER_SUITE_WEP104[] = {0x00, 0x50, 0xf2, 5}; 392865d42cSLarry Finger 402865d42cSLarry Finger static const u8 RSN_CIPHER_SUITE_NONE[] = {0x00, 0x0f, 0xac, 0}; 412865d42cSLarry Finger static const u8 RSN_CIPHER_SUITE_WEP40[] = {0x00, 0x0f, 0xac, 1}; 422865d42cSLarry Finger static const u8 RSN_CIPHER_SUITE_TKIP[] = {0x00, 0x0f, 0xac, 2}; 432865d42cSLarry Finger static const u8 RSN_CIPHER_SUITE_CCMP[] = {0x00, 0x0f, 0xac, 4}; 442865d42cSLarry Finger static const u8 RSN_CIPHER_SUITE_WEP104[] = {0x00, 0x0f, 0xac, 5}; 452865d42cSLarry Finger 462865d42cSLarry Finger /*----------------------------------------------------------- 472865d42cSLarry Finger * for adhoc-master to generate ie and provide supported-rate to fw 482865d42cSLarry Finger *----------------------------------------------------------- 492865d42cSLarry Finger */ 502865d42cSLarry Finger 512865d42cSLarry Finger static u8 WIFI_CCKRATES[] = { 522865d42cSLarry Finger (IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK), 532865d42cSLarry Finger (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK), 542865d42cSLarry Finger (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK), 552865d42cSLarry Finger (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK) 562865d42cSLarry Finger }; 572865d42cSLarry Finger 582865d42cSLarry Finger static u8 WIFI_OFDMRATES[] = { 592865d42cSLarry Finger (IEEE80211_OFDM_RATE_6MB), 602865d42cSLarry Finger (IEEE80211_OFDM_RATE_9MB), 612865d42cSLarry Finger (IEEE80211_OFDM_RATE_12MB), 622865d42cSLarry Finger (IEEE80211_OFDM_RATE_18MB), 632865d42cSLarry Finger (IEEE80211_OFDM_RATE_24MB), 642865d42cSLarry Finger (IEEE80211_OFDM_RATE_36MB), 652865d42cSLarry Finger (IEEE80211_OFDM_RATE_48MB), 662865d42cSLarry Finger (IEEE80211_OFDM_RATE_54MB) 672865d42cSLarry Finger }; 682865d42cSLarry Finger 692865d42cSLarry Finger uint r8712_is_cckrates_included(u8 *rate) 702865d42cSLarry Finger { 712865d42cSLarry Finger u32 i = 0; 722865d42cSLarry Finger 732865d42cSLarry Finger while (rate[i] != 0) { 742865d42cSLarry Finger if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || 752865d42cSLarry Finger (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) 762865d42cSLarry Finger return true; 772865d42cSLarry Finger i++; 782865d42cSLarry Finger } 792865d42cSLarry Finger return false; 802865d42cSLarry Finger } 812865d42cSLarry Finger 822865d42cSLarry Finger uint r8712_is_cckratesonly_included(u8 *rate) 832865d42cSLarry Finger { 842865d42cSLarry Finger u32 i = 0; 852865d42cSLarry Finger 862865d42cSLarry Finger while (rate[i] != 0) { 872865d42cSLarry Finger if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && 882865d42cSLarry Finger (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) 892865d42cSLarry Finger return false; 902865d42cSLarry Finger i++; 912865d42cSLarry Finger } 922865d42cSLarry Finger return true; 932865d42cSLarry Finger } 942865d42cSLarry Finger 952865d42cSLarry Finger /* r8712_set_ie will update frame length */ 962865d42cSLarry Finger u8 *r8712_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen) 972865d42cSLarry Finger { 982865d42cSLarry Finger *pbuf = (u8)index; 992865d42cSLarry Finger *(pbuf + 1) = (u8)len; 1002865d42cSLarry Finger if (len > 0) 1012865d42cSLarry Finger memcpy((void *)(pbuf + 2), (void *)source, len); 1022865d42cSLarry Finger *frlen = *frlen + (len + 2); 1032865d42cSLarry Finger return pbuf + len + 2; 1042865d42cSLarry Finger } 1052865d42cSLarry Finger 1064fd8cba1SPunit Vara /* --------------------------------------------------------------------------- 1074fd8cba1SPunit Vara * index: the information element id index, limit is the limit for search 1084fd8cba1SPunit Vara * --------------------------------------------------------------------------- 1094fd8cba1SPunit Vara */ 1102865d42cSLarry Finger u8 *r8712_get_ie(u8 *pbuf, sint index, sint *len, sint limit) 1112865d42cSLarry Finger { 1122865d42cSLarry Finger sint tmp, i; 1132865d42cSLarry Finger u8 *p; 1142865d42cSLarry Finger 1152865d42cSLarry Finger if (limit < 1) 1162865d42cSLarry Finger return NULL; 1172865d42cSLarry Finger p = pbuf; 1182865d42cSLarry Finger i = 0; 1192865d42cSLarry Finger *len = 0; 1202865d42cSLarry Finger while (1) { 1212865d42cSLarry Finger if (*p == index) { 1222865d42cSLarry Finger *len = *(p + 1); 1232865d42cSLarry Finger return p; 124e92c3511SNitin Kuppelur } 1252865d42cSLarry Finger tmp = *(p + 1); 1262865d42cSLarry Finger p += (tmp + 2); 1272865d42cSLarry Finger i += (tmp + 2); 1282865d42cSLarry Finger if (i >= limit) 1292865d42cSLarry Finger break; 1302865d42cSLarry Finger } 1312865d42cSLarry Finger return NULL; 1322865d42cSLarry Finger } 1332865d42cSLarry Finger 1347fb539edSJoshua Clayton static void set_supported_rate(u8 *rates, uint mode) 1352865d42cSLarry Finger { 1367fb539edSJoshua Clayton memset(rates, 0, NDIS_802_11_LENGTH_RATES_EX); 1372865d42cSLarry Finger switch (mode) { 1382865d42cSLarry Finger case WIRELESS_11B: 1397fb539edSJoshua Clayton memcpy(rates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); 1402865d42cSLarry Finger break; 1412865d42cSLarry Finger case WIRELESS_11G: 1422865d42cSLarry Finger case WIRELESS_11A: 1437fb539edSJoshua Clayton memcpy(rates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN); 1442865d42cSLarry Finger break; 1452865d42cSLarry Finger case WIRELESS_11BG: 1467fb539edSJoshua Clayton memcpy(rates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); 1477fb539edSJoshua Clayton memcpy(rates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, 1482865d42cSLarry Finger IEEE80211_NUM_OFDM_RATESLEN); 1492865d42cSLarry Finger break; 1502865d42cSLarry Finger } 1512865d42cSLarry Finger } 1522865d42cSLarry Finger 1532865d42cSLarry Finger static uint r8712_get_rateset_len(u8 *rateset) 1542865d42cSLarry Finger { 1552865d42cSLarry Finger uint i = 0; 1562865d42cSLarry Finger 1572865d42cSLarry Finger while (1) { 1582865d42cSLarry Finger if ((rateset[i]) == 0) 1592865d42cSLarry Finger break; 1602865d42cSLarry Finger if (i > 12) 1612865d42cSLarry Finger break; 1622865d42cSLarry Finger i++; 1632865d42cSLarry Finger } 1642865d42cSLarry Finger return i; 1652865d42cSLarry Finger } 1662865d42cSLarry Finger 167ee5b1aadSAli Bahar int r8712_generate_ie(struct registry_priv *pregistrypriv) 1682865d42cSLarry Finger { 1692865d42cSLarry Finger int sz = 0, rateLen; 1702865d42cSLarry Finger struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; 1712865d42cSLarry Finger u8 *ie = pdev_network->IEs; 1722865d42cSLarry Finger 1732865d42cSLarry Finger /*timestamp will be inserted by hardware*/ 1742865d42cSLarry Finger sz += 8; 1752865d42cSLarry Finger ie += sz; 1762865d42cSLarry Finger /*beacon interval : 2bytes*/ 17756384ad6SJannik Becher *(__le16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod); 1782865d42cSLarry Finger sz += 2; 1792865d42cSLarry Finger ie += 2; 1802865d42cSLarry Finger /*capability info*/ 1812865d42cSLarry Finger *(u16 *)ie = 0; 18256384ad6SJannik Becher *(__le16 *)ie |= cpu_to_le16(cap_IBSS); 1832865d42cSLarry Finger if (pregistrypriv->preamble == PREAMBLE_SHORT) 18456384ad6SJannik Becher *(__le16 *)ie |= cpu_to_le16(cap_ShortPremble); 1852865d42cSLarry Finger if (pdev_network->Privacy) 18656384ad6SJannik Becher *(__le16 *)ie |= cpu_to_le16(cap_Privacy); 1872865d42cSLarry Finger sz += 2; 1882865d42cSLarry Finger ie += 2; 1892865d42cSLarry Finger /*SSID*/ 1902865d42cSLarry Finger ie = r8712_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, 1912865d42cSLarry Finger pdev_network->Ssid.Ssid, &sz); 1922865d42cSLarry Finger /*supported rates*/ 1937fb539edSJoshua Clayton set_supported_rate(pdev_network->rates, pregistrypriv->wireless_mode); 1947fb539edSJoshua Clayton rateLen = r8712_get_rateset_len(pdev_network->rates); 1952865d42cSLarry Finger if (rateLen > 8) { 1962865d42cSLarry Finger ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_, 8, 1977fb539edSJoshua Clayton pdev_network->rates, &sz); 1982865d42cSLarry Finger ie = r8712_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), 1997fb539edSJoshua Clayton (pdev_network->rates + 8), &sz); 2003bca7cf8SJaya Durga } else { 2012865d42cSLarry Finger ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_, 2027fb539edSJoshua Clayton rateLen, pdev_network->rates, &sz); 2033bca7cf8SJaya Durga } 2042865d42cSLarry Finger /*DS parameter set*/ 2052865d42cSLarry Finger ie = r8712_set_ie(ie, _DSSET_IE_, 1, 2065d04ac54SScott Matheina (u8 *)&pdev_network->Configuration.DSConfig, &sz); 2072865d42cSLarry Finger /*IBSS Parameter Set*/ 2082865d42cSLarry Finger ie = r8712_set_ie(ie, _IBSS_PARA_IE_, 2, 2095d04ac54SScott Matheina (u8 *)&pdev_network->Configuration.ATIMWindow, &sz); 2102865d42cSLarry Finger return sz; 2112865d42cSLarry Finger } 2122865d42cSLarry Finger 2132865d42cSLarry Finger unsigned char *r8712_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit) 2142865d42cSLarry Finger { 2152865d42cSLarry Finger int len; 2162865d42cSLarry Finger u16 val16; 2172865d42cSLarry Finger unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; 2182865d42cSLarry Finger u8 *pbuf = pie; 2192865d42cSLarry Finger 2202865d42cSLarry Finger while (1) { 2212865d42cSLarry Finger pbuf = r8712_get_ie(pbuf, _WPA_IE_ID_, &len, limit); 2222865d42cSLarry Finger if (pbuf) { 2232865d42cSLarry Finger /*check if oui matches...*/ 224d25f658dSParth Sane if (memcmp((pbuf + 2), wpa_oui_type, sizeof(wpa_oui_type))) 2252865d42cSLarry Finger goto check_next_ie; 2262865d42cSLarry Finger /*check version...*/ 2272865d42cSLarry Finger memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16)); 22856384ad6SJannik Becher le16_to_cpus(&val16); 2292865d42cSLarry Finger if (val16 != 0x0001) 2302865d42cSLarry Finger goto check_next_ie; 2312865d42cSLarry Finger *wpa_ie_len = *(pbuf + 1); 2322865d42cSLarry Finger return pbuf; 233e92c3511SNitin Kuppelur } 2342865d42cSLarry Finger *wpa_ie_len = 0; 2352865d42cSLarry Finger return NULL; 2362865d42cSLarry Finger check_next_ie: 2372865d42cSLarry Finger limit = limit - (pbuf - pie) - 2 - len; 2382865d42cSLarry Finger if (limit <= 0) 2392865d42cSLarry Finger break; 2402865d42cSLarry Finger pbuf += (2 + len); 2412865d42cSLarry Finger } 2422865d42cSLarry Finger *wpa_ie_len = 0; 2432865d42cSLarry Finger return NULL; 2442865d42cSLarry Finger } 2452865d42cSLarry Finger 2462865d42cSLarry Finger unsigned char *r8712_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit) 2472865d42cSLarry Finger { 2482865d42cSLarry Finger return r8712_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit); 2492865d42cSLarry Finger } 2502865d42cSLarry Finger 2512865d42cSLarry Finger static int r8712_get_wpa_cipher_suite(u8 *s) 2522865d42cSLarry Finger { 2532865d42cSLarry Finger if (!memcmp(s, (void *)WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN)) 2542865d42cSLarry Finger return WPA_CIPHER_NONE; 2552865d42cSLarry Finger if (!memcmp(s, (void *)WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN)) 2562865d42cSLarry Finger return WPA_CIPHER_WEP40; 2572865d42cSLarry Finger if (!memcmp(s, (void *)WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN)) 2582865d42cSLarry Finger return WPA_CIPHER_TKIP; 2592865d42cSLarry Finger if (!memcmp(s, (void *)WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN)) 2602865d42cSLarry Finger return WPA_CIPHER_CCMP; 2612865d42cSLarry Finger if (!memcmp(s, (void *)WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN)) 2622865d42cSLarry Finger return WPA_CIPHER_WEP104; 2632865d42cSLarry Finger return 0; 2642865d42cSLarry Finger } 2652865d42cSLarry Finger 2662865d42cSLarry Finger static int r8712_get_wpa2_cipher_suite(u8 *s) 2672865d42cSLarry Finger { 2682865d42cSLarry Finger if (!memcmp(s, (void *)RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN)) 2692865d42cSLarry Finger return WPA_CIPHER_NONE; 2702865d42cSLarry Finger if (!memcmp(s, (void *)RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN)) 2712865d42cSLarry Finger return WPA_CIPHER_WEP40; 2722865d42cSLarry Finger if (!memcmp(s, (void *)RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN)) 2732865d42cSLarry Finger return WPA_CIPHER_TKIP; 2742865d42cSLarry Finger if (!memcmp(s, (void *)RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN)) 2752865d42cSLarry Finger return WPA_CIPHER_CCMP; 2762865d42cSLarry Finger if (!memcmp(s, (void *)RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN)) 2772865d42cSLarry Finger return WPA_CIPHER_WEP104; 2782865d42cSLarry Finger return 0; 2792865d42cSLarry Finger } 2802865d42cSLarry Finger 2812865d42cSLarry Finger int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, 2822865d42cSLarry Finger int *pairwise_cipher) 2832865d42cSLarry Finger { 2848ffca9eaSPeter Senna Tschudin int i; 2852865d42cSLarry Finger int left, count; 2862865d42cSLarry Finger u8 *pos; 2872865d42cSLarry Finger 2882865d42cSLarry Finger if (wpa_ie_len <= 0) { 2892865d42cSLarry Finger /* No WPA IE - fail silently */ 2902865d42cSLarry Finger return _FAIL; 2912865d42cSLarry Finger } 29295ee706eSVarsha Rao if ((*wpa_ie != _WPA_IE_ID_) || 29395ee706eSVarsha Rao (*(wpa_ie + 1) != (u8)(wpa_ie_len - 2)) || 29495ee706eSVarsha Rao (memcmp(wpa_ie + 2, (void *)WPA_OUI_TYPE, WPA_SELECTOR_LEN))) 2952865d42cSLarry Finger return _FAIL; 2962865d42cSLarry Finger pos = wpa_ie; 2972865d42cSLarry Finger pos += 8; 2982865d42cSLarry Finger left = wpa_ie_len - 8; 2992865d42cSLarry Finger /*group_cipher*/ 3002865d42cSLarry Finger if (left >= WPA_SELECTOR_LEN) { 3012865d42cSLarry Finger *group_cipher = r8712_get_wpa_cipher_suite(pos); 3022865d42cSLarry Finger pos += WPA_SELECTOR_LEN; 3032865d42cSLarry Finger left -= WPA_SELECTOR_LEN; 304168a2c10SLuis de Bethencourt } else if (left > 0) { 3052865d42cSLarry Finger return _FAIL; 306168a2c10SLuis de Bethencourt } 3072865d42cSLarry Finger /*pairwise_cipher*/ 3082865d42cSLarry Finger if (left >= 2) { 30956384ad6SJannik Becher count = le16_to_cpu(*(__le16 *)pos); 3102865d42cSLarry Finger pos += 2; 3112865d42cSLarry Finger left -= 2; 3122865d42cSLarry Finger if (count == 0 || left < count * WPA_SELECTOR_LEN) 3132865d42cSLarry Finger return _FAIL; 3142865d42cSLarry Finger for (i = 0; i < count; i++) { 3152865d42cSLarry Finger *pairwise_cipher |= r8712_get_wpa_cipher_suite(pos); 3162865d42cSLarry Finger pos += WPA_SELECTOR_LEN; 3172865d42cSLarry Finger left -= WPA_SELECTOR_LEN; 3182865d42cSLarry Finger } 319168a2c10SLuis de Bethencourt } else if (left == 1) { 3202865d42cSLarry Finger return _FAIL; 321168a2c10SLuis de Bethencourt } 3228ffca9eaSPeter Senna Tschudin return _SUCCESS; 3232865d42cSLarry Finger } 3242865d42cSLarry Finger 3252865d42cSLarry Finger int r8712_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, 3262865d42cSLarry Finger int *pairwise_cipher) 3272865d42cSLarry Finger { 3288ffca9eaSPeter Senna Tschudin int i; 3292865d42cSLarry Finger int left, count; 3302865d42cSLarry Finger u8 *pos; 3312865d42cSLarry Finger 3322865d42cSLarry Finger if (rsn_ie_len <= 0) { 3332865d42cSLarry Finger /* No RSN IE - fail silently */ 3342865d42cSLarry Finger return _FAIL; 3352865d42cSLarry Finger } 3364ef2de5aSLuis de Bethencourt if ((*rsn_ie != _WPA2_IE_ID_) || 3374ef2de5aSLuis de Bethencourt (*(rsn_ie + 1) != (u8)(rsn_ie_len - 2))) 3382865d42cSLarry Finger return _FAIL; 3392865d42cSLarry Finger pos = rsn_ie; 3402865d42cSLarry Finger pos += 4; 3412865d42cSLarry Finger left = rsn_ie_len - 4; 3422865d42cSLarry Finger /*group_cipher*/ 3432865d42cSLarry Finger if (left >= RSN_SELECTOR_LEN) { 3442865d42cSLarry Finger *group_cipher = r8712_get_wpa2_cipher_suite(pos); 3452865d42cSLarry Finger pos += RSN_SELECTOR_LEN; 3462865d42cSLarry Finger left -= RSN_SELECTOR_LEN; 347168a2c10SLuis de Bethencourt } else if (left > 0) { 3482865d42cSLarry Finger return _FAIL; 349168a2c10SLuis de Bethencourt } 3502865d42cSLarry Finger /*pairwise_cipher*/ 3512865d42cSLarry Finger if (left >= 2) { 35256384ad6SJannik Becher count = le16_to_cpu(*(__le16 *)pos); 3532865d42cSLarry Finger pos += 2; 3542865d42cSLarry Finger left -= 2; 3552865d42cSLarry Finger if (count == 0 || left < count * RSN_SELECTOR_LEN) 3562865d42cSLarry Finger return _FAIL; 3572865d42cSLarry Finger for (i = 0; i < count; i++) { 3582865d42cSLarry Finger *pairwise_cipher |= r8712_get_wpa2_cipher_suite(pos); 3592865d42cSLarry Finger pos += RSN_SELECTOR_LEN; 3602865d42cSLarry Finger left -= RSN_SELECTOR_LEN; 3612865d42cSLarry Finger } 362168a2c10SLuis de Bethencourt } else if (left == 1) { 3632865d42cSLarry Finger return _FAIL; 364168a2c10SLuis de Bethencourt } 3658ffca9eaSPeter Senna Tschudin return _SUCCESS; 3662865d42cSLarry Finger } 3672865d42cSLarry Finger 3682865d42cSLarry Finger int r8712_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, 3692865d42cSLarry Finger u8 *wpa_ie, u16 *wpa_len) 3702865d42cSLarry Finger { 371e29d3ebcSSudip Mukherjee u8 authmode; 3722865d42cSLarry Finger u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; 3732865d42cSLarry Finger uint cnt; 3742865d42cSLarry Finger 3752865d42cSLarry Finger /*Search required WPA or WPA2 IE and copy to sec_ie[ ]*/ 376bb106dc0SBhaktipriya Shridhar cnt = _TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_; 3772865d42cSLarry Finger while (cnt < in_len) { 3782865d42cSLarry Finger authmode = in_ie[cnt]; 3792865d42cSLarry Finger if ((authmode == _WPA_IE_ID_) && 3802865d42cSLarry Finger (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) { 3812865d42cSLarry Finger memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); 3822865d42cSLarry Finger *wpa_len = in_ie[cnt + 1] + 2; 3832865d42cSLarry Finger cnt += in_ie[cnt + 1] + 2; /*get next */ 3842865d42cSLarry Finger } else { 3852865d42cSLarry Finger if (authmode == _WPA2_IE_ID_) { 3862865d42cSLarry Finger memcpy(rsn_ie, &in_ie[cnt], 3872865d42cSLarry Finger in_ie[cnt + 1] + 2); 3882865d42cSLarry Finger *rsn_len = in_ie[cnt + 1] + 2; 3892865d42cSLarry Finger cnt += in_ie[cnt + 1] + 2; /*get next*/ 390168a2c10SLuis de Bethencourt } else { 3912865d42cSLarry Finger cnt += in_ie[cnt + 1] + 2; /*get next*/ 3922865d42cSLarry Finger } 3932865d42cSLarry Finger } 394168a2c10SLuis de Bethencourt } 3952865d42cSLarry Finger return *rsn_len + *wpa_len; 3962865d42cSLarry Finger } 3972865d42cSLarry Finger 3982865d42cSLarry Finger int r8712_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) 3992865d42cSLarry Finger { 4002865d42cSLarry Finger int match; 4012865d42cSLarry Finger uint cnt; 4022865d42cSLarry Finger u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; 4032865d42cSLarry Finger 4042865d42cSLarry Finger cnt = 12; 4052865d42cSLarry Finger match = false; 4062865d42cSLarry Finger while (cnt < in_len) { 4072865d42cSLarry Finger eid = in_ie[cnt]; 4082865d42cSLarry Finger if ((eid == _WPA_IE_ID_) && 4092865d42cSLarry Finger (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) { 4102865d42cSLarry Finger memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); 4112865d42cSLarry Finger *wps_ielen = in_ie[cnt + 1] + 2; 4122865d42cSLarry Finger cnt += in_ie[cnt + 1] + 2; 4132865d42cSLarry Finger match = true; 4142865d42cSLarry Finger break; 415e92c3511SNitin Kuppelur } 4162865d42cSLarry Finger cnt += in_ie[cnt + 1] + 2; /* goto next */ 4172865d42cSLarry Finger } 4182865d42cSLarry Finger return match; 4192865d42cSLarry Finger } 420