139beb93cSSam Leffler /* 239beb93cSSam Leffler * wpa_supplicant - WPA/RSN IE and KDE processing 385732ac8SCy Schubert * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 1239beb93cSSam Leffler #include "wpa.h" 1339beb93cSSam Leffler #include "pmksa_cache.h" 14e28a4053SRui Paulo #include "common/ieee802_11_defs.h" 1539beb93cSSam Leffler #include "wpa_i.h" 1639beb93cSSam Leffler #include "wpa_ie.h" 1739beb93cSSam Leffler 1839beb93cSSam Leffler 1939beb93cSSam Leffler /** 2039beb93cSSam Leffler * wpa_parse_wpa_ie - Parse WPA/RSN IE 2139beb93cSSam Leffler * @wpa_ie: Pointer to WPA or RSN IE 2239beb93cSSam Leffler * @wpa_ie_len: Length of the WPA/RSN IE 2339beb93cSSam Leffler * @data: Pointer to data area for parsing results 2439beb93cSSam Leffler * Returns: 0 on success, -1 on failure 2539beb93cSSam Leffler * 2639beb93cSSam Leffler * Parse the contents of WPA or RSN IE and write the parsed data into data. 2739beb93cSSam Leffler */ 2839beb93cSSam Leffler int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, 2939beb93cSSam Leffler struct wpa_ie_data *data) 3039beb93cSSam Leffler { 3139beb93cSSam Leffler if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) 3239beb93cSSam Leffler return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); 33325151a3SRui Paulo if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC && 34325151a3SRui Paulo wpa_ie[1] >= 4 && WPA_GET_BE32(&wpa_ie[2]) == OSEN_IE_VENDOR_TYPE) 35325151a3SRui Paulo return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); 3639beb93cSSam Leffler else 3739beb93cSSam Leffler return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); 3839beb93cSSam Leffler } 3939beb93cSSam Leffler 4039beb93cSSam Leffler 4139beb93cSSam Leffler static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, 4239beb93cSSam Leffler int pairwise_cipher, int group_cipher, 4339beb93cSSam Leffler int key_mgmt) 4439beb93cSSam Leffler { 4539beb93cSSam Leffler u8 *pos; 4639beb93cSSam Leffler struct wpa_ie_hdr *hdr; 47f05cddf9SRui Paulo u32 suite; 4839beb93cSSam Leffler 4939beb93cSSam Leffler if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + 5039beb93cSSam Leffler 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) 5139beb93cSSam Leffler return -1; 5239beb93cSSam Leffler 5339beb93cSSam Leffler hdr = (struct wpa_ie_hdr *) wpa_ie; 5439beb93cSSam Leffler hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; 5539beb93cSSam Leffler RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); 5639beb93cSSam Leffler WPA_PUT_LE16(hdr->version, WPA_VERSION); 5739beb93cSSam Leffler pos = (u8 *) (hdr + 1); 5839beb93cSSam Leffler 59f05cddf9SRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher); 60f05cddf9SRui Paulo if (suite == 0) { 6139beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 6239beb93cSSam Leffler group_cipher); 6339beb93cSSam Leffler return -1; 6439beb93cSSam Leffler } 65f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, suite); 6639beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 6739beb93cSSam Leffler 6839beb93cSSam Leffler *pos++ = 1; 6939beb93cSSam Leffler *pos++ = 0; 70f05cddf9SRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher); 71f05cddf9SRui Paulo if (suite == 0 || 72f05cddf9SRui Paulo (!wpa_cipher_valid_pairwise(pairwise_cipher) && 73f05cddf9SRui Paulo pairwise_cipher != WPA_CIPHER_NONE)) { 7439beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 7539beb93cSSam Leffler pairwise_cipher); 7639beb93cSSam Leffler return -1; 7739beb93cSSam Leffler } 78f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, suite); 7939beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 8039beb93cSSam Leffler 8139beb93cSSam Leffler *pos++ = 1; 8239beb93cSSam Leffler *pos++ = 0; 8339beb93cSSam Leffler if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 8439beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); 8539beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 8639beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); 8739beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { 8839beb93cSSam Leffler RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); 89f05cddf9SRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { 90f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM); 9139beb93cSSam Leffler } else { 9239beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 9339beb93cSSam Leffler key_mgmt); 9439beb93cSSam Leffler return -1; 9539beb93cSSam Leffler } 9639beb93cSSam Leffler pos += WPA_SELECTOR_LEN; 9739beb93cSSam Leffler 9839beb93cSSam Leffler /* WPA Capabilities; use defaults, so no need to include it */ 9939beb93cSSam Leffler 10039beb93cSSam Leffler hdr->len = (pos - wpa_ie) - 2; 10139beb93cSSam Leffler 10239beb93cSSam Leffler WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); 10339beb93cSSam Leffler 10439beb93cSSam Leffler return pos - wpa_ie; 10539beb93cSSam Leffler } 10639beb93cSSam Leffler 10739beb93cSSam Leffler 108*c1d255d3SCy Schubert u16 rsn_supp_capab(struct wpa_sm *sm) 109*c1d255d3SCy Schubert { 110*c1d255d3SCy Schubert u16 capab = 0; 111*c1d255d3SCy Schubert 112*c1d255d3SCy Schubert if (sm->mfp) 113*c1d255d3SCy Schubert capab |= WPA_CAPABILITY_MFPC; 114*c1d255d3SCy Schubert if (sm->mfp == 2) 115*c1d255d3SCy Schubert capab |= WPA_CAPABILITY_MFPR; 116*c1d255d3SCy Schubert if (sm->ocv) 117*c1d255d3SCy Schubert capab |= WPA_CAPABILITY_OCVC; 118*c1d255d3SCy Schubert if (sm->ext_key_id) 119*c1d255d3SCy Schubert capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST; 120*c1d255d3SCy Schubert 121*c1d255d3SCy Schubert return capab; 122*c1d255d3SCy Schubert } 123*c1d255d3SCy Schubert 124*c1d255d3SCy Schubert 12539beb93cSSam Leffler static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, 12639beb93cSSam Leffler int pairwise_cipher, int group_cipher, 12739beb93cSSam Leffler int key_mgmt, int mgmt_group_cipher, 12839beb93cSSam Leffler struct wpa_sm *sm) 12939beb93cSSam Leffler { 13039beb93cSSam Leffler u8 *pos; 13139beb93cSSam Leffler struct rsn_ie_hdr *hdr; 132f05cddf9SRui Paulo u32 suite; 13339beb93cSSam Leffler 13439beb93cSSam Leffler if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + 13539beb93cSSam Leffler 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + 13639beb93cSSam Leffler (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) { 13739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", 13839beb93cSSam Leffler (unsigned long) rsn_ie_len); 13939beb93cSSam Leffler return -1; 14039beb93cSSam Leffler } 14139beb93cSSam Leffler 14239beb93cSSam Leffler hdr = (struct rsn_ie_hdr *) rsn_ie; 14339beb93cSSam Leffler hdr->elem_id = WLAN_EID_RSN; 14439beb93cSSam Leffler WPA_PUT_LE16(hdr->version, RSN_VERSION); 14539beb93cSSam Leffler pos = (u8 *) (hdr + 1); 14639beb93cSSam Leffler 147f05cddf9SRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); 148f05cddf9SRui Paulo if (suite == 0) { 14939beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 15039beb93cSSam Leffler group_cipher); 15139beb93cSSam Leffler return -1; 15239beb93cSSam Leffler } 153f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, suite); 15439beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 15539beb93cSSam Leffler 15639beb93cSSam Leffler *pos++ = 1; 15739beb93cSSam Leffler *pos++ = 0; 158f05cddf9SRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); 159f05cddf9SRui Paulo if (suite == 0 || 160f05cddf9SRui Paulo (!wpa_cipher_valid_pairwise(pairwise_cipher) && 161f05cddf9SRui Paulo pairwise_cipher != WPA_CIPHER_NONE)) { 16239beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 16339beb93cSSam Leffler pairwise_cipher); 16439beb93cSSam Leffler return -1; 16539beb93cSSam Leffler } 166f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, suite); 16739beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 16839beb93cSSam Leffler 16939beb93cSSam Leffler *pos++ = 1; 17039beb93cSSam Leffler *pos++ = 0; 17139beb93cSSam Leffler if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 17239beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); 17339beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 17439beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); 175f05cddf9SRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { 176f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM); 17739beb93cSSam Leffler #ifdef CONFIG_IEEE80211R 17839beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { 17939beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); 18085732ac8SCy Schubert #ifdef CONFIG_SHA384 18185732ac8SCy Schubert } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) { 18285732ac8SCy Schubert RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384); 18385732ac8SCy Schubert #endif /* CONFIG_SHA384 */ 18439beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { 18539beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); 18639beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */ 18739beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { 18839beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); 18939beb93cSSam Leffler } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { 19039beb93cSSam Leffler RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); 191f05cddf9SRui Paulo #ifdef CONFIG_SAE 192f05cddf9SRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_SAE) { 193f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); 194f05cddf9SRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) { 195f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); 196f05cddf9SRui Paulo #endif /* CONFIG_SAE */ 1975b9c547cSRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { 1985b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192); 1995b9c547cSRui Paulo } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) { 2005b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B); 20185732ac8SCy Schubert #ifdef CONFIG_FILS 20285732ac8SCy Schubert } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256) { 20385732ac8SCy Schubert RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256); 20485732ac8SCy Schubert } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384) { 20585732ac8SCy Schubert RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384); 20685732ac8SCy Schubert #ifdef CONFIG_IEEE80211R 20785732ac8SCy Schubert } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) { 20885732ac8SCy Schubert RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256); 20985732ac8SCy Schubert } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) { 21085732ac8SCy Schubert RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384); 21185732ac8SCy Schubert #endif /* CONFIG_IEEE80211R */ 21285732ac8SCy Schubert #endif /* CONFIG_FILS */ 21385732ac8SCy Schubert #ifdef CONFIG_OWE 21485732ac8SCy Schubert } else if (key_mgmt & WPA_KEY_MGMT_OWE) { 21585732ac8SCy Schubert RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE); 21685732ac8SCy Schubert #endif /* CONFIG_OWE */ 21785732ac8SCy Schubert #ifdef CONFIG_DPP 21885732ac8SCy Schubert } else if (key_mgmt & WPA_KEY_MGMT_DPP) { 21985732ac8SCy Schubert RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP); 22085732ac8SCy Schubert #endif /* CONFIG_DPP */ 22185732ac8SCy Schubert #ifdef CONFIG_HS20 22285732ac8SCy Schubert } else if (key_mgmt & WPA_KEY_MGMT_OSEN) { 22385732ac8SCy Schubert RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN); 22485732ac8SCy Schubert #endif /* CONFIG_HS20 */ 22539beb93cSSam Leffler } else { 22639beb93cSSam Leffler wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 22739beb93cSSam Leffler key_mgmt); 22839beb93cSSam Leffler return -1; 22939beb93cSSam Leffler } 23039beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 23139beb93cSSam Leffler 23239beb93cSSam Leffler /* RSN Capabilities */ 233*c1d255d3SCy Schubert WPA_PUT_LE16(pos, rsn_supp_capab(sm)); 23439beb93cSSam Leffler pos += 2; 23539beb93cSSam Leffler 23639beb93cSSam Leffler if (sm->cur_pmksa) { 23739beb93cSSam Leffler /* PMKID Count (2 octets, little endian) */ 23839beb93cSSam Leffler *pos++ = 1; 23939beb93cSSam Leffler *pos++ = 0; 24039beb93cSSam Leffler /* PMKID */ 24139beb93cSSam Leffler os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); 24239beb93cSSam Leffler pos += PMKID_LEN; 24339beb93cSSam Leffler } 24439beb93cSSam Leffler 2455b9c547cSRui Paulo if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) { 24639beb93cSSam Leffler if (!sm->cur_pmksa) { 24739beb93cSSam Leffler /* PMKID Count */ 24839beb93cSSam Leffler WPA_PUT_LE16(pos, 0); 24939beb93cSSam Leffler pos += 2; 25039beb93cSSam Leffler } 25139beb93cSSam Leffler 25239beb93cSSam Leffler /* Management Group Cipher Suite */ 2535b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, 2545b9c547cSRui Paulo mgmt_group_cipher)); 25539beb93cSSam Leffler pos += RSN_SELECTOR_LEN; 25639beb93cSSam Leffler } 25739beb93cSSam Leffler 25839beb93cSSam Leffler hdr->len = (pos - rsn_ie) - 2; 25939beb93cSSam Leffler 26039beb93cSSam Leffler WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); 26139beb93cSSam Leffler 26239beb93cSSam Leffler return pos - rsn_ie; 26339beb93cSSam Leffler } 26439beb93cSSam Leffler 26539beb93cSSam Leffler 2665b9c547cSRui Paulo #ifdef CONFIG_HS20 2675b9c547cSRui Paulo static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len, 2685b9c547cSRui Paulo int pairwise_cipher, int group_cipher, 2695b9c547cSRui Paulo int key_mgmt) 2705b9c547cSRui Paulo { 2715b9c547cSRui Paulo u8 *pos, *len; 2725b9c547cSRui Paulo u32 suite; 2735b9c547cSRui Paulo 2745b9c547cSRui Paulo if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN + 2755b9c547cSRui Paulo 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN) 2765b9c547cSRui Paulo return -1; 2775b9c547cSRui Paulo 2785b9c547cSRui Paulo pos = wpa_ie; 2795b9c547cSRui Paulo *pos++ = WLAN_EID_VENDOR_SPECIFIC; 2805b9c547cSRui Paulo len = pos++; /* to be filled */ 2815b9c547cSRui Paulo WPA_PUT_BE24(pos, OUI_WFA); 2825b9c547cSRui Paulo pos += 3; 2835b9c547cSRui Paulo *pos++ = HS20_OSEN_OUI_TYPE; 2845b9c547cSRui Paulo 2855b9c547cSRui Paulo /* Group Data Cipher Suite */ 2865b9c547cSRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); 2875b9c547cSRui Paulo if (suite == 0) { 2885b9c547cSRui Paulo wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 2895b9c547cSRui Paulo group_cipher); 2905b9c547cSRui Paulo return -1; 2915b9c547cSRui Paulo } 2925b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, suite); 2935b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 2945b9c547cSRui Paulo 2955b9c547cSRui Paulo /* Pairwise Cipher Suite Count and List */ 2965b9c547cSRui Paulo WPA_PUT_LE16(pos, 1); 2975b9c547cSRui Paulo pos += 2; 2985b9c547cSRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); 2995b9c547cSRui Paulo if (suite == 0 || 3005b9c547cSRui Paulo (!wpa_cipher_valid_pairwise(pairwise_cipher) && 3015b9c547cSRui Paulo pairwise_cipher != WPA_CIPHER_NONE)) { 3025b9c547cSRui Paulo wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 3035b9c547cSRui Paulo pairwise_cipher); 3045b9c547cSRui Paulo return -1; 3055b9c547cSRui Paulo } 3065b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, suite); 3075b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 3085b9c547cSRui Paulo 3095b9c547cSRui Paulo /* AKM Suite Count and List */ 3105b9c547cSRui Paulo WPA_PUT_LE16(pos, 1); 3115b9c547cSRui Paulo pos += 2; 3125b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN); 3135b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 3145b9c547cSRui Paulo 3155b9c547cSRui Paulo *len = pos - len - 1; 3165b9c547cSRui Paulo 3175b9c547cSRui Paulo WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); 3185b9c547cSRui Paulo 3195b9c547cSRui Paulo return pos - wpa_ie; 3205b9c547cSRui Paulo } 3215b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 3225b9c547cSRui Paulo 3235b9c547cSRui Paulo 32439beb93cSSam Leffler /** 32539beb93cSSam Leffler * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy 32639beb93cSSam Leffler * @sm: Pointer to WPA state machine data from wpa_sm_init() 32739beb93cSSam Leffler * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE 32839beb93cSSam Leffler * @wpa_ie_len: Maximum length of the generated WPA/RSN IE 32939beb93cSSam Leffler * Returns: Length of the generated WPA/RSN IE or -1 on failure 33039beb93cSSam Leffler */ 33139beb93cSSam Leffler int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) 33239beb93cSSam Leffler { 33339beb93cSSam Leffler if (sm->proto == WPA_PROTO_RSN) 33439beb93cSSam Leffler return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, 33539beb93cSSam Leffler sm->pairwise_cipher, 33639beb93cSSam Leffler sm->group_cipher, 33739beb93cSSam Leffler sm->key_mgmt, sm->mgmt_group_cipher, 33839beb93cSSam Leffler sm); 3395b9c547cSRui Paulo #ifdef CONFIG_HS20 3405b9c547cSRui Paulo else if (sm->proto == WPA_PROTO_OSEN) 3415b9c547cSRui Paulo return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len, 3425b9c547cSRui Paulo sm->pairwise_cipher, 3435b9c547cSRui Paulo sm->group_cipher, 3445b9c547cSRui Paulo sm->key_mgmt); 3455b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 34639beb93cSSam Leffler else 34739beb93cSSam Leffler return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, 34839beb93cSSam Leffler sm->pairwise_cipher, 34939beb93cSSam Leffler sm->group_cipher, 35039beb93cSSam Leffler sm->key_mgmt); 35139beb93cSSam Leffler } 35239beb93cSSam Leffler 35339beb93cSSam Leffler 354*c1d255d3SCy Schubert int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len) 3555b9c547cSRui Paulo { 356*c1d255d3SCy Schubert u8 *pos = rsnxe; 357*c1d255d3SCy Schubert u16 capab = 0; 358*c1d255d3SCy Schubert size_t flen; 3595b9c547cSRui Paulo 360*c1d255d3SCy Schubert if (wpa_key_mgmt_sae(sm->key_mgmt) && 361*c1d255d3SCy Schubert (sm->sae_pwe == 1 || sm->sae_pwe == 2 || sm->sae_pk)) { 362*c1d255d3SCy Schubert capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); 363*c1d255d3SCy Schubert #ifdef CONFIG_SAE_PK 364*c1d255d3SCy Schubert if (sm->sae_pk) 365*c1d255d3SCy Schubert capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK); 366*c1d255d3SCy Schubert #endif /* CONFIG_SAE_PK */ 3675b9c547cSRui Paulo } 3685b9c547cSRui Paulo 369*c1d255d3SCy Schubert if (sm->secure_ltf) 370*c1d255d3SCy Schubert capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF); 371*c1d255d3SCy Schubert if (sm->secure_rtt) 372*c1d255d3SCy Schubert capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT); 373*c1d255d3SCy Schubert if (sm->prot_range_neg) 374*c1d255d3SCy Schubert capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG); 3755b9c547cSRui Paulo 376*c1d255d3SCy Schubert flen = (capab & 0xff00) ? 2 : 1; 377*c1d255d3SCy Schubert if (!capab) 378*c1d255d3SCy Schubert return 0; /* no supported extended RSN capabilities */ 379*c1d255d3SCy Schubert if (rsnxe_len < 2 + flen) 380*c1d255d3SCy Schubert return -1; 381*c1d255d3SCy Schubert capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */ 3825b9c547cSRui Paulo 383*c1d255d3SCy Schubert *pos++ = WLAN_EID_RSNX; 384*c1d255d3SCy Schubert *pos++ = flen; 385*c1d255d3SCy Schubert *pos++ = capab & 0x00ff; 386*c1d255d3SCy Schubert capab >>= 8; 387*c1d255d3SCy Schubert if (capab) 388*c1d255d3SCy Schubert *pos++ = capab; 38939beb93cSSam Leffler 390*c1d255d3SCy Schubert return pos - rsnxe; 39139beb93cSSam Leffler } 392