From b8eb4fb26485630a5420618906fcdb71a0080369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Ca=C3=B1uelo=20Navarro?= Date: Wed, 24 Jun 2026 15:38:56 +0200 Subject: [PATCH] src/cyw43_ll: parse RSN/WPA IEs in wifi scans results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a function (cyw43_ll_wifi_parse_ie_auth) to parse the vendor-specific WPA IEs and RSN IEs received during wifi scans. Define a more complete set of security and authentication flags and redefine the CYW43_AUTH_ macros in terms of these new flags. Return the AP security and authentication capabilities as a 32 bit field in cyw43_ev_scan_result_t.auth_mode (previously an 8 bit field). Note that this change may break compatibility with drivers that use the scan feature. Signed-off-by: Ricardo CaƱuelo Navarro --- src/cyw43_ll.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++-- src/cyw43_ll.h | 32 +++++++--- 2 files changed, 182 insertions(+), 14 deletions(-) diff --git a/src/cyw43_ll.c b/src/cyw43_ll.c index dc58df1..6b0c9e4 100644 --- a/src/cyw43_ll.c +++ b/src/cyw43_ll.c @@ -263,6 +263,13 @@ static void cyw43_xxd(size_t len, const uint8_t *buf) { #define DOT11_IE_ID_RSN (48) #define DOT11_IE_ID_VENDOR_SPECIFIC (221) #define WPA_OUI_TYPE1 "\x00\x50\xF2\x01" +#define IEEE_802_11_OUI "\x00\x0F\xAC" +#define IEEE_802_11_OUI_LEN 3 + +// Field offsets for authentication (RSN/WPA) IEs +#define IE_AUTH_GROUP_CIPHER_OUI_OFFSET 4 +#define IE_AUTH_GROUP_CIPHER_OFFSET 7 +#define IE_AUTH_PAIRWISE_CIPHER_COUNT_OFFSET 8 #define SLEEP_MAX (50) @@ -508,21 +515,26 @@ typedef struct _cyw43_scan_result_internal_t { uint16_t capability; uint8_t ssid_len; uint8_t ssid[32]; + uint8_t pad1[1]; uint32_t rateset_count; uint8_t rateset_rates[16]; uint16_t chanspec; uint16_t atim_window; uint8_t dtim_period; + uint8_t pad2[1]; int16_t rssi; int8_t phy_noise; uint8_t n_cap; + uint8_t pad3[2]; uint32_t nbss_cap; uint8_t ctl_ch; + uint8_t pad4[3]; uint32_t reserved32[1]; uint8_t flags; - uint8_t reserved[3]; + uint8_t pad5[3]; uint8_t basic_mcs[16]; uint16_t ie_offset; + uint8_t pad6[2]; uint32_t ie_length; int16_t SNR; } cyw43_scan_result_internal_t; @@ -535,6 +547,148 @@ static inline uint16_t cyw43_be16toh(uint16_t x) { return (x >> 8) | (x << 8); } +/* IEEE 802.11 AKM suites */ +typedef enum +{ + AKM_RESERVED, + AKM_8021X, /* WPA2 enterprise */ + AKM_PSK, /* WPA2 PSK */ + AKM_FT_8021X, /* 802.11r Fast Roaming enterprise */ + AKM_FT_PSK, /* 802.11r Fast Roaming PSK */ + AKM_8021X_SHA256, + AKM_PSK_SHA256, + AKM_TDLS, /* Tunneled Direct Link Setup */ + AKM_SAE_SHA256, + AKM_FT_SAE_SHA256, + AKM_AP_PEER_KEY_SHA256, + AKM_SUITEB_8021X_HMAC_SHA256, + AKM_SUITEB_8021X_HMAC_SHA384, + AKM_SUITEB_FT_8021X_HMAC_SHA384, +} akm_suite_t; + +/* IEEE 802.11 Cipher suites */ +typedef enum +{ + CIPHER_GROUP, /* Use group cipher suite */ + CIPHER_WEP_40, /* WEP-40 */ + CIPHER_TKIP, /* TKIP */ + CIPHER_RESERVED, /* Reserved */ + CIPHER_CCMP_128, /* CCMP-128 - default pairwise and group cipher suite */ + CIPHER_WEP_104, /* WEP-104 - also known as WEP-128 */ + CIPHER_BIP_CMAC_128, /* BIP-CMAC-128 - default management frame cipher suite */ + CIPHER_GROUP_DISALLOWED, /* Group address traffic not allowed */ + CIPHER_GCMP_128, /* GCMP-128 - default for 60 GHz STAs */ + CIPHER_GCMP_256, /* GCMP-256 - introduced for Suite B */ + CIPHER_CCMP_256, /* CCMP-256 - introduced for suite B */ + CIPHER_BIP_GMAC_128, /* BIP-GMAC-128 - introduced for suite B */ + CIPHER_BIP_GMAC_256, /* BIP-GMAC-256 - introduced for suite B */ + CIPHER_BIP_CMAC_256, /* BIP-CMAC-256 - introduced for suite B */ +} cipher_t; + +/* + * Parses an RSN or vendor-specific WPA IE. + * + * Parameters: + * ie: the buffer containing the Information Element. + * wpa: 1 if the IE is a vendor-specific WPA IE, 0 if it's an RSN IE. + * + * Returns the security and authentication capabilities encoded in a + * 32-bit field (see the CYW43_AUTH_ macros), or 0 if it found an error + * parsing the IE. + */ +static uint32_t cyw43_ll_wifi_parse_ie_auth(uint8_t *ie, int wpa) { + uint32_t security = 0; + char *oui; + int pairwise_cipher_cnt; + int akm_cnt; + int idx; + + if (wpa) { + security = WPA_SECURITY; + oui = WPA_OUI_TYPE1; + } else { + oui = IEEE_802_11_OUI; + } + + /* Group cipher suite */ + if (memcmp(&ie[IE_AUTH_GROUP_CIPHER_OUI_OFFSET], oui, IEEE_802_11_OUI_LEN)) { + return 0; + } + switch (ie[IE_AUTH_GROUP_CIPHER_OFFSET]) { + case CIPHER_TKIP: + security |= TKIP_ENABLED; + break; + case CIPHER_CCMP_128: + security |= AES_ENABLED; + break; + default: + CYW43_WARN("Unsupported group cipher %d\n", ie[IE_AUTH_GROUP_CIPHER_OFFSET]); + } + + /* Pairwise cipher suites */ + pairwise_cipher_cnt = *(uint16_t*)(&ie[IE_AUTH_PAIRWISE_CIPHER_COUNT_OFFSET]); + idx = IE_AUTH_PAIRWISE_CIPHER_COUNT_OFFSET + 2; + for (int i = 0; i < pairwise_cipher_cnt; i++) { + if (memcmp(&ie[idx], oui, IEEE_802_11_OUI_LEN)) { + CYW43_WARN("Error parsing management IE: wrong OUI in pairwise cipher\n"); + return 0; + } + idx += IEEE_802_11_OUI_LEN; + switch (ie[idx]) { + case CIPHER_TKIP: + security |= TKIP_ENABLED; + break; + case CIPHER_CCMP_128: + security |= AES_ENABLED; + break; + default: + CYW43_WARN("Unsupported pairwise cipher %d\n", ie[idx]); + } + idx++; + } + + /* AKM suites */ + akm_cnt = *(uint16_t*)(&ie[idx]); + idx += 2; + for (int i = 0; i < akm_cnt; i++) { + if (memcmp(&ie[idx], oui, IEEE_802_11_OUI_LEN)) { + CYW43_WARN("Error parsing management IE: wrong OUI in AKM suite\n"); + return 0; + } + idx += IEEE_802_11_OUI_LEN; + switch (ie[idx]) { + case AKM_PSK: + security |= WPA2_SECURITY; + break; + case AKM_PSK_SHA256: + security |= WPA2_SECURITY | WPA2_SHA256_SECURITY; + break; + case AKM_SAE_SHA256: + security |= WPA3_SECURITY; + break; + case AKM_8021X: + if (wpa) { + security |= ENTERPRISE_ENABLED; + } else { + security |= WPA2_SECURITY | ENTERPRISE_ENABLED; + } + break; + case AKM_FT_8021X: + security |= WPA2_SECURITY | FBT_ENABLED | ENTERPRISE_ENABLED; + break; + case AKM_FT_PSK: + security |= WPA2_SECURITY | FBT_ENABLED; + break; + default: + CYW43_WARN("Unsupported group cipher %d\n", ie_rsn[idx]); + } + idx++; + } + + return security; +} + + static void cyw43_ll_wifi_parse_scan_result(cyw43_async_event_t *ev) { struct _scan_result_t { uint32_t buflen; @@ -572,15 +726,13 @@ static void cyw43_ll_wifi_parse_scan_result(cyw43_async_event_t *ev) { } int security = 0;// OPEN if (ie_rsn != NULL) { - // TODO need to parse the IE to check for TKIP, AES and enterprise modes - security |= 4;// WPA2; + security = cyw43_ll_wifi_parse_ie_auth(ie_rsn, 0); } if (ie_wpa != NULL) { - // TODO need to parse the IE to check for TKIP, AES and enterprise modes - security |= 2;// WPA; + security = cyw43_ll_wifi_parse_ie_auth(ie_wpa, 1); } if (scan_res->bss.capability & DOT11_CAP_PRIVACY) { - security |= 1;// WEP_PSK; + security |= WEP_ENABLED; } ev->u.scan_result.channel &= 0xff; diff --git a/src/cyw43_ll.h b/src/cyw43_ll.h index fe7c68f..fc0bf04 100644 --- a/src/cyw43_ll.h +++ b/src/cyw43_ll.h @@ -161,18 +161,33 @@ #define CYW43_REASON_SUP_DEAUTH (14) // received FC_DEAUTH #define CYW43_REASON_SUP_WPA_PSK_TMO (15) // WPA PSK 4-way handshake timeout +// Security and authentication flags +#define WEP_ENABLED 0x0001 +#define TKIP_ENABLED 0x0002 +#define AES_ENABLED 0x0004 +#define SHARED_ENABLED 0x00008000 +#define WPA_SECURITY 0x00200000 +#define WPA2_SECURITY 0x00400000 +#define WPA2_SHA256_SECURITY 0x00800000 +#define WPA3_SECURITY 0x01000000 +#define ENTERPRISE_ENABLED 0x02000000 +#define WPS_ENABLED 0x10000000 +#define IBSS_ENABLED 0x20000000 +#define FBT_ENABLED 0x40000000 + /** * \name Authorization types * \brief Used when setting up an access point, or connecting to an access point * \anchor CYW43_AUTH_ */ //!\{ -#define CYW43_AUTH_OPEN (0) ///< No authorisation required (open) -#define CYW43_AUTH_WPA_TKIP_PSK (0x00200002) ///< WPA authorisation -#define CYW43_AUTH_WPA2_AES_PSK (0x00400004) ///< WPA2 authorisation (preferred) -#define CYW43_AUTH_WPA2_MIXED_PSK (0x00400006) ///< WPA2/WPA mixed authorisation -#define CYW43_AUTH_WPA3_SAE_AES_PSK (0x01000004) ///< WPA3 AES authorisation -#define CYW43_AUTH_WPA3_WPA2_AES_PSK (0x01400004) ///< WPA2/WPA3 authorisation +#define CYW43_AUTH_OPEN (0) ///< No authorisation required (open) +#define CYW43_AUTH_WEP_PSK (WEP_ENABLED) ///< WEP PSK Security with open authentication +#define CYW43_AUTH_WPA_TKIP_PSK (WPA_SECURITY | TKIP_ENABLED) ///< WPA authorisation +#define CYW43_AUTH_WPA2_AES_PSK (WPA2_SECURITY | AES_ENABLED) ///< WPA2 authorisation (preferred) +#define CYW43_AUTH_WPA2_MIXED_PSK (WPA2_SECURITY | AES_ENABLED | TKIP_ENABLED) ///< WPA2/WPA mixed authorisation +#define CYW43_AUTH_WPA3_SAE_AES_PSK (WPA3_SECURITY | AES_ENABLED) ///< WPA3 AES authorisation +#define CYW43_AUTH_WPA3_WPA2_AES_PSK (WPA3_SECURITY | WPA2_SECURITY | AES_ENABLED) ///< WPA2/WPA3 authorisation //!\} /*! @@ -221,9 +236,10 @@ typedef struct _cyw43_ev_scan_result_t { uint8_t ssid[32]; ///< wlan access point name uint32_t _2[5]; uint16_t channel; ///< wifi channel - uint16_t _3; - uint8_t auth_mode; ///< wifi auth mode \ref CYW43_AUTH_ + uint8_t _3[4]; int16_t rssi; ///< signal strength + uint8_t _4[12]; + uint32_t auth_mode; ///< security and authentication flags } cyw43_ev_scan_result_t; //!\}