From 7a06b7db286805bd71a91a855184c292a0692b1a Mon Sep 17 00:00:00 2001 From: yinqingzhao Date: Tue, 16 Jun 2026 11:14:41 +0800 Subject: [PATCH 01/27] fix(wifi): fix cache access error in wifi interrupt with psram enabled --- components/esp_coex/esp32/esp_coex_adapter.c | 2 +- components/esp_coex/esp32c5/esp_coex_adapter.c | 2 +- components/esp_coex/esp32c61/esp_coex_adapter.c | 2 +- components/esp_coex/esp32h4/esp_coex_adapter.c | 2 +- components/esp_coex/esp32s31/esp_coex_adapter.c | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/esp_coex/esp32/esp_coex_adapter.c b/components/esp_coex/esp32/esp_coex_adapter.c index fbd93f6a6ad..65c1fa40021 100644 --- a/components/esp_coex/esp32/esp_coex_adapter.c +++ b/components/esp_coex/esp32/esp_coex_adapter.c @@ -46,7 +46,7 @@ void * esp_coex_common_spin_lock_create_wrapper(void) void *mux = heap_caps_malloc(sizeof(portMUX_TYPE), MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL); if (mux) { - memcpy(mux,&tmp,sizeof(portMUX_TYPE)); + memcpy(mux, &tmp, sizeof(portMUX_TYPE)); return mux; } return NULL; diff --git a/components/esp_coex/esp32c5/esp_coex_adapter.c b/components/esp_coex/esp32c5/esp_coex_adapter.c index 8588b7348d1..48b871c8a44 100644 --- a/components/esp_coex/esp32c5/esp_coex_adapter.c +++ b/components/esp_coex/esp32c5/esp_coex_adapter.c @@ -39,7 +39,7 @@ bool IRAM_ATTR esp_coex_common_env_is_chip_wrapper(void) void *esp_coex_common_spin_lock_create_wrapper(void) { portMUX_TYPE tmp = portMUX_INITIALIZER_UNLOCKED; - void *mux = malloc(sizeof(portMUX_TYPE)); + void *mux = heap_caps_malloc(sizeof(portMUX_TYPE), MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL); if (mux) { memcpy(mux, &tmp, sizeof(portMUX_TYPE)); diff --git a/components/esp_coex/esp32c61/esp_coex_adapter.c b/components/esp_coex/esp32c61/esp_coex_adapter.c index 059160f7bab..2778940239d 100644 --- a/components/esp_coex/esp32c61/esp_coex_adapter.c +++ b/components/esp_coex/esp32c61/esp_coex_adapter.c @@ -40,7 +40,7 @@ bool IRAM_ATTR esp_coex_common_env_is_chip_wrapper(void) void *esp_coex_common_spin_lock_create_wrapper(void) { portMUX_TYPE tmp = portMUX_INITIALIZER_UNLOCKED; - void *mux = malloc(sizeof(portMUX_TYPE)); + void *mux = heap_caps_malloc(sizeof(portMUX_TYPE), MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL); if (mux) { memcpy(mux, &tmp, sizeof(portMUX_TYPE)); diff --git a/components/esp_coex/esp32h4/esp_coex_adapter.c b/components/esp_coex/esp32h4/esp_coex_adapter.c index f9592d2624b..49bb8130669 100644 --- a/components/esp_coex/esp32h4/esp_coex_adapter.c +++ b/components/esp_coex/esp32h4/esp_coex_adapter.c @@ -40,7 +40,7 @@ bool IRAM_ATTR esp_coex_common_env_is_chip_wrapper(void) void *esp_coex_common_spin_lock_create_wrapper(void) { portMUX_TYPE tmp = portMUX_INITIALIZER_UNLOCKED; - void *mux = malloc(sizeof(portMUX_TYPE)); + void *mux = heap_caps_malloc(sizeof(portMUX_TYPE), MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL); if (mux) { memcpy(mux, &tmp, sizeof(portMUX_TYPE)); diff --git a/components/esp_coex/esp32s31/esp_coex_adapter.c b/components/esp_coex/esp32s31/esp_coex_adapter.c index 858c8714c3c..ec8eddb75cd 100644 --- a/components/esp_coex/esp32s31/esp_coex_adapter.c +++ b/components/esp_coex/esp32s31/esp_coex_adapter.c @@ -40,10 +40,10 @@ bool IRAM_ATTR esp_coex_common_env_is_chip_wrapper(void) void *esp_coex_common_spin_lock_create_wrapper(void) { portMUX_TYPE tmp = portMUX_INITIALIZER_UNLOCKED; - void *mux = malloc(sizeof(portMUX_TYPE)); + void *mux = heap_caps_malloc(sizeof(portMUX_TYPE), MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL); if (mux) { - memcpy(mux, &tmp, sizeof(portMUX_TYPE)); + memcpy(mux,&tmp,sizeof(portMUX_TYPE)); return mux; } return NULL; From 09589e3425069ad5e92ff31edf7dd2246fb26152 Mon Sep 17 00:00:00 2001 From: yinqingzhao Date: Mon, 15 Jun 2026 16:22:16 +0800 Subject: [PATCH 02/27] fix(wifi): fix still performing active scan on unsupported channels in auto policy --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index e54196faa03..1747224af60 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit e54196faa039e7836847a2920da749e4abbb3d96 +Subproject commit 1747224af600785e11ffe41b1df4201be7632464 From 84beb7abcd6d9d50dc00aeecc571262d58edb82c Mon Sep 17 00:00:00 2001 From: muhaidong Date: Mon, 22 Jun 2026 17:50:50 +0800 Subject: [PATCH 03/27] fix(wifi): post disconnect event after disassociation tx callback --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 1747224af60..2fee84b9b73 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 1747224af600785e11ffe41b1df4201be7632464 +Subproject commit 2fee84b9b73d88b0ff713e78b1b9d759fd8d37fc From a1ab8394ccf710543b650dd4c7567093b3b54862 Mon Sep 17 00:00:00 2001 From: Sajia Date: Wed, 3 Jun 2026 12:00:13 +0530 Subject: [PATCH 04/27] feat(ftm): Update ftm calibration values esp32s31 --- .../esp_private/ftm_calibration_data.h | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/components/esp_wifi/include/esp_private/ftm_calibration_data.h b/components/esp_wifi/include/esp_private/ftm_calibration_data.h index 53297fd4f81..e08f099d553 100644 --- a/components/esp_wifi/include/esp_private/ftm_calibration_data.h +++ b/components/esp_wifi/include/esp_private/ftm_calibration_data.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -230,35 +230,35 @@ #elif CONFIG_IDF_TARGET_ESP32S31 //TODO: Dummy values, remove or update when FTM loopback and auto-calibration is verified // 20 MHz FTM in 20MHz PHY - Initiator Values -#define EST_PHY_INIT_FTM_COMP_20_20U_MHZ 859 // Connected Initiator in 20MHz (Ch 1) using 20MHz FTM -#define EST_PHY_INIT_FTM_COMP_20_20U_MHZ_DIS 859 // Disconnected Initiator in 20MHz (Ch 1) using 20MHz FTM -#define EST_PHY_INIT_FTM_COMP_20_20D_MHZ 869 // Connected Initiator in 20MHz (Ch 11) using 20MHz FTM -#define EST_PHY_INIT_FTM_COMP_20_20D_MHZ_DIS 869 // Disconnected Initiator in 20MHz (Ch 11) using 20MHz FTM +#define EST_PHY_INIT_FTM_COMP_20_20U_MHZ 437 // Connected Initiator in 20MHz (Ch 1) using 20MHz FTM +#define EST_PHY_INIT_FTM_COMP_20_20U_MHZ_DIS 433 // Disconnected Initiator in 20MHz (Ch 1) using 20MHz FTM +#define EST_PHY_INIT_FTM_COMP_20_20D_MHZ 443 // Connected Initiator in 20MHz (Ch 11) using 20MHz FTM +#define EST_PHY_INIT_FTM_COMP_20_20D_MHZ_DIS 442 // Disconnected Initiator in 20MHz (Ch 11) using 20MHz FTM // 20 MHz FTM in 20MHz PHY - Responder Values -#define EST_PHY_RESP_FTM_COMP_20_20U_MHZ 867 // Connected Responder in 20MHz (Ch 1) using 20MHz FTM -#define EST_PHY_RESP_FTM_COMP_20_20U_MHZ_DIS 867 // Disconnected Responder in 20MHz (Ch 1) using 20MHz FTM -#define EST_PHY_RESP_FTM_COMP_20_20D_MHZ 857 // Connected Responder in 20MHz (Ch 11) using 20MHz FTM -#define EST_PHY_RESP_FTM_COMP_20_20D_MHZ_DIS 857 // Disconnected Responder in 20MHz (Ch 11) using 20MHz FTM +#define EST_PHY_RESP_FTM_COMP_20_20U_MHZ 426 // Connected Responder in 20MHz (Ch 1) using 20MHz FTM +#define EST_PHY_RESP_FTM_COMP_20_20U_MHZ_DIS 429 // Disconnected Responder in 20MHz (Ch 1) using 20MHz FTM +#define EST_PHY_RESP_FTM_COMP_20_20D_MHZ 420 // Connected Responder in 20MHz (Ch 11) using 20MHz FTM +#define EST_PHY_RESP_FTM_COMP_20_20D_MHZ_DIS 421 // Disconnected Responder in 20MHz (Ch 11) using 20MHz FTM // 20 MHz FTM in 40MHz PHY - Initiator Values -#define EST_PHY_INIT_FTM_COMP_20_40U_MHZ 746 // Connected Initiator in 40MHz (Ch 1) using 20MHz FTM -#define EST_PHY_INIT_FTM_COMP_20_40U_MHZ_DIS 744 // Disconnected Initiator in 40MHz (Ch 1) using 20MHz FTM -#define EST_PHY_INIT_FTM_COMP_20_40D_MHZ 758 // Connected Initiator in 40MHz (Ch 11) using 20MHz FTM -#define EST_PHY_INIT_FTM_COMP_20_40D_MHZ_DIS 755 // Disconnected Initiator in 40MHz (Ch 11) using 20MHz FTM +#define EST_PHY_INIT_FTM_COMP_20_40U_MHZ 462 // Connected Initiator in 40MHz (Ch 1) using 20MHz FTM +#define EST_PHY_INIT_FTM_COMP_20_40U_MHZ_DIS 433 // Disconnected Initiator in 40MHz (Ch 1) using 20MHz FTM +#define EST_PHY_INIT_FTM_COMP_20_40D_MHZ 438 // Connected Initiator in 40MHz (Ch 11) using 20MHz FTM +#define EST_PHY_INIT_FTM_COMP_20_40D_MHZ_DIS 442 // Disconnected Initiator in 40MHz (Ch 11) using 20MHz FTM // 20 MHz FTM in 40MHz PHY - Responder Values -#define EST_PHY_RESP_FTM_COMP_20_40U_MHZ 754 // Connected Responder in 40MHz (Ch 1) using 20MHz FTM -#define EST_PHY_RESP_FTM_COMP_20_40U_MHZ_DIS 753 // Disconnected Responder in 40MHz (Ch 1) using 20MHz FTM -#define EST_PHY_RESP_FTM_COMP_20_40D_MHZ 744 // Connected Responder in 40MHz (Ch 11) using 20MHz FTM -#define EST_PHY_RESP_FTM_COMP_20_40D_MHZ_DIS 744 // Disconnected Responder in 40MHz (Ch 11) using 20MHz FTM +#define EST_PHY_RESP_FTM_COMP_20_40U_MHZ 425 // Connected Responder in 40MHz (Ch 1) using 20MHz FTM +#define EST_PHY_RESP_FTM_COMP_20_40U_MHZ_DIS 430 // Disconnected Responder in 40MHz (Ch 1) using 20MHz FTM +#define EST_PHY_RESP_FTM_COMP_20_40D_MHZ 420 // Connected Responder in 40MHz (Ch 11) using 20MHz FTM +#define EST_PHY_RESP_FTM_COMP_20_40D_MHZ_DIS 420 // Disconnected Responder in 40MHz (Ch 11) using 20MHz FTM // 40 MHz FTM in 40MHz PHY - Initiator Values -#define EST_PHY_INIT_FTM_COMP_40_40U_MHZ 931 // Connected Initiator in 40MHz (Ch 1) using 40MHz FTM -#define EST_PHY_INIT_FTM_COMP_40_40U_MHZ_DIS 931 // Disconnected Initiator in 40MHz (Ch 1) using 40MHz FTM -#define EST_PHY_INIT_FTM_COMP_40_40D_MHZ 931 // Connected Initiator in 40MHz (Ch 11) using 40MHz FTM -#define EST_PHY_INIT_FTM_COMP_40_40D_MHZ_DIS 931 // Disconnected Initiator in 40MHz (Ch 11) using 40MHz FTM +#define EST_PHY_INIT_FTM_COMP_40_40U_MHZ 237 // Connected Initiator in 40MHz (Ch 1) using 40MHz FTM +#define EST_PHY_INIT_FTM_COMP_40_40U_MHZ_DIS 237 // Disconnected Initiator in 40MHz (Ch 1) using 40MHz FTM +#define EST_PHY_INIT_FTM_COMP_40_40D_MHZ 234 // Connected Initiator in 40MHz (Ch 11) using 40MHz FTM +#define EST_PHY_INIT_FTM_COMP_40_40D_MHZ_DIS 234 // Disconnected Initiator in 40MHz (Ch 11) using 40MHz FTM // 40 MHz FTM in 40MHz PHY - Responder Values -#define EST_PHY_RESP_FTM_COMP_40_40U_MHZ 566 // Connected Responder in 40MHz (Ch 1) using 40MHz FTM -#define EST_PHY_RESP_FTM_COMP_40_40U_MHZ_DIS 566 // Disconnected Responder in 40MHz (Ch 1) using 40MHz FTM -#define EST_PHY_RESP_FTM_COMP_40_40D_MHZ 567 // Connected Responder in 40MHz (Ch 11) using 40MHz FTM -#define EST_PHY_RESP_FTM_COMP_40_40D_MHZ_DIS 567 // Disconnected Responder in 40MHz (Ch 11) using 40MHz FTM +#define EST_PHY_RESP_FTM_COMP_40_40U_MHZ 626 // Connected Responder in 40MHz (Ch 1) using 40MHz FTM +#define EST_PHY_RESP_FTM_COMP_40_40U_MHZ_DIS 626 // Disconnected Responder in 40MHz (Ch 1) using 40MHz FTM +#define EST_PHY_RESP_FTM_COMP_40_40D_MHZ 629 // Connected Responder in 40MHz (Ch 11) using 40MHz FTM +#define EST_PHY_RESP_FTM_COMP_40_40D_MHZ_DIS 629 // Disconnected Responder in 40MHz (Ch 11) using 40MHz FTM #endif /********************************************** 5 GHz Values *******************************************************/ From d7ac95f709de1d84dd3c2ef6f55f4ded38428a10 Mon Sep 17 00:00:00 2001 From: muhaidong Date: Wed, 3 Jun 2026 10:52:43 +0800 Subject: [PATCH 05/27] fix(coex): remove unsupported external coex soc caps --- components/soc/esp32c2/include/soc/Kconfig.soc_caps.in | 4 ---- components/soc/esp32c2/include/soc/soc_caps.h | 1 - components/soc/esp32c3/include/soc/Kconfig.soc_caps.in | 8 -------- components/soc/esp32c3/include/soc/soc_caps.h | 2 -- components/soc/esp32c5/include/soc/Kconfig.soc_caps.in | 4 ---- components/soc/esp32c5/include/soc/soc_caps.h | 1 - components/soc/esp32c6/include/soc/Kconfig.soc_caps.in | 4 ---- components/soc/esp32c6/include/soc/soc_caps.h | 1 - components/soc/esp32c61/include/soc/Kconfig.soc_caps.in | 4 ---- components/soc/esp32c61/include/soc/soc_caps.h | 1 - components/soc/esp32h2/include/soc/Kconfig.soc_caps.in | 4 ---- components/soc/esp32h2/include/soc/soc_caps.h | 1 - components/soc/esp32h21/include/soc/Kconfig.soc_caps.in | 4 ---- components/soc/esp32h21/include/soc/soc_caps.h | 1 - components/soc/esp32h4/include/soc/Kconfig.soc_caps.in | 4 ---- components/soc/esp32h4/include/soc/soc_caps.h | 1 - components/soc/esp32s2/include/soc/Kconfig.soc_caps.in | 4 ---- components/soc/esp32s2/include/soc/soc_caps.h | 1 - components/soc/esp32s3/include/soc/Kconfig.soc_caps.in | 4 ---- components/soc/esp32s3/include/soc/soc_caps.h | 1 - 20 files changed, 55 deletions(-) diff --git a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in index 83ce987cea9..118f6a535db 100644 --- a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in @@ -599,10 +599,6 @@ config SOC_EXTERNAL_COEX_ADVANCE bool default y -config SOC_EXTERNAL_COEX_LEADER_TX_LINE - bool - default n - config SOC_PHY_DIG_REGS_MEM_SIZE int default 21 diff --git a/components/soc/esp32c2/include/soc/soc_caps.h b/components/soc/esp32c2/include/soc/soc_caps.h index 943d5f27948..9cc0ac01d98 100644 --- a/components/soc/esp32c2/include/soc/soc_caps.h +++ b/components/soc/esp32c2/include/soc/soc_caps.h @@ -275,7 +275,6 @@ /*-------------------------- EXTERNAL COEXISTENCE CAPS -------------------------------------*/ #define SOC_EXTERNAL_COEX_ADVANCE (1) /*!< HARDWARE ADVANCED EXTERNAL COEXISTENCE CAPS */ -#define SOC_EXTERNAL_COEX_LEADER_TX_LINE (0) /*!< EXTERNAL COEXISTENCE TX LINE CAPS */ /*--------------- PHY REGISTER AND MEMORY SIZE CAPS --------------------------*/ #define SOC_PHY_DIG_REGS_MEM_SIZE (21*4) diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index a825a03208b..8329fa213c6 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -811,14 +811,6 @@ config SOC_COEX_HW_PTI bool default y -config SOC_EXTERNAL_COEX_ADVANCE - bool - default n - -config SOC_EXTERNAL_COEX_LEADER_TX_LINE - bool - default n - config SOC_PHY_DIG_REGS_MEM_SIZE int default 21 diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index ef9c55eb48d..95f472f90e6 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -361,8 +361,6 @@ #define SOC_COEX_HW_PTI (1) /*-------------------------- EXTERNAL COEXISTENCE CAPS -------------------------------------*/ -#define SOC_EXTERNAL_COEX_ADVANCE (0) /*!< HARDWARE ADVANCED EXTERNAL COEXISTENCE CAPS */ -#define SOC_EXTERNAL_COEX_LEADER_TX_LINE (0) /*!< EXTERNAL COEXISTENCE TX LINE CAPS */ /*--------------- PHY REGISTER AND MEMORY SIZE CAPS --------------------------*/ #define SOC_PHY_DIG_REGS_MEM_SIZE (21*4) diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 9e9766922f7..81687faedcf 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -1335,10 +1335,6 @@ config SOC_EXTERNAL_COEX_ADVANCE bool default y -config SOC_EXTERNAL_COEX_LEADER_TX_LINE - bool - default n - config SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH int default 12 diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 0a88b3f2cd3..be85b0921ce 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -541,7 +541,6 @@ /*-------------------------- EXTERNAL COEXISTENCE CAPS -------------------------------------*/ #define SOC_EXTERNAL_COEX_ADVANCE (1) /*!< HARDWARE EXTERNAL COEXISTENCE CAPS */ -#define SOC_EXTERNAL_COEX_LEADER_TX_LINE (0) /*!< EXTERNAL COEXISTENCE TX LINE CAPS */ /*--------------- PHY REGISTER AND MEMORY SIZE CAPS --------------------------*/ // #define SOC_PHY_DIG_REGS_MEM_SIZE (21*4) diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 9c6d7259615..e031cfeb211 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1071,10 +1071,6 @@ config SOC_EXTERNAL_COEX_ADVANCE bool default y -config SOC_EXTERNAL_COEX_LEADER_TX_LINE - bool - default n - config SOC_PHY_DIG_REGS_MEM_SIZE int default 21 diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 4144853696f..4736fd8ff30 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -442,7 +442,6 @@ /*-------------------------- EXTERNAL COEXISTENCE CAPS -------------------------------------*/ #define SOC_EXTERNAL_COEX_ADVANCE (1) /*!< HARDWARE ADVANCED EXTERNAL COEXISTENCE CAPS */ -#define SOC_EXTERNAL_COEX_LEADER_TX_LINE (0) /*!< EXTERNAL COEXISTENCE TX LINE CAPS */ /*--------------- PHY REGISTER AND MEMORY SIZE CAPS --------------------------*/ #define SOC_PHY_DIG_REGS_MEM_SIZE (21*4) diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index 4750a131bd0..5fb1f9e222f 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -983,10 +983,6 @@ config SOC_EXTERNAL_COEX_ADVANCE bool default y -config SOC_EXTERNAL_COEX_LEADER_TX_LINE - bool - default n - config SOC_PHY_DIG_REGS_MEM_SIZE int default 21 diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index aedc36add10..705a36e07b6 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -411,7 +411,6 @@ /*-------------------------- EXTERNAL COEXISTENCE CAPS -------------------------------------*/ #define SOC_EXTERNAL_COEX_ADVANCE (1) /*!< HARDWARE ADVANCED EXTERNAL COEXISTENCE CAPS */ -#define SOC_EXTERNAL_COEX_LEADER_TX_LINE (0) /*!< EXTERNAL COEXISTENCE TX LINE CAPS */ /*--------------- PHY REGISTER AND MEMORY SIZE CAPS --------------------------*/ #define SOC_PHY_DIG_REGS_MEM_SIZE (21*4) diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 51b7d0f2f8a..36e7b09e47f 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -1079,10 +1079,6 @@ config SOC_EXTERNAL_COEX_ADVANCE bool default y -config SOC_EXTERNAL_COEX_LEADER_TX_LINE - bool - default n - config SOC_PHY_DIG_REGS_MEM_SIZE int default 21 diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index e25952bae16..ba4f0d68352 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -469,7 +469,6 @@ /*-------------------------- EXTERNAL COEXISTENCE CAPS -------------------------------------*/ #define SOC_EXTERNAL_COEX_ADVANCE (1) /*!< HARDWARE ADVANCED EXTERNAL COEXISTENCE CAPS */ -#define SOC_EXTERNAL_COEX_LEADER_TX_LINE (0) /*!< EXTERNAL COEXISTENCE TX LINE CAPS */ /*--------------- PHY REGISTER AND MEMORY SIZE CAPS --------------------------*/ #define SOC_PHY_DIG_REGS_MEM_SIZE (21*4) diff --git a/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in index b71665140b1..c19b2c8e0fd 100644 --- a/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in @@ -951,10 +951,6 @@ config SOC_EXTERNAL_COEX_ADVANCE bool default y -config SOC_EXTERNAL_COEX_LEADER_TX_LINE - bool - default n - config SOC_PHY_DIG_REGS_MEM_SIZE int default 21 diff --git a/components/soc/esp32h21/include/soc/soc_caps.h b/components/soc/esp32h21/include/soc/soc_caps.h index 90fde75f781..93dbb1483ab 100644 --- a/components/soc/esp32h21/include/soc/soc_caps.h +++ b/components/soc/esp32h21/include/soc/soc_caps.h @@ -444,7 +444,6 @@ /*-------------------------- EXTERNAL COEXISTENCE CAPS -------------------------------------*/ #define SOC_EXTERNAL_COEX_ADVANCE (1) /*!< HARDWARE ADVANCED EXTERNAL COEXISTENCE CAPS */ -#define SOC_EXTERNAL_COEX_LEADER_TX_LINE (0) /*!< EXTERNAL COEXISTENCE TX LINE CAPS */ /*--------------- PHY REGISTER AND MEMORY SIZE CAPS --------------------------*/ #define SOC_PHY_DIG_REGS_MEM_SIZE (21*4) diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 66f94cdea15..affe94d8b0d 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -1127,10 +1127,6 @@ config SOC_EXTERNAL_COEX_ADVANCE bool default y -config SOC_EXTERNAL_COEX_LEADER_TX_LINE - bool - default n - config SOC_PHY_DIG_REGS_MEM_SIZE int default 21 diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 5164c60b63a..48590968076 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -478,7 +478,6 @@ /*-------------------------- EXTERNAL COEXISTENCE CAPS -------------------------------------*/ #define SOC_EXTERNAL_COEX_ADVANCE (1) /*!< HARDWARE ADVANCED EXTERNAL COEXISTENCE CAPS */ -#define SOC_EXTERNAL_COEX_LEADER_TX_LINE (0) /*!< EXTERNAL COEXISTENCE TX LINE CAPS */ /*--------------- PHY REGISTER AND MEMORY SIZE CAPS --------------------------*/ #define SOC_PHY_DIG_REGS_MEM_SIZE (21*4) diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index 87efef0536c..11f54579ec4 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -979,10 +979,6 @@ config SOC_COEX_HW_PTI bool default y -config SOC_EXTERNAL_COEX_ADVANCE - bool - default n - config SOC_EXTERNAL_COEX_LEADER_TX_LINE bool default y diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 631f7aff845..bb6235e9946 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -440,7 +440,6 @@ // No contents /*-------------------------- EXTERNAL COEXISTENCE CAPS -------------------------------------*/ -#define SOC_EXTERNAL_COEX_ADVANCE (0) /*!< HARDWARE ADVANCED EXTERNAL COEXISTENCE CAPS */ #define SOC_EXTERNAL_COEX_LEADER_TX_LINE (1) /*!< EXTERNAL COEXISTENCE TX LINE CAPS */ /*-------------------------- Temperature Sensor CAPS -------------------------------------*/ diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index fe0a48c1b46..b1a311ba9b2 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -1139,10 +1139,6 @@ config SOC_COEX_HW_PTI bool default y -config SOC_EXTERNAL_COEX_ADVANCE - bool - default n - config SOC_EXTERNAL_COEX_LEADER_TX_LINE bool default y diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 228893254ed..4a59b9a6ce6 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -471,7 +471,6 @@ #define SOC_COEX_HW_PTI (1) /*-------------------------- EXTERNAL COEXISTENCE CAPS -------------------------------------*/ -#define SOC_EXTERNAL_COEX_ADVANCE (0) /*!< HARDWARE ADVANCED EXTERNAL COEXISTENCE CAPS */ #define SOC_EXTERNAL_COEX_LEADER_TX_LINE (1) /*!< EXTERNAL COEXISTENCE TX LINE CAPS */ /*-------------------------- SDMMC CAPS -----------------------------------------*/ From ba9f628f88232bbfd617db531775ccc008a7b882 Mon Sep 17 00:00:00 2001 From: muhaidong Date: Wed, 3 Jun 2026 11:05:24 +0800 Subject: [PATCH 06/27] feat(coex): add external coex unit test for esp32h4 and esp32h21 --- components/esp_coex/test_apps/.build-test-rules.yml | 4 ++-- .../esp_coex/test_apps/external_coex_function/README.md | 4 ++-- .../external_coex_function/main/test_enable_extern_coex.c | 7 +++++-- .../pytest_external_coex_function.py | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/components/esp_coex/test_apps/.build-test-rules.yml b/components/esp_coex/test_apps/.build-test-rules.yml index 21737a4ab0c..8aa670ac94b 100644 --- a/components/esp_coex/test_apps/.build-test-rules.yml +++ b/components/esp_coex/test_apps/.build-test-rules.yml @@ -2,5 +2,5 @@ components/esp_coex/test_apps/: disable: - - if: IDF_TARGET not in ["esp32s2", "esp32s3", "esp32c3", "esp32c2", "esp32c6", "esp32h2", "esp32c5", "esp32c61", "esp32s31"] - reason: only supported with s2, s3, c3, c2, c6, h2, c5, c61 and s31 + - if: IDF_TARGET not in ["esp32s2", "esp32s3", "esp32c3", "esp32c2", "esp32c6", "esp32h2", "esp32c5", "esp32c61", "esp32s31", "esp32h4", "esp32h21"] + reason: only supported with s2, s3, c3, c2, c6, h2, c5, c61, s31, esp32h4 and esp32h21 diff --git a/components/esp_coex/test_apps/external_coex_function/README.md b/components/esp_coex/test_apps/external_coex_function/README.md index a0d10bf872d..0f69904fb59 100644 --- a/components/esp_coex/test_apps/external_coex_function/README.md +++ b/components/esp_coex/test_apps/external_coex_function/README.md @@ -1,3 +1,3 @@ -| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S2 | ESP32-S3 | ESP32-S31 | -| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | --------- | +| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | --------- | diff --git a/components/esp_coex/test_apps/external_coex_function/main/test_enable_extern_coex.c b/components/esp_coex/test_apps/external_coex_function/main/test_enable_extern_coex.c index 84706ad490d..6a59384de6c 100644 --- a/components/esp_coex/test_apps/external_coex_function/main/test_enable_extern_coex.c +++ b/components/esp_coex/test_apps/external_coex_function/main/test_enable_extern_coex.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -36,12 +36,15 @@ TEST_CASE("enable external coex", "[external_coex]") #elif CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C61 #define EXTERNAL_COEX_CONF 0x600AF4A0 #define WDEV_RW_BT_COEX_EN (BIT(9)) -#elif CONFIG_IDF_TARGET_ESP32H2 +#elif CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32H21 #define EXTERNAL_COEX_CONF 0x600AD4A0 #define WDEV_RW_BT_COEX_EN (BIT(9)) #elif CONFIG_IDF_TARGET_ESP32S31 #define EXTERNAL_COEX_CONF 0x2010F4A0 #define WDEV_RW_BT_COEX_EN (BIT(9)) +#elif CONFIG_IDF_TARGET_ESP32H4 +#define EXTERNAL_COEX_CONF 0x600CF4A0 +#define WDEV_RW_BT_COEX_EN (BIT(9)) #endif esp_extern_coex_work_mode_t mode = EXTERNAL_COEX_LEADER_ROLE; diff --git a/components/esp_coex/test_apps/external_coex_function/pytest_external_coex_function.py b/components/esp_coex/test_apps/external_coex_function/pytest_external_coex_function.py index 0a527748231..17e46d77cfe 100644 --- a/components/esp_coex/test_apps/external_coex_function/pytest_external_coex_function.py +++ b/components/esp_coex/test_apps/external_coex_function/pytest_external_coex_function.py @@ -8,7 +8,7 @@ from pytest_embedded_idf.utils import idf_parametrize @pytest.mark.generic @idf_parametrize( 'target', - ['esp32h2', 'esp32c3', 'esp32s2', 'esp32s3', 'esp32c6', 'esp32c61', 'esp32c5', 'esp32s31'], + ['esp32h2', 'esp32c3', 'esp32s2', 'esp32s3', 'esp32c6', 'esp32c61', 'esp32c5', 'esp32s31', 'esp32h4', 'esp32h21'], indirect=['target'], ) def test_external_coex_unit_test(dut: Dut) -> None: From b027033c98542a28bf74093d3c8663dd1f635eae Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Tue, 2 Jun 2026 15:41:18 +0530 Subject: [PATCH 07/27] fix(nan): Add NDP Setup timeout at the publisher side - fix PASN initiator pmksa_cache_get() usage with the extra argument - Add attributes to secured NDP frames according to Specs - Resolve M2 MIC verification failure in secured datapath --- components/esp_wifi/lib | 2 +- components/wpa_supplicant/src/pasn/pasn_initiator.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 2fee84b9b73..3555d024434 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 2fee84b9b73d88b0ff713e78b1b9d759fd8d37fc +Subproject commit 3555d024434f071bd9abf9f5bde3b8dd404fc1ce diff --git a/components/wpa_supplicant/src/pasn/pasn_initiator.c b/components/wpa_supplicant/src/pasn/pasn_initiator.c index c75983c1ae5..47faab5e619 100644 --- a/components/wpa_supplicant/src/pasn/pasn_initiator.c +++ b/components/wpa_supplicant/src/pasn/pasn_initiator.c @@ -54,7 +54,7 @@ void pasn_initiator_pmksa_cache_remove(struct rsn_pmksa_cache *pmksa, { struct rsn_pmksa_cache_entry *entry; - entry = pmksa_cache_get(pmksa, bssid, NULL, NULL); + entry = pmksa_cache_get(pmksa, bssid, NULL, NULL, NULL); if (!entry) return; @@ -68,7 +68,7 @@ int pasn_initiator_pmksa_cache_get(struct rsn_pmksa_cache *pmksa, { struct rsn_pmksa_cache_entry *entry; - entry = pmksa_cache_get(pmksa, bssid, NULL, NULL); + entry = pmksa_cache_get(pmksa, bssid, NULL, NULL, NULL); if (entry) { os_memcpy(pmkid, entry->pmkid, PMKID_LEN); os_memcpy(pmk, entry->pmk, entry->pmk_len); @@ -627,7 +627,8 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct pasn_data *pasn, } else if (wrapped_data != WPA_PASN_WRAPPED_DATA_NO) { struct rsn_pmksa_cache_entry *pmksa; - pmksa = pmksa_cache_get(pasn->pmksa, pasn->peer_addr, NULL, NULL); + pmksa = pmksa_cache_get(pasn->pmksa, pasn->peer_addr, pasn->own_addr, + NULL, NULL); if (pmksa && pasn->custom_pmkid_valid) pmkid = pasn->custom_pmkid; else if (pmksa) @@ -900,7 +901,7 @@ static int wpas_pasn_set_pmk(struct pasn_data *pasn, pmkid = rsn_data->pmkid; } - pmksa = pmksa_cache_get(pasn->pmksa, pasn->peer_addr, + pmksa = pmksa_cache_get(pasn->pmksa, pasn->peer_addr, pasn->own_addr, pmkid, NULL); if (pmksa) { wpa_printf(MSG_DEBUG, "PASN: Using PMKSA"); From 8ae605b70f4935ea56637df24d1053b876837e89 Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Thu, 4 Jun 2026 12:25:35 +0530 Subject: [PATCH 08/27] fix(nan): Add CLUSTER_JOIN Event and Cluster merging feat --- components/esp_wifi/include/esp_wifi_types_generic.h | 8 ++++++++ .../remote/include/injected/esp_wifi_types_generic.h | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index ac5c111f566..8adb1ddd2f9 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -1308,6 +1308,7 @@ typedef enum { WIFI_EVENT_NAN_BOOTSTRAP_COMPLETED, /**< NAN Pairing Bootstrapping completed (success/failure) */ WIFI_EVENT_NAN_PAIRING_INDICATION, /**< Received NAN Pairing indication (reserved) */ WIFI_EVENT_NAN_PAIRING_CONFIRM, /**< NAN PASN pairwise key installation completed */ + WIFI_EVENT_NAN_CLUSTER_JOIN, /**< NAN Cluster joined/started successfully */ WIFI_EVENT_MAX, /**< Invalid Wi-Fi event ID */ } wifi_event_t; @@ -1578,6 +1579,13 @@ typedef struct { uint8_t ssi[]; /**< Service specific info of Subscriber */ } wifi_event_nan_replied_t; +/** + * @brief Argument structure for WIFI_EVENT_NAN_CLUSTER_JOIN event + */ +typedef struct { + uint8_t cluster_id[6]; /**< Cluster ID (BSSID) that was joined/started */ +} wifi_event_nan_cluster_join_t; + /** * @brief Argument structure for WIFI_EVENT_NAN_RECEIVE event */ diff --git a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h index 6debdfbecb3..397e577ebab 100644 --- a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h +++ b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h @@ -1308,6 +1308,7 @@ typedef enum { WIFI_EVENT_NAN_BOOTSTRAP_COMPLETED, /**< NAN Pairing Bootstrapping completed (success/failure) */ WIFI_EVENT_NAN_PAIRING_INDICATION, /**< Received NAN Pairing indication (reserved) */ WIFI_EVENT_NAN_PAIRING_CONFIRM, /**< NAN PASN pairwise key installation completed */ + WIFI_EVENT_NAN_CLUSTER_JOIN, /**< NAN Cluster joined/started successfully */ WIFI_EVENT_MAX, /**< Invalid Wi-Fi event ID */ } wifi_event_t; @@ -1578,6 +1579,13 @@ typedef struct { uint8_t ssi[]; /**< Service specific info of Subscriber */ } wifi_event_nan_replied_t; +/** + * @brief Argument structure for WIFI_EVENT_NAN_CLUSTER_JOIN event + */ +typedef struct { + uint8_t cluster_id[6]; /**< Cluster ID (BSSID) that was joined/started */ +} wifi_event_nan_cluster_join_t; + /** * @brief Argument structure for WIFI_EVENT_NAN_RECEIVE event */ From 3e81bc86c76f41c7a82e330707e897a160d06187 Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Thu, 4 Jun 2026 21:01:08 +0530 Subject: [PATCH 09/27] fix(nan): fix NAN pairing NIK/NIRA exchange and verification Register esp_nan_verify_nira, cache NIRA for publish frames, send own_nik in pairing follow-up, and complete pairing only after peer NIK is stored. --- .../esp_wifi/include/esp_private/wifi.h | 12 + .../esp_wifi/include/esp_wifi_types_generic.h | 4 +- .../include/injected/esp_wifi_types_generic.h | 4 +- .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 9 + .../esp_wifi/wifi_apps/nan_app/src/nan_i.h | 4 +- .../wifi_apps/nan_app/src/nan_pairing.c | 260 ++++++++++++------ .../esp_supplicant/src/esp_wifi_driver.h | 1 + 7 files changed, 211 insertions(+), 83 deletions(-) diff --git a/components/esp_wifi/include/esp_private/wifi.h b/components/esp_wifi/include/esp_private/wifi.h index a8eb783f9a3..f69b4e43388 100644 --- a/components/esp_wifi/include/esp_private/wifi.h +++ b/components/esp_wifi/include/esp_private/wifi.h @@ -195,6 +195,7 @@ struct nan_sync_callbacks { void (* receive_pasn)(uint8_t *buf, size_t len, uint16_t trans_seq, uint16_t status); uint32_t (* get_nira_len)(void); int (* construct_nira)(uint8_t *frm); + bool (*verify_nira)(uint8_t *peer_mac, uint8_t *nira_attr, uint16_t nira_attr_len); }; /* Host helpers for NAN encrypted-datapath, registered via @@ -1197,6 +1198,17 @@ uint32_t esp_nan_get_nira_len(void); */ int esp_nan_construct_nira(uint8_t *frm); +/** + * @brief Verify a received NAN Identity Resolution Attribute (NIRA) + * + * @param[in] peer_mac NMI of the sender + * @param[in] nira_attr NIRA attribute buffer + * @param[in] nira_attr_len Attribute length in bytes + * + * @return true if the tag matches, false otherwise + */ +bool esp_nan_verify_nira(uint8_t *peer_mac, uint8_t *nira_attr, uint16_t nira_attr_len); + /** * @brief Get the time information from the MAC clock. The time is precise only if modem sleep or light sleep is not enabled. * diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index 8adb1ddd2f9..3e28f14e7b3 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -1580,8 +1580,8 @@ typedef struct { } wifi_event_nan_replied_t; /** - * @brief Argument structure for WIFI_EVENT_NAN_CLUSTER_JOIN event - */ + * @brief Argument structure for WIFI_EVENT_NAN_CLUSTER_JOIN event + */ typedef struct { uint8_t cluster_id[6]; /**< Cluster ID (BSSID) that was joined/started */ } wifi_event_nan_cluster_join_t; diff --git a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h index 397e577ebab..e4e98fcc114 100644 --- a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h +++ b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h @@ -1580,8 +1580,8 @@ typedef struct { } wifi_event_nan_replied_t; /** - * @brief Argument structure for WIFI_EVENT_NAN_CLUSTER_JOIN event - */ + * @brief Argument structure for WIFI_EVENT_NAN_CLUSTER_JOIN event + */ typedef struct { uint8_t cluster_id[6]; /**< Cluster ID (BSSID) that was joined/started */ } wifi_event_nan_cluster_join_t; diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c index a8a137ad20e..fea7ddfff64 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c @@ -59,6 +59,14 @@ int esp_nan_construct_nira(uint8_t *frm) (void)frm; return 0; } + +bool esp_nan_verify_nira(uint8_t *peer_mac, uint8_t *nira_attr, uint16_t nira_attr_len) +{ + (void)peer_mac; + (void)nira_attr; + (void)nira_attr_len; + return false; +} #endif #if defined(CONFIG_ESP_WIFI_NAN_SYNC_ENABLE) && defined(CONFIG_ESP_WIFI_PASN_SUPPORT) @@ -1435,6 +1443,7 @@ void esp_nan_action_start(esp_netif_t *nan_netif) #ifdef CONFIG_ESP_WIFI_NAN_PAIRING .get_nira_len = esp_nan_get_nira_len, .construct_nira = esp_nan_construct_nira, + .verify_nira = esp_nan_verify_nira, .receive_pasn = handle_auth_pasn, #endif }; diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h index 80064086d8a..54eeb252000 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h @@ -287,9 +287,11 @@ typedef struct { struct own_svc_info own_svc[ESP_WIFI_NAN_MAX_SVC_SUPPORTED]; esp_netif_t *nan_netif; #ifdef CONFIG_ESP_WIFI_NAN_SECURITY - /* Own NAN Identity Key (NIK) cached for pairing/security flows. */ uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN]; bool own_nik_valid; + uint8_t cached_nira_nonce[8]; + uint8_t cached_nira_tag[8]; + bool cached_nira_valid; #endif #ifdef CONFIG_ESP_WIFI_PASN_SUPPORT struct nan_pasn_data *nan_pasn_data; diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index 53c26be1959..c5d5ae120e1 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -21,6 +21,7 @@ #include "nan_i.h" #include "os.h" #include "utils/common.h" +#include "utils/eloop.h" #if defined(CONFIG_ESP_WIFI_PASN_SUPPORT) #include "esp_private/esp_supp_nan.h" @@ -49,42 +50,7 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, uint8_t role, uint8_t ndp_csid, const uint8_t *nd_pmk, - size_t nd_pmk_len) -{ - wifi_event_nan_pairing_complete_t evt = {0}; - - if (!peer_nmi) { - return; - } - -#if defined(CONFIG_ESP_WIFI_NAN_SECURITY) - /* Cache ND-PMK for future paired NDPs (Wi-Fi Aware v4.0 §7.6.4.2). The - * NDP cipher (CSID) is determined by the PASN cipher and resolved on the - * supplicant side before this callback fires; if either is missing, the - * pairing event still fires but the security layer will fall back to its - * service-credential path for any subsequent NDP. */ - if (ndp_csid && nd_pmk && nd_pmk_len == ESP_WIFI_NAN_NDP_PMK_LEN) { - (void)nan_app_register_paired_peer(peer_nmi, role, ndp_csid, - nd_pmk, nd_pmk_len, - NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC); - } else { - ESP_LOGW(TAG, "Pairing complete for " MACSTR - ": ND-PMK unavailable (csid=%u nd_pmk_len=%u); " - "paired-peer cache not updated", - MAC2STR(peer_nmi), ndp_csid, (unsigned)nd_pmk_len); - } -#else - (void)role; - (void)ndp_csid; - (void)nd_pmk; - (void)nd_pmk_len; -#endif - - evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; - evt.reason_code = 0; - MACADDR_COPY(evt.peer_nmi, peer_nmi); - nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); -} + size_t nd_pmk_len); #endif bool nan_pairing_validate_publish_bootstrapping(uint16_t bootstrapping_methods) @@ -334,53 +300,66 @@ uint32_t esp_nan_get_nira_len(void) int esp_nan_construct_nira(uint8_t *frm) { - uint8_t nonce[NAN_NIRA_NONCE_LEN]; - uint8_t tag[NAN_NIRA_TAG_LEN]; + const uint8_t *nonce; + const uint8_t *tag; + uint8_t fresh_nonce[NAN_NIRA_NONCE_LEN]; + uint8_t fresh_tag[NAN_NIRA_TAG_LEN]; if (!frm) { return 0; } - if (os_get_random(nonce, sizeof(nonce)) != 0) { - ESP_LOGE(TAG, "NIRA: failed to generate nonce"); - return 0; - } - #ifdef CONFIG_ESP_WIFI_NAN_SECURITY - uint8_t own_nmi[MACADDR_LEN]; - const unsigned char *addr[3]; - int len_arr[3]; - uint8_t digest[32]; + if (s_nan_ctx.cached_nira_valid) { + nonce = s_nan_ctx.cached_nira_nonce; + tag = s_nan_ctx.cached_nira_tag; + } else { + uint8_t own_nmi[MACADDR_LEN]; + const unsigned char *addr[3]; + int len_arr[3]; + uint8_t digest[32]; - if (!s_nan_ctx.own_nik_valid) { - ESP_LOGW(TAG, "NIRA: own NIK is not available"); - return 0; - } - if (!g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector) { - ESP_LOGE(TAG, "NIRA: hmac_sha256_vector not registered"); - return 0; - } - if (esp_wifi_get_mac(WIFI_IF_NAN, own_nmi) != ESP_OK) { - ESP_LOGE(TAG, "NIRA: failed to read NAN NMI"); - return 0; - } + if (!s_nan_ctx.own_nik_valid) { + ESP_LOGW(TAG, "NIRA: own NIK is not available"); + return 0; + } + if (!g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector) { + ESP_LOGE(TAG, "NIRA: hmac_sha256_vector not registered"); + return 0; + } + if (esp_wifi_get_mac(WIFI_IF_NAN, own_nmi) != ESP_OK) { + ESP_LOGE(TAG, "NIRA: failed to read NAN NMI"); + return 0; + } + if (os_get_random(fresh_nonce, sizeof(fresh_nonce)) != 0) { + ESP_LOGE(TAG, "NIRA: failed to generate nonce"); + return 0; + } - /* Tag = Truncate-64(HMAC-SHA-256(NIK, "NIR" || NMI || Nonce)) */ - addr[0] = (const unsigned char *)NAN_NIRA_STR; - len_arr[0] = NAN_NIRA_STR_LEN; - addr[1] = own_nmi; - len_arr[1] = MACADDR_LEN; - addr[2] = nonce; - len_arr[2] = NAN_NIRA_NONCE_LEN; - if (g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector(s_nan_ctx.own_nik, - ESP_WIFI_NAN_NIK_LEN, - 3, addr, len_arr, - digest) != 0) { - ESP_LOGE(TAG, "NIRA: tag derivation failed"); - return 0; + /* Tag = Truncate-64(HMAC-SHA-256(NIK, "NIR" || NMI || Nonce)) */ + addr[0] = (const unsigned char *)NAN_NIRA_STR; + len_arr[0] = NAN_NIRA_STR_LEN; + addr[1] = own_nmi; + len_arr[1] = MACADDR_LEN; + addr[2] = fresh_nonce; + len_arr[2] = NAN_NIRA_NONCE_LEN; + if (g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector(s_nan_ctx.own_nik, + ESP_WIFI_NAN_NIK_LEN, + 3, addr, len_arr, + digest) != 0) { + ESP_LOGE(TAG, "NIRA: tag derivation failed"); + return 0; + } + memcpy(fresh_tag, digest, NAN_NIRA_TAG_LEN); + memset(digest, 0, sizeof(digest)); + + memcpy(s_nan_ctx.cached_nira_nonce, fresh_nonce, NAN_NIRA_NONCE_LEN); + memcpy(s_nan_ctx.cached_nira_tag, fresh_tag, NAN_NIRA_TAG_LEN); + s_nan_ctx.cached_nira_valid = true; + + nonce = fresh_nonce; + tag = fresh_tag; } - memcpy(tag, digest, NAN_NIRA_TAG_LEN); - memset(digest, 0, sizeof(digest)); #else /* NIRA requires an available NIK; skip when NAN security is not enabled. */ return 0; @@ -403,7 +382,6 @@ int esp_nan_construct_nira(uint8_t *frm) #if defined(CONFIG_ESP_WIFI_NAN_PAIRING) && defined(CONFIG_ESP_WIFI_PASN_SUPPORT) && defined(CONFIG_ESP_WIFI_NAN_SECURITY) #include "crypto/sha256.h" -#include "utils/eloop.h" #include "crypto/aes_wrap.h" #include "common/ieee802_11_defs.h" #include "common/wpa_common.h" @@ -680,9 +658,14 @@ static esp_err_t nan_app_send_pairing_followup(uint8_t svc_id, uint8_t peer_svc_ (void)shared_key_attr; (void)shared_key_attr_len; - if (!peer_mac || os_get_random(nik, sizeof(nik)) != 0) { + if (!peer_mac) { return ESP_ERR_INVALID_ARG; } + if (!s_nan_ctx.own_nik_valid) { + ESP_LOGW(TAG, "Pairing follow-up: own NIK is not available"); + return ESP_ERR_INVALID_STATE; + } + memcpy(nik, s_nan_ctx.own_nik, sizeof(nik)); saved = nan_pasn_get_saved_keys(); if (!saved || !saved->kek_len) { @@ -773,6 +756,7 @@ static void nan_app_send_pairing_followup_eloop(void *eloop_data, void *user_dat if (!ctx) { return; } + (void) nan_app_send_pairing_followup(ctx->svc_id, ctx->peer_svc_id, ctx->peer_mac, ctx->shared_key_attr, @@ -780,6 +764,62 @@ static void nan_app_send_pairing_followup_eloop(void *eloop_data, void *user_dat os_free(ctx); } +static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, + uint8_t role, + uint8_t ndp_csid, + const uint8_t *nd_pmk, + size_t nd_pmk_len) +{ + if (!peer_nmi) { + return; + } + +#if defined(CONFIG_ESP_WIFI_NAN_SECURITY) + /* Cache ND-PMK for future paired NDPs (Wi-Fi Aware v4.0 §7.6.4.2). */ + if (ndp_csid && nd_pmk && nd_pmk_len == ESP_WIFI_NAN_NDP_PMK_LEN) { + (void)nan_app_register_paired_peer(peer_nmi, role, ndp_csid, + nd_pmk, nd_pmk_len, + NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC); + } else { + ESP_LOGW(TAG, "Pairing complete for " MACSTR + ": ND-PMK unavailable (csid=%u nd_pmk_len=%u); " + "paired-peer cache not updated", + MAC2STR(peer_nmi), ndp_csid, (unsigned)nd_pmk_len); + } +#else + (void)ndp_csid; + (void)nd_pmk; + (void)nd_pmk_len; +#endif + + if (role == NAN_ROLE_PAIRING_INITIATOR) { + struct nan_pairing_fup_ctx *ctx = os_zalloc(sizeof(*ctx)); + if (!ctx) { + ESP_LOGW(TAG, "Pairing key installed: failed to alloc fup ctx for " MACSTR, + MAC2STR(peer_nmi)); + return; + } + + NAN_DATA_LOCK(); + struct peer_svc_info *peer = nan_find_peer_svc(0, 0, (uint8_t *)peer_nmi); + if (peer) { + ctx->svc_id = peer->own_svc_id; + ctx->peer_svc_id = peer->svc_id; + } + NAN_DATA_UNLOCK(); + + MACADDR_COPY(ctx->peer_mac, peer_nmi); + ctx->shared_key_attr_len = 0; + + if (eloop_register_timeout(0, 0, nan_app_send_pairing_followup_eloop, NULL, ctx) != 0) { + ESP_LOGW(TAG, "Pairing key installed: failed to schedule initiator follow-up"); + os_free(ctx); + } + return; + } + (void)role; +} + void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, const uint8_t *peer_mac, const uint8_t *shared_key_attr, @@ -792,7 +832,6 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, uint32_t lifetime_sec = 0; struct nan_pairing_fup_ctx *ctx; size_t alloc_len; - if (!shared_key_attr || !peer_mac) { return; } @@ -802,7 +841,6 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, if (shared_key_attr[0] != NAN_ATTR_ID_SHARED_KEY_DESC) { return; } - const uint16_t *attr_body_len_field = (const uint16_t *)&shared_key_attr[1]; attr_body_len = *attr_body_len_field; @@ -823,18 +861,39 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, return; } + bool already_had_nik = false; + NAN_DATA_LOCK(); struct peer_svc_info *p_peer_svc = nan_find_peer_svc_exact(svc_id, peer_svc_id, peer_mac); if (p_peer_svc) { + already_had_nik = p_peer_svc->has_nik; memcpy(p_peer_svc->peer_nik, nik, NAN_APP_PEER_NIK_LEN); p_peer_svc->peer_nik_cipher_ver = cipher_ver; p_peer_svc->peer_nik_lifetime_sec = lifetime_sec; p_peer_svc->has_nik = true; ESP_LOGI(TAG, "Stored peer NIK from " MACSTR " (cipher_ver=%u, lifetime=%u s)", MAC2STR(peer_mac), cipher_ver, lifetime_sec); + + if (!already_had_nik) { + wifi_event_nan_pairing_complete_t evt = {0}; + evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; + evt.reason_code = 0; + MACADDR_COPY(evt.peer_nmi, peer_mac); + esp_nan_disable_pairing(); + nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); + } } NAN_DATA_UNLOCK(); + /* Only reply with our own NIK the first time we receive the peer's. + * If has_nik was already true this is a redundant echo — don't reply + * or we create an infinite ping-pong of follow-ups. */ + if (already_had_nik) { + ESP_LOGD(TAG, "Pairing follow-up: NIK already known for " MACSTR ", skipping reply", + MAC2STR(peer_mac)); + return; + } + if (total_len > SIZE_MAX - sizeof(*ctx)) { return; } @@ -855,6 +914,51 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, } } +bool esp_nan_verify_nira(uint8_t *peer_mac, uint8_t *nira_attr, uint16_t nira_attr_len) +{ + uint8_t expected_tag[NAN_NIRA_TAG_LEN]; + const uint8_t *nonce; + const uint8_t *received_tag; + struct peer_svc_info *p_peer_svc; + bool match; + + if (!peer_mac || !nira_attr) { + return false; + } + + if (nira_attr_len < NAN_NIRA_ATTR_LEN) { + ESP_LOGW(TAG, "NIRA verify: attribute too short (%u < %u)", + (unsigned)nira_attr_len, (unsigned)NAN_NIRA_ATTR_LEN); + return false; + } + + nonce = nira_attr + 4; + received_tag = nira_attr + 4 + NAN_NIRA_NONCE_LEN; + + NAN_DATA_LOCK(); + p_peer_svc = nan_find_peer_svc(0, 0, peer_mac); + if (!p_peer_svc || !p_peer_svc->has_nik) { + NAN_DATA_UNLOCK(); + ESP_LOGD(TAG, "NIRA verify: no stored NIK for "MACSTR, MAC2STR(peer_mac)); + return false; + } + + if (nan_pairing_derive_nira_tag(p_peer_svc->peer_nik, peer_mac, nonce, expected_tag) != 0) { + NAN_DATA_UNLOCK(); + ESP_LOGE(TAG, "NIRA verify: tag derivation failed for "MACSTR, MAC2STR(peer_mac)); + return false; + } + NAN_DATA_UNLOCK(); + + match = (os_memcmp_const(expected_tag, received_tag, NAN_NIRA_TAG_LEN) == 0); + if (match) { + ESP_LOGD(TAG, "NIRA verify: OK for "MACSTR, MAC2STR(peer_mac)); + } else { + ESP_LOGW(TAG, "NIRA verify: tag mismatch for "MACSTR, MAC2STR(peer_mac)); + } + return match; +} + #endif /* CONFIG_ESP_WIFI_NAN_PAIRING && CONFIG_ESP_WIFI_PASN_SUPPORT && CONFIG_ESP_WIFI_NAN_SECURITY */ #endif /* CONFIG_ESP_WIFI_NAN_PAIRING */ diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h index dcf3fed52f7..35e5e93a3ba 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -334,5 +334,6 @@ void esp_wifi_ap_set_group_mgmt_cipher_internal(wifi_cipher_type_t cipher); uint8_t esp_wifi_op_class_supported_internal(uint8_t op_class, uint8_t min_chan, uint8_t max_chan, uint8_t inc, uint8_t bw, channel_bitmap_t *non_pref_channels); bool esp_wifi_is_wpa3_compatible_mode_enabled(uint8_t if_index); uint8_t esp_wifi_ap_get_owe_config_internal(void); +esp_err_t esp_nan_disable_pairing(void); #endif /* _ESP_WIFI_DRIVER_H_ */ From 2e2e63e3d3b5ac87e0be170cb77f5b6d30fb4f7c Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Mon, 8 Jun 2026 17:06:54 +0530 Subject: [PATCH 10/27] Address Review comments --- .../esp_wifi/include/esp_wifi_types_generic.h | 2 +- .../include/injected/esp_wifi_types_generic.h | 2 +- .../esp_wifi/wifi_apps/nan_app/src/nan_i.h | 2 +- .../wifi_apps/nan_app/src/nan_pairing.c | 20 +++++++++++----- .../include/esp_private/esp_supp_nan.h | 23 +++++++++++++++---- .../esp_supplicant/src/esp_nan_supp_i.h | 1 + .../esp_supplicant/src/esp_nan_supplicant.c | 14 +++++++++-- .../esp_supplicant/src/esp_wifi_driver.h | 2 +- 8 files changed, 49 insertions(+), 17 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index 3e28f14e7b3..412c1a22b2e 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -1583,7 +1583,7 @@ typedef struct { * @brief Argument structure for WIFI_EVENT_NAN_CLUSTER_JOIN event */ typedef struct { - uint8_t cluster_id[6]; /**< Cluster ID (BSSID) that was joined/started */ + uint8_t cluster_id[6]; /**< NAN Cluster ID (BSSID) that was joined/started by the device */ } wifi_event_nan_cluster_join_t; /** diff --git a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h index e4e98fcc114..266a5027bf3 100644 --- a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h +++ b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h @@ -1583,7 +1583,7 @@ typedef struct { * @brief Argument structure for WIFI_EVENT_NAN_CLUSTER_JOIN event */ typedef struct { - uint8_t cluster_id[6]; /**< Cluster ID (BSSID) that was joined/started */ + uint8_t cluster_id[6]; /**< NAN Cluster ID (BSSID) that was joined/started by the device */ } wifi_event_nan_cluster_join_t; /** diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h index 54eeb252000..c58587ec7aa 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h @@ -291,7 +291,7 @@ typedef struct { bool own_nik_valid; uint8_t cached_nira_nonce[8]; uint8_t cached_nira_tag[8]; - bool cached_nira_valid; + bool nira_cached; #endif #ifdef CONFIG_ESP_WIFI_PASN_SUPPORT struct nan_pasn_data *nan_pasn_data; diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index c5d5ae120e1..71d4043d416 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -50,7 +50,8 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, uint8_t role, uint8_t ndp_csid, const uint8_t *nd_pmk, - size_t nd_pmk_len); + size_t nd_pmk_len, + uint32_t nik_lifetime_sec); #endif bool nan_pairing_validate_publish_bootstrapping(uint16_t bootstrapping_methods) @@ -259,6 +260,7 @@ esp_err_t esp_wifi_nan_pairing_start(wifi_nan_pairing_config_t *cfg) switch (cfg->self_role) { case NAN_PAIRING_ROLE_RESPONDER: ret = esp_nan_supp_pasn_responder_init(cfg->peer_nmi, cfg->cred.pincode, + NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC, nan_pairing_key_installed_cb); if (ret != 0) { ESP_LOGE(TAG, "NAN PASN responder init failed for "MACSTR, MAC2STR(cfg->peer_nmi)); @@ -267,6 +269,7 @@ esp_err_t esp_wifi_nan_pairing_start(wifi_nan_pairing_config_t *cfg) break; case NAN_PAIRING_ROLE_INITIATOR: ret = esp_nan_supp_pasn_initiator_auth(cfg->peer_nmi, cfg->cred.pincode, + NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC, nan_pairing_key_installed_cb); if (ret != 0) { ESP_LOGE(TAG, "NAN PASN initiator auth failed for "MACSTR, MAC2STR(cfg->peer_nmi)); @@ -310,7 +313,7 @@ int esp_nan_construct_nira(uint8_t *frm) } #ifdef CONFIG_ESP_WIFI_NAN_SECURITY - if (s_nan_ctx.cached_nira_valid) { + if (s_nan_ctx.nira_cached) { nonce = s_nan_ctx.cached_nira_nonce; tag = s_nan_ctx.cached_nira_tag; } else { @@ -355,7 +358,7 @@ int esp_nan_construct_nira(uint8_t *frm) memcpy(s_nan_ctx.cached_nira_nonce, fresh_nonce, NAN_NIRA_NONCE_LEN); memcpy(s_nan_ctx.cached_nira_tag, fresh_tag, NAN_NIRA_TAG_LEN); - s_nan_ctx.cached_nira_valid = true; + s_nan_ctx.nira_cached = true; nonce = fresh_nonce; tag = fresh_tag; @@ -768,18 +771,22 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, uint8_t role, uint8_t ndp_csid, const uint8_t *nd_pmk, - size_t nd_pmk_len) + size_t nd_pmk_len, + uint32_t nik_lifetime_sec) { if (!peer_nmi) { return; } #if defined(CONFIG_ESP_WIFI_NAN_SECURITY) + uint32_t lifetime_sec = nik_lifetime_sec ? + nik_lifetime_sec : NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC; + /* Cache ND-PMK for future paired NDPs (Wi-Fi Aware v4.0 §7.6.4.2). */ if (ndp_csid && nd_pmk && nd_pmk_len == ESP_WIFI_NAN_NDP_PMK_LEN) { (void)nan_app_register_paired_peer(peer_nmi, role, ndp_csid, nd_pmk, nd_pmk_len, - NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC); + lifetime_sec); } else { ESP_LOGW(TAG, "Pairing complete for " MACSTR ": ND-PMK unavailable (csid=%u nd_pmk_len=%u); " @@ -790,6 +797,7 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, (void)ndp_csid; (void)nd_pmk; (void)nd_pmk_len; + (void)nik_lifetime_sec; #endif if (role == NAN_ROLE_PAIRING_INITIATOR) { @@ -879,7 +887,7 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; evt.reason_code = 0; MACADDR_COPY(evt.peer_nmi, peer_mac); - esp_nan_disable_pairing(); + esp_nan_disable_pairing(p_peer_svc->own_svc_id); nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); } } diff --git a/components/wpa_supplicant/esp_supplicant/include/esp_private/esp_supp_nan.h b/components/wpa_supplicant/esp_supplicant/include/esp_private/esp_supp_nan.h index 1ab35e54cfa..865b93ac18b 100644 --- a/components/wpa_supplicant/esp_supplicant/include/esp_private/esp_supp_nan.h +++ b/components/wpa_supplicant/esp_supplicant/include/esp_private/esp_supp_nan.h @@ -64,14 +64,19 @@ enum nan_role { * @param role enum nan_role value for the local device. * @param ndp_csid NCS-SK CSID for paired-peer NDP (WIFI_NAN_CSID_NCS_SK_128 * or _SK_256), 0 if no usable cipher mapping was available. - * @param nd_pmk ND-PMK bytes (32) or NULL if KDK was absent. - * @param nd_pmk_len Length of @a nd_pmk (32 when present, 0 otherwise). + * @param nd_pmk ND-PMK bytes (32) or NULL if KDK was absent. + * @param nd_pmk_len Length of @a nd_pmk (32 when present, 0 otherwise). + * @param nik_lifetime_sec NIK / paired-peer cache lifetime in seconds, as supplied + * to @ref esp_nan_supp_pasn_initiator_auth or + * @ref esp_nan_supp_pasn_responder_init. The NAN app + * substitutes 86400 s when this is 0. */ typedef void (*esp_nan_pairing_key_installed_cb_t)(const uint8_t *peer_nmi, uint8_t role, uint8_t ndp_csid, const uint8_t *nd_pmk, - size_t nd_pmk_len); + size_t nd_pmk_len, + uint32_t nik_lifetime_sec); /** * Last PASN key material after successful pairing (PMK + flattened PTK KCK|KEK|TK|KDK). @@ -98,11 +103,15 @@ struct nan_pasn_key_material { * pairing responder. Runs on the wpa_supplicant eloop thread. * * @param peer_nmi Peer NMI (6 bytes). - * @param pincode 6-digit PIN (0..999999), or @c UINT32_MAX for the default PIN. + * @param pincode 6-digit PIN (0..999999), or @c UINT32_MAX for the default PIN. + * @param nik_lifetime_sec NIK lifetime in seconds; forwarded unchanged to + * @c pairing_key_installed_cb (NAN app currently + * passes 86400). * @param pairing_key_installed_cb Callback invoked after pairwise key installation with peer NMI. * @return 0 on success, -1 on failure. */ int esp_nan_supp_pasn_responder_init(const uint8_t *peer_nmi, uint32_t pincode, + uint32_t nik_lifetime_sec, esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb); /** @@ -113,11 +122,15 @@ int esp_nan_supp_pasn_responder_init(const uint8_t *peer_nmi, uint32_t pincode, * Runs on the wpa_supplicant eloop thread. * * @param peer_nmi Peer NMI (6 bytes). - * @param pincode 6-digit PIN (0..999999), or @c UINT32_MAX for the default PIN. + * @param pincode 6-digit PIN (0..999999), or @c UINT32_MAX for the default PIN. + * @param nik_lifetime_sec NIK lifetime in seconds; forwarded unchanged to + * @c pairing_key_installed_cb (NAN app currently + * passes 86400). * @param pairing_key_installed_cb Callback invoked after pairwise key installation with peer NMI. * @return 0 on success, -1 on failure. */ int esp_nan_supp_pasn_initiator_auth(const uint8_t *peer_nmi, uint32_t pincode, + uint32_t nik_lifetime_sec, esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb); /** diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_nan_supp_i.h b/components/wpa_supplicant/esp_supplicant/src/esp_nan_supp_i.h index 92accd57134..044cdcf1c83 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_nan_supp_i.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_nan_supp_i.h @@ -43,6 +43,7 @@ struct nan_pasn_data { size_t pasn_ptk_len; struct pasn_data *pasn; nan_pasn_pairing_key_installed_cb_t pairing_key_installed_cb; + uint32_t nik_lifetime_sec; }; int nan_initiate_pasn_verify(struct nan_pasn_data *pd, const uint8_t *peer_addr, diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_nan_supplicant.c b/components/wpa_supplicant/esp_supplicant/src/esp_nan_supplicant.c index 3a3ea9d2edd..c332d1a47bd 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_nan_supplicant.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_nan_supplicant.c @@ -1254,7 +1254,8 @@ static int nan_handle_pasn_auth(struct nan_pasn_data *nan, nan->pairing_key_installed_cb(pasn->peer_addr, (uint8_t)nan->dev_role, nan_pasn_pasn_cipher_to_ndp_csid(pasn->cipher), - nd_pmk, nd_pmk_len); + nd_pmk, nd_pmk_len, + nan->nik_lifetime_sec); } forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk)); nan_pasn_data_deinit(nan); @@ -1311,7 +1312,8 @@ int nan_pasn_auth_rx(struct nan_pasn_data *nan, const struct ieee80211_auth *mgm nan->pairing_key_installed_cb(pasn->peer_addr, (uint8_t)nan->dev_role, nan_pasn_pasn_cipher_to_ndp_csid(pasn->cipher), - nd_pmk, nd_pmk_len); + nd_pmk, nd_pmk_len, + nan->nik_lifetime_sec); } } #ifdef CONFIG_TESTING_OPTIONS @@ -1550,6 +1552,7 @@ int nan_pasn_auth_initiate(struct nan_pasn_data *pd, const uint8_t *peer_addr, i struct nan_pasn_eloop_ctx { uint8_t peer_addr[ETH_ALEN]; uint32_t pincode; + uint32_t nik_lifetime_sec; esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb; }; @@ -1580,6 +1583,7 @@ static void nan_pasn_auth_eloop_cb(void *eloop_ctx, void *user_data) esp_nan_app_set_pasn_data(pd); pd->pairing_key_installed_cb = ctx->pairing_key_installed_cb; + pd->nik_lifetime_sec = ctx->nik_lifetime_sec; if (ctx->pincode != UINT32_MAX) { n = os_snprintf(pin_digits, sizeof(pin_digits), "%06u", @@ -1610,6 +1614,7 @@ static void nan_pasn_auth_eloop_cb(void *eloop_ctx, void *user_data) } int esp_nan_supp_pasn_initiator_auth(const uint8_t *peer_nmi, uint32_t pincode, + uint32_t nik_lifetime_sec, esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb) { struct nan_pasn_eloop_ctx *ctx; @@ -1621,6 +1626,7 @@ int esp_nan_supp_pasn_initiator_auth(const uint8_t *peer_nmi, uint32_t pincode, os_memcpy(ctx->peer_addr, peer_nmi, ETH_ALEN); ctx->pincode = pincode; + ctx->nik_lifetime_sec = nik_lifetime_sec; ctx->pairing_key_installed_cb = pairing_key_installed_cb; if (eloop_register_timeout(0, 0, nan_pasn_auth_eloop_cb, NULL, ctx) != 0) { @@ -1773,6 +1779,7 @@ fail: struct pasn_responder_eloop_ctx { uint8_t peer_addr[ETH_ALEN]; uint32_t pincode; + uint32_t nik_lifetime_sec; esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb; }; @@ -1789,12 +1796,14 @@ static void pasn_responder_init_eloop_cb(void *eloop_ctx, void *user_data) pd = esp_nan_app_get_pasn_data(); if (pd) { pd->pairing_key_installed_cb = ctx->pairing_key_installed_cb; + pd->nik_lifetime_sec = ctx->nik_lifetime_sec; } } os_free(ctx); } int esp_nan_supp_pasn_responder_init(const uint8_t *peer_nmi, uint32_t pincode, + uint32_t nik_lifetime_sec, esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb) { struct pasn_responder_eloop_ctx *ctx; @@ -1805,6 +1814,7 @@ int esp_nan_supp_pasn_responder_init(const uint8_t *peer_nmi, uint32_t pincode, } ctx->pincode = pincode; + ctx->nik_lifetime_sec = nik_lifetime_sec; os_memcpy(ctx->peer_addr, peer_nmi, ETH_ALEN); ctx->pairing_key_installed_cb = pairing_key_installed_cb; diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h index 35e5e93a3ba..59fd3c62d98 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -334,6 +334,6 @@ void esp_wifi_ap_set_group_mgmt_cipher_internal(wifi_cipher_type_t cipher); uint8_t esp_wifi_op_class_supported_internal(uint8_t op_class, uint8_t min_chan, uint8_t max_chan, uint8_t inc, uint8_t bw, channel_bitmap_t *non_pref_channels); bool esp_wifi_is_wpa3_compatible_mode_enabled(uint8_t if_index); uint8_t esp_wifi_ap_get_owe_config_internal(void); -esp_err_t esp_nan_disable_pairing(void); +esp_err_t esp_nan_disable_pairing(uint8_t svc_id); #endif /* _ESP_WIFI_DRIVER_H_ */ From fd550bd66b0ede15b550f67c994742bc1318156a Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Tue, 9 Jun 2026 12:28:34 +0530 Subject: [PATCH 11/27] fix(nan): address esp_ai_reviewer review comments --- .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 2 ++ .../wifi_apps/nan_app/src/nan_pairing.c | 29 +++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c index fea7ddfff64..347b643c92f 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c @@ -1525,6 +1525,8 @@ esp_err_t esp_wifi_nan_sync_start(const wifi_nan_sync_config_t *nan_cfg) } s_nan_ctx.own_nik_valid = true; } + /* Drop the cached NIRA tag; it was derived from the previous NIK. */ + s_nan_ctx.nira_cached = false; #endif NAN_DATA_UNLOCK(); diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index 71d4043d416..73fcc571539 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -816,6 +816,15 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, } NAN_DATA_UNLOCK(); + /* Without a peer service entry the follow-up would carry zero service + * IDs; drop it rather than send an invalid frame. */ + if (!ctx->svc_id || !ctx->peer_svc_id) { + ESP_LOGW(TAG, "Pairing key installed: peer service not found for " MACSTR + ", skipping initiator follow-up", MAC2STR(peer_nmi)); + os_free(ctx); + return; + } + MACADDR_COPY(ctx->peer_mac, peer_nmi); ctx->shared_key_attr_len = 0; @@ -870,6 +879,8 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, } bool already_had_nik = false; + bool pairing_completed = false; + uint8_t own_svc_id_to_disable = 0; NAN_DATA_LOCK(); struct peer_svc_info *p_peer_svc = nan_find_peer_svc_exact(svc_id, peer_svc_id, peer_mac); @@ -883,16 +894,22 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, MAC2STR(peer_mac), cipher_ver, lifetime_sec); if (!already_had_nik) { - wifi_event_nan_pairing_complete_t evt = {0}; - evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; - evt.reason_code = 0; - MACADDR_COPY(evt.peer_nmi, peer_mac); - esp_nan_disable_pairing(p_peer_svc->own_svc_id); - nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); + pairing_completed = true; + own_svc_id_to_disable = p_peer_svc->own_svc_id; } } NAN_DATA_UNLOCK(); + /* Invoke blocking calls outside NAN_DATA_LOCK to avoid deadlock. */ + if (pairing_completed) { + wifi_event_nan_pairing_complete_t evt = {0}; + evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; + evt.reason_code = 0; + MACADDR_COPY(evt.peer_nmi, peer_mac); + esp_nan_disable_pairing(own_svc_id_to_disable); + nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); + } + /* Only reply with our own NIK the first time we receive the peer's. * If has_nik was already true this is a redundant echo — don't reply * or we create an infinite ping-pong of follow-ups. */ From cf95c2ad909e20849d5a4b86e4f6839c692f9359 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Tue, 9 Jun 2026 15:34:33 +0530 Subject: [PATCH 12/27] fix(nan): Move Pairing API's to private header --- .../include/apps_private/wifi_apps_private.h | 129 +++++++++++++++++- .../wifi_apps/nan_app/include/esp_nan.h | 110 --------------- 2 files changed, 125 insertions(+), 114 deletions(-) diff --git a/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h b/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h index cd726f58b1c..1fe52d7502c 100644 --- a/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h +++ b/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h @@ -51,13 +51,134 @@ void esp_nan_action_stop(void); #endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ -#if defined(CONFIG_ESP_WIFI_PASN_SUPPORT) +#ifdef CONFIG_ESP_WIFI_NAN_PAIRING + +#define NAN_PAIRING_PINCODE_MIN 000000 +#define NAN_PAIRING_PINCODE_MAX 999999 + +union pairing_cred_t { + uint32_t pincode; /**< 6-digit PIN in range of NAN_PAIRING_PINCODE_MIN to NAN_PAIRING_PINCODE_MAX */ +}; + +enum nan_pairing_role { + NAN_PAIRING_ROLE_INITIATOR, + NAN_PAIRING_ROLE_RESPONDER, +}; + +typedef struct { + uint8_t peer_svc_id; + uint8_t peer_nmi[6]; + enum nan_pairing_role self_role; + union pairing_cred_t cred; +} wifi_nan_pairing_config_t; + +/** + * @brief NAN Pairing Bootstrapping status values + */ +typedef enum { + WIFI_NAN_PAIRING_STATUS_ACCEPTED = 0, /**< Bootstrapping request accepted */ + WIFI_NAN_PAIRING_STATUS_REJECTED = 1, /**< Bootstrapping request rejected */ + WIFI_NAN_PAIRING_STATUS_COMEBACK = 2, /**< Comeback - responder needs more time */ +} wifi_nan_pairing_status_t; + +/** + * @brief NAN Pairing Bootstrapping Request parameters (initiator -> responder) + * + * Used by a subscriber (bootstrapping initiator) to send a bootstrapping + * request follow-up message with NPBA attribute (Type=Request) to a publisher. + */ +typedef struct { + uint8_t inst_id; /**< Own service instance id */ + uint8_t peer_inst_id; /**< Peer's service instance id */ + uint8_t peer_mac[6]; /**< Peer's NAN Management Interface MAC */ + uint16_t selected_method; /**< One selected WIFI_NAN_BOOTSTRAP_* method bit */ + wifi_nan_pairing_status_t status; /**< Set to COMEBACK when resending with cookie */ + uint16_t comeback_after; /**< Comeback deferral time in TUs (only when status=COMEBACK) */ + uint32_t cookie; /**< Opaque cookie from responder (only when status=COMEBACK) */ +} wifi_nan_pairing_bootstrap_req_t; + +/** + * @brief NAN Pairing Bootstrapping Response parameters (responder -> initiator) + * + * Used by a publisher (bootstrapping responder) to respond to a bootstrapping + * request follow-up message with NPBA attribute (Type=Response). + */ +typedef struct { + uint8_t inst_id; /**< Own service instance id */ + uint8_t peer_inst_id; /**< Peer's service instance id */ + uint8_t peer_mac[6]; /**< Peer's NAN Management Interface MAC */ + wifi_nan_pairing_status_t status; /**< Accepted, Rejected, or Comeback */ + uint16_t matched_method; /**< Matched bootstrapping method, one WIFI_NAN_BOOTSTRAP_* bit (valid if accepted) */ + uint8_t reason_code; /**< Rejection reason code (valid if rejected) */ + uint16_t comeback_after; /**< Comeback deferral time in TUs (only when status=COMEBACK) */ + uint32_t cookie; /**< Opaque cookie for comeback (only when status=COMEBACK) */ +} wifi_nan_pairing_bootstrapping_resp_t; + +/** + * @brief Send a NAN Pairing Bootstrapping request to a matched publisher + * + * @attention This API should be called by the Subscriber after a service match + * (WIFI_EVENT_NAN_SVC_MATCH) with a Publisher that has pairing enabled. + * The selected_method must match one of the methods advertised by the publisher. + * + * @param req Pairing bootstrapping request parameters. + * + * @return + * - ESP_OK: Bootstrapping request follow-up sent successfully + * - ESP_ERR_INVALID_ARG: Invalid parameters + * - ESP_FAIL: Failed to send + */ +esp_err_t esp_wifi_nan_bootstrap_request(wifi_nan_pairing_bootstrap_req_t *req); + +/** + * @brief Respond to a NAN Pairing Bootstrapping request from a peer + * + * @attention This API should be called by the Publisher after receiving a + * WIFI_EVENT_NAN_BOOTSTRAP_INDICATION event. + * + * @param resp Pairing bootstrapping response parameters. + * + * @return + * - ESP_OK: Bootstrapping response follow-up sent successfully + * - ESP_ERR_INVALID_ARG: Invalid parameters + * - ESP_FAIL: Failed to send + */ +esp_err_t esp_wifi_nan_bootstrap_response(wifi_nan_pairing_bootstrapping_resp_t *resp); + +/** + * @brief Start NAN Pairing process after credentials are shared Out-of-band + * + * @attention This API should be called after Bootstrapping is completed + * + * @param req Pairing setup parameters. + * + * @return + * - ESP_OK: Bootstrapping request follow-up sent successfully + * - ESP_ERR_INVALID_ARG: Invalid parameters + * - ESP_FAIL: Failed to send + */ +esp_err_t esp_wifi_nan_pairing_start(wifi_nan_pairing_config_t *cfg); + struct nan_pasn_data; + +/** + * @brief Get the NAN PASN context held by the NAN App. + * + * @return Pointer to the current NAN PASN data, or NULL if none is set. + */ struct nan_pasn_data *esp_nan_app_get_pasn_data(void); + +/** + * @brief Store the NAN PASN context in the NAN App. + * + * @attention Ownership is not transferred; the caller remains responsible for + * the lifetime of @p pd. Pass NULL to clear the stored context. + * + * @param pd Pointer to the NAN PASN data to store, or NULL to clear it. + */ void esp_nan_app_set_pasn_data(struct nan_pasn_data *pd); -//void esp_nan_app_post_pasn_pairing_indication(const wifi_event_nan_pasn_pairing_indication_t *evt); -//void esp_nan_app_post_pasn_pairing_confirm(const wifi_event_nan_pasn_pairing_confirm_t *evt); -#endif /* CONFIG_ESP_WIFI_PASN_SUPPORT */ + +#endif /* CONFIG_ESP_WIFI_NAN_PAIRING */ #ifdef __cplusplus } diff --git a/components/esp_wifi/wifi_apps/nan_app/include/esp_nan.h b/components/esp_wifi/wifi_apps/nan_app/include/esp_nan.h index df4b1fac425..a06f2199501 100644 --- a/components/esp_wifi/wifi_apps/nan_app/include/esp_nan.h +++ b/components/esp_wifi/wifi_apps/nan_app/include/esp_nan.h @@ -58,25 +58,6 @@ struct nan_peer_record { uint8_t peer_ndi[6]; /**< Peer's NAN Data Interface address, only valid when ndp_id is non-zero */ }; -#define NAN_PAIRING_PINCODE_MIN 000000 -#define NAN_PAIRING_PINCODE_MAX 999999 - -union pairing_cred_t { - uint32_t pincode; /**< 6-digit PIN in range of NAN_PAIRING_PINCODE_MIN to NAN_PAIRING_PINCODE_MAX */ -}; - -enum nan_pairing_role { - NAN_PAIRING_ROLE_INITIATOR, - NAN_PAIRING_ROLE_RESPONDER, -}; - -typedef struct { - uint8_t peer_svc_id; - uint8_t peer_nmi[6]; - enum nan_pairing_role self_role; - union pairing_cred_t cred; -} wifi_nan_pairing_config_t; - /** * @brief Start NAN Synchronization using the provided parameters. * @note Discovery traffic begins only after publish/subscribe services are started. @@ -197,97 +178,6 @@ esp_err_t esp_wifi_nan_get_peer_records(int *num_peer_records, uint8_t own_svc_i esp_err_t esp_wifi_nan_get_peer_info(char *svc_name, uint8_t *peer_mac, struct nan_peer_record *peer_info); -#ifdef CONFIG_ESP_WIFI_NAN_PAIRING - -/** - * @brief NAN Pairing Bootstrapping status values - */ -typedef enum { - WIFI_NAN_PAIRING_STATUS_ACCEPTED = 0, /**< Bootstrapping request accepted */ - WIFI_NAN_PAIRING_STATUS_REJECTED = 1, /**< Bootstrapping request rejected */ - WIFI_NAN_PAIRING_STATUS_COMEBACK = 2, /**< Comeback - responder needs more time */ -} wifi_nan_pairing_status_t; - -/** - * @brief NAN Pairing Bootstrapping Request parameters (initiator -> responder) - * - * Used by a subscriber (bootstrapping initiator) to send a bootstrapping - * request follow-up message with NPBA attribute (Type=Request) to a publisher. - */ -typedef struct { - uint8_t inst_id; /**< Own service instance id */ - uint8_t peer_inst_id; /**< Peer's service instance id */ - uint8_t peer_mac[6]; /**< Peer's NAN Management Interface MAC */ - uint16_t selected_method; /**< One selected WIFI_NAN_BOOTSTRAP_* method bit */ - wifi_nan_pairing_status_t status; /**< Set to COMEBACK when resending with cookie */ - uint16_t comeback_after; /**< Comeback deferral time in TUs (only when status=COMEBACK) */ - uint32_t cookie; /**< Opaque cookie from responder (only when status=COMEBACK) */ -} wifi_nan_pairing_bootstrap_req_t; - -/** - * @brief NAN Pairing Bootstrapping Response parameters (responder -> initiator) - * - * Used by a publisher (bootstrapping responder) to respond to a bootstrapping - * request follow-up message with NPBA attribute (Type=Response). - */ -typedef struct { - uint8_t inst_id; /**< Own service instance id */ - uint8_t peer_inst_id; /**< Peer's service instance id */ - uint8_t peer_mac[6]; /**< Peer's NAN Management Interface MAC */ - wifi_nan_pairing_status_t status; /**< Accepted, Rejected, or Comeback */ - uint16_t matched_method; /**< Matched bootstrapping method, one WIFI_NAN_BOOTSTRAP_* bit (valid if accepted) */ - uint8_t reason_code; /**< Rejection reason code (valid if rejected) */ - uint16_t comeback_after; /**< Comeback deferral time in TUs (only when status=COMEBACK) */ - uint32_t cookie; /**< Opaque cookie for comeback (only when status=COMEBACK) */ -} wifi_nan_pairing_bootstrapping_resp_t; - -/** - * @brief Send a NAN Pairing Bootstrapping request to a matched publisher - * - * @attention This API should be called by the Subscriber after a service match - * (WIFI_EVENT_NAN_SVC_MATCH) with a Publisher that has pairing enabled. - * The selected_method must match one of the methods advertised by the publisher. - * - * @param req Pairing bootstrapping request parameters. - * - * @return - * - ESP_OK: Bootstrapping request follow-up sent successfully - * - ESP_ERR_INVALID_ARG: Invalid parameters - * - ESP_FAIL: Failed to send - */ -esp_err_t esp_wifi_nan_bootstrap_request(wifi_nan_pairing_bootstrap_req_t *req); - -/** - * @brief Respond to a NAN Pairing Bootstrapping request from a peer - * - * @attention This API should be called by the Publisher after receiving a - * WIFI_EVENT_NAN_BOOTSTRAP_INDICATION event. - * - * @param resp Pairing bootstrapping response parameters. - * - * @return - * - ESP_OK: Bootstrapping response follow-up sent successfully - * - ESP_ERR_INVALID_ARG: Invalid parameters - * - ESP_FAIL: Failed to send - */ -esp_err_t esp_wifi_nan_bootstrap_response(wifi_nan_pairing_bootstrapping_resp_t *resp); - -/** - * @brief Start NAN Pairing process after credentials are shared Out-of-band - * - * @attention This API should be called after Bootstrapping is completed - * - * @param req Pairing setup parameters. - * - * @return - * - ESP_OK: Bootstrapping request follow-up sent successfully - * - ESP_ERR_INVALID_ARG: Invalid parameters - * - ESP_FAIL: Failed to send - */ -esp_err_t esp_wifi_nan_pairing_start(wifi_nan_pairing_config_t *cfg); - -#endif /* CONFIG_ESP_WIFI_NAN_PAIRING */ - #endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ #if defined(CONFIG_ESP_WIFI_NAN_SYNC_ENABLE) || defined(CONFIG_ESP_WIFI_NAN_USD_ENABLE) From e9c4cfa0a52bd59565f0fe0e55441abe3bc1f1b0 Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Wed, 10 Jun 2026 18:07:48 +0530 Subject: [PATCH 13/27] Add pairing followup timeout and post CONFIRM Failure --- .../esp_wifi/include/esp_wifi_types_generic.h | 7 +- .../include/injected/esp_wifi_types_generic.h | 7 +- .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 3 + .../esp_wifi/wifi_apps/nan_app/src/nan_i.h | 5 ++ .../wifi_apps/nan_app/src/nan_pairing.c | 80 ++++++++++++++++++- 5 files changed, 93 insertions(+), 9 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index 412c1a22b2e..fc80352a68c 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -1307,7 +1307,7 @@ typedef enum { WIFI_EVENT_NAN_BOOTSTRAP_INDICATION, /**< Received NAN Pairing Bootstrapping Request from a Peer */ WIFI_EVENT_NAN_BOOTSTRAP_COMPLETED, /**< NAN Pairing Bootstrapping completed (success/failure) */ WIFI_EVENT_NAN_PAIRING_INDICATION, /**< Received NAN Pairing indication (reserved) */ - WIFI_EVENT_NAN_PAIRING_CONFIRM, /**< NAN PASN pairwise key installation completed */ + WIFI_EVENT_NAN_PAIRING_CONFIRM, /**< NAN pairing completed after NIK follow-up exchange */ WIFI_EVENT_NAN_CLUSTER_JOIN, /**< NAN Cluster joined/started successfully */ WIFI_EVENT_MAX, /**< Invalid Wi-Fi event ID */ } wifi_event_t; @@ -1668,11 +1668,10 @@ typedef struct { uint32_t cookie; /**< Comeback cookie from responder (0 if none) */ } wifi_event_nan_bootstrap_complete_t; +#define WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT 1 /**< Peer NIK follow-up not received (Wi-Fi Aware v4.0 §7.6.4.2) */ + /** * @brief Argument structure for WIFI_EVENT_NAN_PAIRING_CONFIRM event - * - * Posted when PASN pairwise key installation completes. - * Distinct from WIFI_EVENT_NAN_BOOTSTRAP_COMPLETED (NPBA follow-up bootstrapping). */ typedef struct { uint8_t status; /**< 0=Accepted, 1=Rejected (wifi_nan_pairing_status_t) */ diff --git a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h index 266a5027bf3..cf66ba38bfb 100644 --- a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h +++ b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h @@ -1307,7 +1307,7 @@ typedef enum { WIFI_EVENT_NAN_BOOTSTRAP_INDICATION, /**< Received NAN Pairing Bootstrapping Request from a Peer */ WIFI_EVENT_NAN_BOOTSTRAP_COMPLETED, /**< NAN Pairing Bootstrapping completed (success/failure) */ WIFI_EVENT_NAN_PAIRING_INDICATION, /**< Received NAN Pairing indication (reserved) */ - WIFI_EVENT_NAN_PAIRING_CONFIRM, /**< NAN PASN pairwise key installation completed */ + WIFI_EVENT_NAN_PAIRING_CONFIRM, /**< NAN pairing completed after NIK follow-up exchange */ WIFI_EVENT_NAN_CLUSTER_JOIN, /**< NAN Cluster joined/started successfully */ WIFI_EVENT_MAX, /**< Invalid Wi-Fi event ID */ } wifi_event_t; @@ -1668,11 +1668,10 @@ typedef struct { uint32_t cookie; /**< Comeback cookie from responder (0 if none) */ } wifi_event_nan_bootstrap_complete_t; +#define WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT 1 /**< Peer NIK follow-up not received (Wi-Fi Aware v4.0 §7.6.4.2) */ + /** * @brief Argument structure for WIFI_EVENT_NAN_PAIRING_CONFIRM event - * - * Posted when PASN pairwise key installation completes. - * Distinct from WIFI_EVENT_NAN_BOOTSTRAP_COMPLETED (NPBA follow-up bootstrapping). */ typedef struct { uint8_t status; /**< 0=Accepted, 1=Rejected (wifi_nan_pairing_status_t) */ diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c index 347b643c92f..91e89555a88 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c @@ -414,6 +414,9 @@ static void nan_reset_service(uint8_t svc_id, bool reset_all) while (idx < ESP_WIFI_NAN_MAX_SVC_SUPPORTED) { p_own_svc = &s_nan_ctx.own_svc[idx++]; if (reset_all || (svc_id && p_own_svc->svc_id == svc_id)) { +#ifdef CONFIG_ESP_WIFI_NAN_PAIRING + nan_pairing_cancel_svc_pending(p_own_svc); +#endif SLIST_FOREACH_SAFE(p_peer_svc, &(p_own_svc->peer_list), next, temp) { SLIST_REMOVE(&(p_own_svc->peer_list), p_peer_svc, peer_svc_info, next); os_free(p_peer_svc); diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h index c58587ec7aa..40976b5e45c 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h @@ -223,6 +223,10 @@ struct own_svc_info { #endif uint8_t num_peer_records; SLIST_HEAD(peer_list_t, peer_svc_info) peer_list; +#if CONFIG_ESP_WIFI_NAN_PAIRING + bool nik_fup_pending; + uint8_t nik_fup_pending_peer_nmi[MACADDR_LEN]; +#endif }; /* Per-NDP link state */ @@ -340,6 +344,7 @@ void nan_app_bootstrap_completed(uint8_t status, uint8_t peer_svc_id, uint8_t su uint8_t reason_code); bool nan_app_parse_npba_from_receive(uint8_t own_svc_id, uint8_t peer_svc_id, uint8_t peer_nmi[6], const struct nan_cb_npba_t *npba); +void nan_pairing_cancel_svc_pending(struct own_svc_info *own); #endif /* CONFIG_ESP_WIFI_NAN_PAIRING */ #ifdef CONFIG_ESP_WIFI_NAN_SECURITY diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index 73fcc571539..d20763947f7 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -400,6 +400,7 @@ int esp_nan_construct_nira(uint8_t *frm) #define NAN_PAIRING_SRV_PORT 3333 #define NAN_PAIRING_SRV_HOSTNAME "ESP-SRV-1234" #define NAN_PAIRING_SSI_BUF_LEN 64 +#define NAN_PAIRING_NIK_FUP_TIMEOUT_SEC 2 struct nan_pairing_fup_ctx { uint8_t svc_id; @@ -437,6 +438,56 @@ static struct peer_svc_info *nan_find_peer_svc_exact(uint8_t own_svc_id, uint8_t return NULL; } +static void nan_pairing_nik_fup_timeout_cb(void *eloop_data, void *user_ctx); + +void nan_pairing_cancel_svc_pending(struct own_svc_info *own) +{ + if (!own || !own->nik_fup_pending) { + return; + } + + eloop_cancel_timeout(nan_pairing_nik_fup_timeout_cb, NULL, own); + own->nik_fup_pending = false; +} + +static void nan_pairing_arm_pending(struct own_svc_info *own, const uint8_t *peer_mac) +{ + if (!own || !peer_mac) { + return; + } + + nan_pairing_cancel_svc_pending(own); + MACADDR_COPY(own->nik_fup_pending_peer_nmi, peer_mac); + own->nik_fup_pending = true; + + if (eloop_register_timeout(NAN_PAIRING_NIK_FUP_TIMEOUT_SEC, 0, + nan_pairing_nik_fup_timeout_cb, NULL, + own) != 0) { + own->nik_fup_pending = false; + } +} + +static void nan_pairing_nik_fup_timeout_cb(void *eloop_data, void *user_ctx) +{ + struct own_svc_info *own = user_ctx; + wifi_event_nan_pairing_complete_t evt = {0}; + + (void)eloop_data; + + if (!own || !own->nik_fup_pending) { + return; + } + + own->nik_fup_pending = false; + evt.status = WIFI_NAN_PAIRING_STATUS_REJECTED; + evt.reason_code = WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT; + MACADDR_COPY(evt.peer_nmi, own->nik_fup_pending_peer_nmi); + esp_nan_disable_pairing(own->svc_id); + nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); + ESP_LOGW(TAG, "Pairing NIK follow-up timed out for peer " MACSTR, + MAC2STR(own->nik_fup_pending_peer_nmi)); +} + /** * Build the WFA OUI + GSP protocol header that prefixes a Generic Service * Protocol SSI (Wi-Fi Aware v4.0 §4.2.7). Ported from esp-nsd @@ -828,13 +879,35 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, MACADDR_COPY(ctx->peer_mac, peer_nmi); ctx->shared_key_attr_len = 0; + struct own_svc_info *own = nan_find_own_svc(ctx->svc_id); + if (own) { + nan_pairing_arm_pending(own, peer_nmi); + } + if (eloop_register_timeout(0, 0, nan_app_send_pairing_followup_eloop, NULL, ctx) != 0) { ESP_LOGW(TAG, "Pairing key installed: failed to schedule initiator follow-up"); + if (own) { + nan_pairing_cancel_svc_pending(own); + } os_free(ctx); } return; } - (void)role; + + if (role == NAN_ROLE_PAIRING_RESPONDER) { + struct own_svc_info *own = NULL; + + NAN_DATA_LOCK(); + struct peer_svc_info *peer = nan_find_peer_svc(0, 0, (uint8_t *)peer_nmi); + if (peer) { + own = nan_find_own_svc(peer->own_svc_id); + } + NAN_DATA_UNLOCK(); + + if (own) { + nan_pairing_arm_pending(own, peer_nmi); + } + } } void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, @@ -903,6 +976,11 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, /* Invoke blocking calls outside NAN_DATA_LOCK to avoid deadlock. */ if (pairing_completed) { wifi_event_nan_pairing_complete_t evt = {0}; + + struct own_svc_info *own = nan_find_own_svc(own_svc_id_to_disable); + if (own) { + nan_pairing_cancel_svc_pending(own); + } evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; evt.reason_code = 0; MACADDR_COPY(evt.peer_nmi, peer_mac); From e70033e6a7c22a85982fbad2474dc4478b29c391 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Thu, 11 Jun 2026 17:40:46 +0530 Subject: [PATCH 14/27] refactor(nan): consolidate NIRA construction into esp_nan_construct_nira --- .../wifi_apps/nan_app/src/nan_pairing.c | 155 ++++++------------ 1 file changed, 46 insertions(+), 109 deletions(-) diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index d20763947f7..1fe18bb918d 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -301,6 +301,47 @@ uint32_t esp_nan_get_nira_len(void) return NAN_NIRA_ATTR_LEN; } +/** + * Derive a NIRA tag for cipher version 0 (Wi-Fi Aware v4.0): + * Tag = Truncate-64(HMAC-SHA-256(NIK, "NIR" || NMI || Nonce)) + * + * Ported from hostap @c nan_crypto_derive_nira_tag (src/nan/nan_crypto.c), + * adapted to the ESP-IDF crypto trampoline. + */ +static int nan_pairing_derive_nira_tag(const uint8_t nik[NAN_PASN_NIK_LEN], + const uint8_t nmi_addr[ETH_ALEN], + const uint8_t nira_nonce[NAN_NIRA_NONCE_LEN], + uint8_t tag_out[NAN_NIRA_TAG_LEN]) +{ + const unsigned char *addr[3]; + int len_arr[3]; + uint8_t digest[32]; + + if (!nik || !nmi_addr || !nira_nonce || !tag_out) { + return -1; + } + if (!g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector) { + return -1; + } + + addr[0] = (const unsigned char *)NAN_NIRA_STR; + len_arr[0] = NAN_NIRA_STR_LEN; + addr[1] = nmi_addr; + len_arr[1] = ETH_ALEN; + addr[2] = nira_nonce; + len_arr[2] = NAN_NIRA_NONCE_LEN; + + if (g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector(nik, NAN_PASN_NIK_LEN, + 3, addr, len_arr, + digest) != 0) { + return -1; + } + + memcpy(tag_out, digest, NAN_NIRA_TAG_LEN); + memset(digest, 0, sizeof(digest)); + return 0; +} + int esp_nan_construct_nira(uint8_t *frm) { const uint8_t *nonce; @@ -312,24 +353,16 @@ int esp_nan_construct_nira(uint8_t *frm) return 0; } -#ifdef CONFIG_ESP_WIFI_NAN_SECURITY if (s_nan_ctx.nira_cached) { nonce = s_nan_ctx.cached_nira_nonce; tag = s_nan_ctx.cached_nira_tag; } else { uint8_t own_nmi[MACADDR_LEN]; - const unsigned char *addr[3]; - int len_arr[3]; - uint8_t digest[32]; if (!s_nan_ctx.own_nik_valid) { ESP_LOGW(TAG, "NIRA: own NIK is not available"); return 0; } - if (!g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector) { - ESP_LOGE(TAG, "NIRA: hmac_sha256_vector not registered"); - return 0; - } if (esp_wifi_get_mac(WIFI_IF_NAN, own_nmi) != ESP_OK) { ESP_LOGE(TAG, "NIRA: failed to read NAN NMI"); return 0; @@ -338,23 +371,12 @@ int esp_nan_construct_nira(uint8_t *frm) ESP_LOGE(TAG, "NIRA: failed to generate nonce"); return 0; } - /* Tag = Truncate-64(HMAC-SHA-256(NIK, "NIR" || NMI || Nonce)) */ - addr[0] = (const unsigned char *)NAN_NIRA_STR; - len_arr[0] = NAN_NIRA_STR_LEN; - addr[1] = own_nmi; - len_arr[1] = MACADDR_LEN; - addr[2] = fresh_nonce; - len_arr[2] = NAN_NIRA_NONCE_LEN; - if (g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector(s_nan_ctx.own_nik, - ESP_WIFI_NAN_NIK_LEN, - 3, addr, len_arr, - digest) != 0) { + if (nan_pairing_derive_nira_tag(s_nan_ctx.own_nik, own_nmi, + fresh_nonce, fresh_tag) != 0) { ESP_LOGE(TAG, "NIRA: tag derivation failed"); return 0; } - memcpy(fresh_tag, digest, NAN_NIRA_TAG_LEN); - memset(digest, 0, sizeof(digest)); memcpy(s_nan_ctx.cached_nira_nonce, fresh_nonce, NAN_NIRA_NONCE_LEN); memcpy(s_nan_ctx.cached_nira_tag, fresh_tag, NAN_NIRA_TAG_LEN); @@ -363,10 +385,6 @@ int esp_nan_construct_nira(uint8_t *frm) nonce = fresh_nonce; tag = fresh_tag; } -#else - /* NIRA requires an available NIK; skip when NAN security is not enabled. */ - return 0; -#endif uint8_t *p = frm; *p++ = NAN_ATTR_ID_IDENTITY_RESOLUTION; @@ -553,82 +571,6 @@ static size_t nan_pairing_build_srv_ssi(uint8_t *buf, size_t buf_len, return (size_t)(p - buf); } -/** - * Derive a NIRA tag for cipher version 0 (Wi-Fi Aware v4.0): - * Tag = Truncate-64(HMAC-SHA-256(NIK, "NIR" || NMI || Nonce)) - * - * Ported from hostap @c nan_crypto_derive_nira_tag (src/nan/nan_crypto.c), - * adapted to the ESP-IDF crypto trampoline. - */ -static int nan_pairing_derive_nira_tag(const uint8_t nik[NAN_PASN_NIK_LEN], - const uint8_t nmi_addr[ETH_ALEN], - const uint8_t nira_nonce[NAN_NIRA_NONCE_LEN], - uint8_t tag_out[NAN_NIRA_TAG_LEN]) -{ - const unsigned char *addr[3]; - int len_arr[3]; - uint8_t digest[32]; - - if (!nik || !nmi_addr || !nira_nonce || !tag_out) { - return -1; - } - if (!g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector) { - return -1; - } - - addr[0] = (const unsigned char *)NAN_NIRA_STR; - len_arr[0] = NAN_NIRA_STR_LEN; - addr[1] = nmi_addr; - len_arr[1] = ETH_ALEN; - addr[2] = nira_nonce; - len_arr[2] = NAN_NIRA_NONCE_LEN; - - if (g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector(nik, NAN_PASN_NIK_LEN, - 3, addr, len_arr, - digest) != 0) { - return -1; - } - - memcpy(tag_out, digest, NAN_NIRA_TAG_LEN); - memset(digest, 0, sizeof(digest)); - return 0; -} - -/** - * Build a NIRA attribute (ID 0x2B) into @a buf using the NIK and our NMI. - * Returns total attribute length on success, 0 on failure. - */ -static size_t nan_pairing_build_nira_attr(uint8_t *buf, size_t buf_len, - const uint8_t nik[NAN_PASN_NIK_LEN], - const uint8_t nmi_addr[ETH_ALEN]) -{ - uint8_t nonce[NAN_NIRA_NONCE_LEN]; - uint8_t tag[NAN_NIRA_TAG_LEN]; - uint8_t *p = buf; - - if (!buf || !nik || !nmi_addr || buf_len < NAN_NIRA_ATTR_LEN) { - return 0; - } - if (os_get_random(nonce, sizeof(nonce)) != 0) { - return 0; - } - if (nan_pairing_derive_nira_tag(nik, nmi_addr, nonce, tag) != 0) { - return 0; - } - - *p++ = NAN_ATTR_ID_IDENTITY_RESOLUTION; - /* Attribute Length (LE16): CipherVersion(1) + Nonce(8) + Tag(8) = 17 */ - WPA_PUT_LE16(p, 1 + NAN_NIRA_NONCE_LEN + NAN_NIRA_TAG_LEN); - p += 2; - *p++ = NAN_NIRA_CIPHER_VER; - memcpy(p, nonce, NAN_NIRA_NONCE_LEN); - p += NAN_NIRA_NONCE_LEN; - memcpy(p, tag, NAN_NIRA_TAG_LEN); - p += NAN_NIRA_TAG_LEN; - - return (size_t)(p - buf); -} - static size_t nan_pairing_build_plain_key_data(uint8_t *buf, size_t buf_len, const uint8_t nik[NAN_PASN_NIK_LEN]) { @@ -696,7 +638,6 @@ static esp_err_t nan_app_send_pairing_followup(uint8_t svc_id, uint8_t peer_svc_ uint8_t shared_key_wrapped[sizeof(struct wpa_eapol_key) + sizeof(wrapped)] = {0}; uint8_t nira_attr[NAN_NIRA_ATTR_LEN] = {0}; uint8_t srv_ssi[NAN_PAIRING_SSI_BUF_LEN] = {0}; - uint8_t our_nmi[ETH_ALEN] = {0}; uint8_t nik[NAN_PASN_NIK_LEN]; size_t plain_len; size_t wrapped_len; @@ -784,13 +725,9 @@ static esp_err_t nan_app_send_pairing_followup(uint8_t svc_id, uint8_t peer_svc_ /* NIRA proves possession of the NIK we just wrapped above; iPhone uses * it to bind the NIK to the sender and won't commit the pairing record - * without it. */ - if (esp_wifi_get_mac(WIFI_IF_NAN, our_nmi) != ESP_OK) { - ESP_LOGW(TAG, "Pairing follow-up: cannot read NAN NMI for NIRA"); - return ESP_FAIL; - } - nira_len = nan_pairing_build_nira_attr(nira_attr, sizeof(nira_attr), - nik, our_nmi); + * without it. esp_nan_construct_nira() reuses the same cached nonce/tag we + * advertise in sync discovery. */ + nira_len = (size_t)esp_nan_construct_nira(nira_attr); if (nira_len == 0) { ESP_LOGW(TAG, "Pairing follow-up: NIRA attribute build failed"); return ESP_FAIL; From ebf7dc9b31bf90e175216dc8a56fd0f5b990e2f6 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Thu, 11 Jun 2026 11:25:31 +0530 Subject: [PATCH 15/27] feat(nan): persist NIK/NPK credentials in NVS Replace nik/nik_valid in wifi_nan_sync_config_t with reset_current_nvs_creds and use_nvs_for_caching. On NAN start, load the saved own NIK and peer credentials from NVS (or erase them when reset is requested); generate and persist a fresh own NIK only when none is valid and caching is enabled. PASN reuses the SAE module (PWE/crypto and the comeback-token mechanism), so define CONFIG_SAE whenever SoftAP-SAE or PASN is enabled. This fixes the undefined references to check_comeback_token()/auth_build_token_req() when SOFTAP config is disabled. --- .../esp_wifi/include/esp_wifi_types_generic.h | 7 +- .../include/injected/esp_wifi_types_generic.h | 7 +- .../wifi_apps/nan_app/include/esp_nan.h | 3 +- .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 25 +++++- .../esp_wifi/wifi_apps/nan_app/src/nan_i.h | 8 ++ .../wifi_apps/nan_app/src/nan_pairing.c | 80 +++++++++++++++---- components/wpa_supplicant/CMakeLists.txt | 6 +- .../esp_supplicant/src/esp_wifi_driver.h | 12 +++ .../esp_supplicant/src/esp_wpa3.c | 8 +- .../esp_supplicant/src/esp_wpa3_i.h | 10 ++- components/wpa_supplicant/src/ap/ieee802_11.c | 7 +- 11 files changed, 139 insertions(+), 34 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index fc80352a68c..f3abe1aefcf 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -604,9 +604,8 @@ typedef struct { uint8_t scan_time; /**< Scan time in seconds while searching for a NAN cluster */ uint16_t warm_up_sec; /**< Warm up time before assuming NAN Anchor Master role */ bool disable_random_mac;/**< Disable the MAC Randomisation in NAN */ - uint8_t nik[ESP_WIFI_NAN_NIK_LEN]; /**< Optional NIK. Auto-generated when nik_valid is false. */ - uint8_t nik_valid: 1; /**< NIK present in nik[] and should be used as-is. */ - uint8_t reserved: 7; /**< Reserved for future use. */ + bool reset_current_nvs_creds; /**< Erase all NAN credentials (own NIK and cached peer NIK/NPK entries) saved in NVS before starting. */ + bool use_nvs_for_caching; /**< Persist newly-learned peer credentials (NIK/NPK) to NVS so they survive across reboots. */ } wifi_nan_sync_config_t; /** @@ -874,7 +873,9 @@ typedef struct { #define ESP_WIFI_NDP_ROLE_RESPONDER 2 /**< Responder role for NAN Data Path */ #define ESP_WIFI_NAN_NDP_PMK_LEN 32 /**< Length of NAN Datapath PMK */ +#define ESP_WIFI_NAN_NPK_LEN ESP_WIFI_NAN_NDP_PMK_LEN /**< Length of NAN Pairwise Key (same as NDP PMK) */ #define ESP_WIFI_NAN_NDP_PMKID_LEN 16 /**< Length of NAN Datapath PMKID */ +#define ESP_WIFI_NAN_MAX_PEER_CREDS 2 /**< nik_valid) { - memcpy(s_nan_ctx.own_nik, nan_cfg->nik, ESP_WIFI_NAN_NIK_LEN); - s_nan_ctx.own_nik_valid = true; - } else { + s_nan_ctx.own_nik_valid = false; + s_nan_ctx.num_peer_creds = 0; + memset(s_nan_ctx.peer_creds, 0, sizeof(s_nan_ctx.peer_creds)); + s_nan_ctx.use_nvs_for_caching = nan_cfg->use_nvs_for_caching; + + if (nan_cfg->reset_current_nvs_creds) { + /* Start from a clean slate: drop every credential persisted in NVS. */ + esp_wifi_nan_erase_all_creds(); + } else if (esp_wifi_nan_load_saved_creds(s_nan_ctx.own_nik, &s_nan_ctx.own_nik_valid, + s_nan_ctx.peer_creds, &s_nan_ctx.num_peer_creds) != ESP_OK) { + ESP_LOGW(TAG, "Failed to load saved NAN credentials"); + s_nan_ctx.own_nik_valid = false; + s_nan_ctx.num_peer_creds = 0; + } + + if (!s_nan_ctx.own_nik_valid) { if (os_get_random(s_nan_ctx.own_nik, ESP_WIFI_NAN_NIK_LEN) != 0) { NAN_DATA_UNLOCK(); ESP_LOGE(TAG, "Failed to generate NAN NIK"); return ESP_FAIL; } s_nan_ctx.own_nik_valid = true; + /* Persist the freshly generated NIK only when NVS caching is enabled; + * otherwise the identity stays ephemeral for this session. */ + if (s_nan_ctx.use_nvs_for_caching) { + esp_wifi_nan_save_own_nik(s_nan_ctx.own_nik); + } } /* Drop the cached NIRA tag; it was derived from the previous NIK. */ s_nan_ctx.nira_cached = false; diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h index 40976b5e45c..25a0df128fd 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h @@ -17,6 +17,8 @@ #include "esp_wifi_types_generic.h" #include "esp_private/wifi.h" #include "esp_nan.h" +#include "utils/common.h" /* u8/u16 typedefs required by esp_wifi_driver.h */ +#include "esp_wifi_driver.h" /* wifi_nan_peer_creds_t + NAN credential NVS APIs */ #include "os.h" #ifdef __cplusplus @@ -296,6 +298,12 @@ typedef struct { uint8_t cached_nira_nonce[8]; uint8_t cached_nira_tag[8]; bool nira_cached; + /* Peer NIK/NPK credentials loaded from NVS at start and refreshed as peers + * are paired. Drives NIRA identity resolution; optionally persisted to NVS + * when @c use_nvs_for_caching is set. */ + wifi_nan_peer_creds_t peer_creds[ESP_WIFI_NAN_MAX_PEER_CREDS]; + uint8_t num_peer_creds; + bool use_nvs_for_caching; #endif #ifdef CONFIG_ESP_WIFI_PASN_SUPPORT struct nan_pasn_data *nan_pasn_data; diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index 1fe18bb918d..758c876c283 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -847,6 +847,39 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, } } +/* Insert or refresh a (peer NIK, NPK) entry in the in-RAM credential cache used + * for NIRA identity resolution. Caller holds NAN_DATA_LOCK. A @a npk of NULL + * stores a zeroed key. When the cache is full the oldest entry (slot 0) is + * reused. */ +static void nan_app_update_peer_creds(const uint8_t *peer_nik, const uint8_t *npk) +{ + wifi_nan_peer_creds_t *slot = NULL; + + /* Reuse the slot already holding this NIK, if any. */ + for (uint8_t i = 0; i < s_nan_ctx.num_peer_creds; i++) { + if (s_nan_ctx.peer_creds[i].is_valid && + os_memcmp(s_nan_ctx.peer_creds[i].peer_nik, peer_nik, ESP_WIFI_NAN_NIK_LEN) == 0) { + slot = &s_nan_ctx.peer_creds[i]; + break; + } + } + if (!slot) { + if (s_nan_ctx.num_peer_creds < ESP_WIFI_NAN_MAX_PEER_CREDS) { + slot = &s_nan_ctx.peer_creds[s_nan_ctx.num_peer_creds++]; + } else { + slot = &s_nan_ctx.peer_creds[0]; + } + } + + memcpy(slot->peer_nik, peer_nik, ESP_WIFI_NAN_NIK_LEN); + if (npk) { + memcpy(slot->npk, npk, ESP_WIFI_NAN_NPK_LEN); + } else { + memset(slot->npk, 0, ESP_WIFI_NAN_NPK_LEN); + } + slot->is_valid = true; +} + void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, const uint8_t *peer_mac, const uint8_t *shared_key_attr, @@ -891,6 +924,8 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, bool already_had_nik = false; bool pairing_completed = false; uint8_t own_svc_id_to_disable = 0; + bool persist_creds = false; + uint8_t persist_npk[ESP_WIFI_NAN_NPK_LEN] = {0}; NAN_DATA_LOCK(); struct peer_svc_info *p_peer_svc = nan_find_peer_svc_exact(svc_id, peer_svc_id, peer_mac); @@ -903,6 +938,15 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, ESP_LOGI(TAG, "Stored peer NIK from " MACSTR " (cipher_ver=%u, lifetime=%u s)", MAC2STR(peer_mac), cipher_ver, lifetime_sec); + /* Refresh the NIRA credential cache with this peer's NIK and, if the + * pairing record is available, its NPK. */ + const struct nan_paired_peer *paired = nan_app_find_paired_peer(peer_mac); + if (paired) { + memcpy(persist_npk, paired->nd_pmk, ESP_WIFI_NAN_NPK_LEN); + } + nan_app_update_peer_creds(nik, paired ? paired->nd_pmk : NULL); + persist_creds = s_nan_ctx.use_nvs_for_caching; + if (!already_had_nik) { pairing_completed = true; own_svc_id_to_disable = p_peer_svc->own_svc_id; @@ -910,6 +954,11 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, } NAN_DATA_UNLOCK(); + /* Persist outside the lock; NVS writes can block. */ + if (persist_creds) { + esp_wifi_nan_save_creds_for_peer(nik, persist_npk); + } + /* Invoke blocking calls outside NAN_DATA_LOCK to avoid deadlock. */ if (pairing_completed) { wifi_event_nan_pairing_complete_t evt = {0}; @@ -959,8 +1008,7 @@ bool esp_nan_verify_nira(uint8_t *peer_mac, uint8_t *nira_attr, uint16_t nira_at uint8_t expected_tag[NAN_NIRA_TAG_LEN]; const uint8_t *nonce; const uint8_t *received_tag; - struct peer_svc_info *p_peer_svc; - bool match; + bool match = false; if (!peer_mac || !nira_attr) { return false; @@ -975,26 +1023,28 @@ bool esp_nan_verify_nira(uint8_t *peer_mac, uint8_t *nira_attr, uint16_t nira_at nonce = nira_attr + 4; received_tag = nira_attr + 4 + NAN_NIRA_NONCE_LEN; + /* The peer derives its NIRA tag from one of its NIKs; the sending MAC may be + * randomised, so resolve the identity by trying every cached peer NIK. */ NAN_DATA_LOCK(); - p_peer_svc = nan_find_peer_svc(0, 0, peer_mac); - if (!p_peer_svc || !p_peer_svc->has_nik) { - NAN_DATA_UNLOCK(); - ESP_LOGD(TAG, "NIRA verify: no stored NIK for "MACSTR, MAC2STR(peer_mac)); - return false; - } - - if (nan_pairing_derive_nira_tag(p_peer_svc->peer_nik, peer_mac, nonce, expected_tag) != 0) { - NAN_DATA_UNLOCK(); - ESP_LOGE(TAG, "NIRA verify: tag derivation failed for "MACSTR, MAC2STR(peer_mac)); - return false; + for (uint8_t i = 0; i < s_nan_ctx.num_peer_creds; i++) { + if (!s_nan_ctx.peer_creds[i].is_valid) { + continue; + } + if (nan_pairing_derive_nira_tag(s_nan_ctx.peer_creds[i].peer_nik, peer_mac, + nonce, expected_tag) != 0) { + continue; + } + if (os_memcmp_const(expected_tag, received_tag, NAN_NIRA_TAG_LEN) == 0) { + match = true; + break; + } } NAN_DATA_UNLOCK(); - match = (os_memcmp_const(expected_tag, received_tag, NAN_NIRA_TAG_LEN) == 0); if (match) { ESP_LOGD(TAG, "NIRA verify: OK for "MACSTR, MAC2STR(peer_mac)); } else { - ESP_LOGW(TAG, "NIRA verify: tag mismatch for "MACSTR, MAC2STR(peer_mac)); + ESP_LOGW(TAG, "NIRA verify: no matching NIK for "MACSTR, MAC2STR(peer_mac)); } return match; } diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 8a9b5829334..85eef8e5246 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -314,7 +314,11 @@ endif() if(CONFIG_ESP_WIFI_ENABLE_SAE_H2E) target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_SAE_H2E) endif() -if(CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT) +# PASN reuses the SAE module (PWE/crypto + comeback-token mechanism), so +# CONFIG_SAE must be defined whenever SoftAP-SAE or PASN is enabled. AP-side SAE +# authentication paths are additionally gated on CONFIG_ESP_WIFI_SOFTAP_SUPPORT +# in the sources so they stay out of PASN-only (SoftAP-disabled) builds. +if(CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT OR CONFIG_ESP_WIFI_PASN_SUPPORT) target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_SAE) endif() if(CONFIG_ESP_WIFI_WPA3_COMPATIBLE_SUPPORT) diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h index 59fd3c62d98..8d6c7382070 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -240,6 +240,12 @@ typedef enum { NAN_KEY_NM_TK, } nan_key_type_t; +typedef struct { + uint8_t peer_nik[ESP_WIFI_NAN_NIK_LEN]; /**< Peer's NAN Identity Key (16 bytes) */ + uint8_t npk[ESP_WIFI_NAN_NPK_LEN]; /**< NAN Pairwise Key / NCS-SK PMK (32 bytes) */ + bool is_valid; +} wifi_nan_peer_creds_t; + typedef wifi_scan_channel_bitmap_t channel_bitmap_t; uint8_t *esp_wifi_ap_get_prof_pmk_internal(void); @@ -335,5 +341,11 @@ uint8_t esp_wifi_op_class_supported_internal(uint8_t op_class, uint8_t min_chan, bool esp_wifi_is_wpa3_compatible_mode_enabled(uint8_t if_index); uint8_t esp_wifi_ap_get_owe_config_internal(void); esp_err_t esp_nan_disable_pairing(uint8_t svc_id); +esp_err_t esp_wifi_nan_load_saved_creds(uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN], bool *own_nik_valid, + wifi_nan_peer_creds_t peer_creds[ESP_WIFI_NAN_MAX_PEER_CREDS], uint8_t *num_peer_creds); +esp_err_t esp_wifi_nan_save_own_nik(const uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN]) ; +esp_err_t esp_wifi_nan_save_creds_for_peer(const uint8_t peer_nik[ESP_WIFI_NAN_NIK_LEN], + const uint8_t npk[ESP_WIFI_NAN_NPK_LEN]); +esp_err_t esp_wifi_nan_erase_all_creds(void); #endif /* _ESP_WIFI_DRIVER_H_ */ diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c index 895955d6d28..32430eb7445 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c @@ -441,7 +441,11 @@ void esp_wifi_unregister_wpa3_cb(void) } #endif /* CONFIG_WPA3_SAE */ -#ifdef CONFIG_SAE +/* AP-side (hostap) SAE authentication. CONFIG_SAE may also be enabled for PASN + * with SoftAP disabled, but this block both defines and calls SoftAP-only + * primitives (esp_send_sae_auth_reply, handle_auth_sae), so additionally gate + * it on CONFIG_ESP_WIFI_SOFTAP_SUPPORT. */ +#if defined(CONFIG_SAE) && defined(CONFIG_ESP_WIFI_SOFTAP_SUPPORT) static TaskHandle_t g_wpa3_hostap_task_hdl = NULL; static QueueHandle_t g_wpa3_hostap_evt_queue = NULL; @@ -861,4 +865,4 @@ void esp_wifi_register_wpa3_ap_cb(struct wpa_funcs *wpa_cb) wpa_cb->wpa3_hostap_handle_auth = wpa3_hostap_handle_auth; } -#endif /* CONFIG_SAE */ +#endif /* CONFIG_SAE && CONFIG_ESP_WIFI_SOFTAP_SUPPORT */ diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa3_i.h b/components/wpa_supplicant/esp_supplicant/src/esp_wpa3_i.h index 9f5e49018d2..26486207e3b 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa3_i.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa3_i.h @@ -6,6 +6,7 @@ #ifndef ESP_WPA3_H #define ESP_WPA3_H +#include "sdkconfig.h" #include "esp_wifi_driver.h" #ifdef CONFIG_WPA3_SAE @@ -27,7 +28,10 @@ static inline void esp_wpa3_free_sae_data(void) #endif /* CONFIG_WPA3_SAE */ -#ifdef CONFIG_SAE +/* AP-side (hostap) SAE definitions require SoftAP; CONFIG_SAE alone may be set + * for PASN. The #else branch provides a no-op esp_wifi_register_wpa3_ap_cb() + * stub so callers link in PASN-only (SoftAP-disabled) builds. */ +#if defined(CONFIG_SAE) && defined(CONFIG_ESP_WIFI_SOFTAP_SUPPORT) enum SIG_WPA3_TASK { SIG_WPA3_RX_COMMIT, SIG_WPA3_RX_CONFIRM, @@ -58,12 +62,12 @@ void esp_wifi_register_wpa3_ap_cb(struct wpa_funcs *wpa_cb); int wpa3_hostap_auth_init(void *data); bool wpa3_hostap_auth_deinit(void); -#else /* CONFIG_SAE */ +#else /* CONFIG_SAE && CONFIG_ESP_WIFI_SOFTAP_SUPPORT */ static inline void esp_wifi_register_wpa3_ap_cb(struct wpa_funcs *wpa_cb) { wpa_cb->wpa3_hostap_handle_auth = NULL; } -#endif /* CONFIG_SAE */ +#endif /* CONFIG_SAE && CONFIG_ESP_WIFI_SOFTAP_SUPPORT */ #endif /* ESP_WPA3_H */ diff --git a/components/wpa_supplicant/src/ap/ieee802_11.c b/components/wpa_supplicant/src/ap/ieee802_11.c index 99327c8acbb..4ba44dad40e 100644 --- a/components/wpa_supplicant/src/ap/ieee802_11.c +++ b/components/wpa_supplicant/src/ap/ieee802_11.c @@ -28,7 +28,10 @@ #define OWE_DH_GRP19 19 #endif -#ifdef CONFIG_SAE +/* AP-side SAE authentication. Requires SoftAP: CONFIG_SAE may also be enabled + * for PASN (SoftAP disabled), but this block calls SoftAP-only primitives + * (e.g. esp_send_sae_auth_reply), so gate it on CONFIG_ESP_WIFI_SOFTAP_SUPPORT. */ +#if defined(CONFIG_SAE) && defined(CONFIG_ESP_WIFI_SOFTAP_SUPPORT) static void sae_set_state(struct sta_info *sta, enum sae_state state, const char *reason) @@ -778,7 +781,7 @@ queued: } -#endif /* CONFIG_SAE */ +#endif /* CONFIG_SAE && CONFIG_ESP_WIFI_SOFTAP_SUPPORT */ u16 wpa_res_to_status_code(enum wpa_validate_result res) { From f3c2ff40193299214fb4df066b020e37e1a4ab7d Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Thu, 11 Jun 2026 16:47:20 +0530 Subject: [PATCH 16/27] fix(nan): Disable/Enable Pairing setup bit based on NIK stored in NVS - Only send pairing followup only if nik caching is enabled --- .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 16 +++++++++-- .../esp_wifi/wifi_apps/nan_app/src/nan_i.h | 3 ++ .../wifi_apps/nan_app/src/nan_pairing.c | 28 +++++++++++++++---- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c index 4c54176d516..76879988a70 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c @@ -462,7 +462,7 @@ static bool nan_services_limit_reached(void) #define NAN_SVC_ID_PENDING 0xFF static struct own_svc_info *nan_claim_own_svc_slot(uint8_t type, const char svc_name[], - const wifi_nan_discovery_security_params_t *security_cfg) + const wifi_nan_discovery_security_params_t *security_cfg, wifi_nan_pairing_cfg_t *pairing) { struct own_svc_info *p_svc = NULL; for (int i = 0; i < ESP_WIFI_NAN_MAX_SVC_SUPPORTED; i++) { @@ -485,6 +485,11 @@ static struct own_svc_info *nan_claim_own_svc_slot(uint8_t type, const char svc_ if (security_cfg) { memcpy(&p_svc->user_cfg, security_cfg, sizeof(*security_cfg)); } +#ifdef CONFIG_ESP_WIFI_NAN_PAIRING + if (pairing) { + memcpy(&p_svc->pairing, pairing, sizeof(*pairing)); + } +#endif #else (void)security_cfg; #endif @@ -1755,9 +1760,14 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg) * tripping the task watchdog when num_credentials > 1. */ if (!nan_claim_own_svc_slot(ESP_NAN_PUBLISH, publish_cfg->service_name, #ifdef CONFIG_ESP_WIFI_NAN_SECURITY - cfg->security_cfg + cfg->security_cfg, +#ifdef CONFIG_ESP_WIFI_NAN_PAIRING + cfg->pairing #else NULL +#endif +#else + NULL, NULL #endif )) { ESP_LOGE(TAG, "No free service slot"); @@ -1896,7 +1906,7 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe /* Pre-claim host slot BEFORE the blob's subscribe call; see comment on * the publish path for the watchdog rationale. */ if (!nan_claim_own_svc_slot(ESP_NAN_SUBSCRIBE, subscribe_cfg->service_name, - subscribe_cfg->security_cfg)) { + subscribe_cfg->security_cfg, subscribe_cfg->pairing)) { ESP_LOGE(TAG, "No free service slot"); goto fail; } diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h index 25a0df128fd..a46d5860ec3 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h @@ -222,6 +222,9 @@ struct own_svc_info { * per-service array the blob caches in svc_entry->self_security_params[]. * Valid entries: [0, user_cfg.num_credentials). */ wifi_nan_security_params_t derived_security[ESP_WIFI_NAN_MAX_CREDS_PER_SVC]; +#ifdef CONFIG_ESP_WIFI_NAN_PAIRING + wifi_nan_pairing_cfg_t pairing; +#endif #endif uint8_t num_peer_records; SLIST_HEAD(peer_list_t, peer_svc_info) peer_list; diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index 758c876c283..93de2adf3f4 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -788,6 +788,24 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, (void)nik_lifetime_sec; #endif + struct peer_svc_info *peer = nan_find_peer_svc(0, 0, (uint8_t *)peer_nmi); + struct own_svc_info *own = NULL; + + if (peer) { + own = nan_find_own_svc(peer->own_svc_id); + } + + if (own) { + if (!own->pairing.npk_nik_caching) { + wifi_event_nan_pairing_complete_t evt = {0}; + evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; + evt.reason_code = 0; + MACADDR_COPY(evt.peer_nmi, peer_nmi); + nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); + return; + } + } + if (role == NAN_ROLE_PAIRING_INITIATOR) { struct nan_pairing_fup_ctx *ctx = os_zalloc(sizeof(*ctx)); if (!ctx) { @@ -797,7 +815,7 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, } NAN_DATA_LOCK(); - struct peer_svc_info *peer = nan_find_peer_svc(0, 0, (uint8_t *)peer_nmi); + if (peer) { ctx->svc_id = peer->own_svc_id; ctx->peer_svc_id = peer->svc_id; @@ -816,7 +834,7 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, MACADDR_COPY(ctx->peer_mac, peer_nmi); ctx->shared_key_attr_len = 0; - struct own_svc_info *own = nan_find_own_svc(ctx->svc_id); + own = nan_find_own_svc(ctx->svc_id); if (own) { nan_pairing_arm_pending(own, peer_nmi); } @@ -832,10 +850,8 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, } if (role == NAN_ROLE_PAIRING_RESPONDER) { - struct own_svc_info *own = NULL; - NAN_DATA_LOCK(); - struct peer_svc_info *peer = nan_find_peer_svc(0, 0, (uint8_t *)peer_nmi); + if (peer) { own = nan_find_own_svc(peer->own_svc_id); } @@ -858,7 +874,7 @@ static void nan_app_update_peer_creds(const uint8_t *peer_nik, const uint8_t *np /* Reuse the slot already holding this NIK, if any. */ for (uint8_t i = 0; i < s_nan_ctx.num_peer_creds; i++) { if (s_nan_ctx.peer_creds[i].is_valid && - os_memcmp(s_nan_ctx.peer_creds[i].peer_nik, peer_nik, ESP_WIFI_NAN_NIK_LEN) == 0) { + os_memcmp(s_nan_ctx.peer_creds[i].peer_nik, peer_nik, ESP_WIFI_NAN_NIK_LEN) == 0) { slot = &s_nan_ctx.peer_creds[i]; break; } From fb56779fd1359039313edc48837d162fca51b7ce Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Thu, 11 Jun 2026 18:56:55 +0530 Subject: [PATCH 17/27] Change the NIRA verification logic --- components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c | 5 +++-- .../wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index 93de2adf3f4..4a4ac938adb 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -500,7 +500,7 @@ static void nan_pairing_nik_fup_timeout_cb(void *eloop_data, void *user_ctx) evt.status = WIFI_NAN_PAIRING_STATUS_REJECTED; evt.reason_code = WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT; MACADDR_COPY(evt.peer_nmi, own->nik_fup_pending_peer_nmi); - esp_nan_disable_pairing(own->svc_id); + esp_nan_complete_pairing(own->svc_id); nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); ESP_LOGW(TAG, "Pairing NIK follow-up timed out for peer " MACSTR, MAC2STR(own->nik_fup_pending_peer_nmi)); @@ -801,6 +801,7 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; evt.reason_code = 0; MACADDR_COPY(evt.peer_nmi, peer_nmi); + esp_nan_complete_pairing(own->svc_id); nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); return; } @@ -986,7 +987,7 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; evt.reason_code = 0; MACADDR_COPY(evt.peer_nmi, peer_mac); - esp_nan_disable_pairing(own_svc_id_to_disable); + esp_nan_complete_pairing(own_svc_id_to_disable); nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); } diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h index 8d6c7382070..774e25f094d 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -340,12 +340,12 @@ void esp_wifi_ap_set_group_mgmt_cipher_internal(wifi_cipher_type_t cipher); uint8_t esp_wifi_op_class_supported_internal(uint8_t op_class, uint8_t min_chan, uint8_t max_chan, uint8_t inc, uint8_t bw, channel_bitmap_t *non_pref_channels); bool esp_wifi_is_wpa3_compatible_mode_enabled(uint8_t if_index); uint8_t esp_wifi_ap_get_owe_config_internal(void); -esp_err_t esp_nan_disable_pairing(uint8_t svc_id); +esp_err_t esp_nan_complete_pairing(uint8_t svc_id); esp_err_t esp_wifi_nan_load_saved_creds(uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN], bool *own_nik_valid, - wifi_nan_peer_creds_t peer_creds[ESP_WIFI_NAN_MAX_PEER_CREDS], uint8_t *num_peer_creds); + wifi_nan_peer_creds_t peer_creds[ESP_WIFI_NAN_MAX_PEER_CREDS], uint8_t *num_peer_creds); esp_err_t esp_wifi_nan_save_own_nik(const uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN]) ; esp_err_t esp_wifi_nan_save_creds_for_peer(const uint8_t peer_nik[ESP_WIFI_NAN_NIK_LEN], - const uint8_t npk[ESP_WIFI_NAN_NPK_LEN]); + const uint8_t npk[ESP_WIFI_NAN_NPK_LEN]); esp_err_t esp_wifi_nan_erase_all_creds(void); #endif /* _ESP_WIFI_DRIVER_H_ */ From 8a69a0856751b515bc06e10129d9bbed1e3f86ca Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Fri, 12 Jun 2026 18:12:20 +0530 Subject: [PATCH 18/27] fix(nan): Add service hash to NVS to maintain pairing states after reset --- .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 46 +++++++++++++++++-- .../esp_wifi/wifi_apps/nan_app/src/nan_i.h | 3 ++ .../wifi_apps/nan_app/src/nan_pairing.c | 22 +++++---- .../wifi_apps/nan_app/src/nan_security.c | 2 +- .../esp_supplicant/src/esp_wifi_driver.h | 3 +- 5 files changed, 61 insertions(+), 15 deletions(-) diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c index 76879988a70..a1336e65cbb 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c @@ -479,6 +479,7 @@ static struct own_svc_info *nan_claim_own_svc_slot(uint8_t type, const char svc_ p_svc->type = type; strlcpy(p_svc->svc_name, svc_name, ESP_WIFI_MAX_SVC_NAME_LEN); SLIST_INIT(&p_svc->peer_list); + #ifdef CONFIG_ESP_WIFI_NAN_SECURITY forced_memzero(&p_svc->user_cfg, sizeof(p_svc->user_cfg)); forced_memzero(&p_svc->derived_security, sizeof(p_svc->derived_security)); @@ -499,13 +500,14 @@ static struct own_svc_info *nan_claim_own_svc_slot(uint8_t type, const char svc_ /* Stamp the real svc_id and per-publish flags after the blob accepts the * service. Looked up by name since the WiFi-task derive callback may have * already populated derived_security[] before this runs. */ -static void nan_finalize_own_svc(const char *svc_name, uint8_t id, bool ndp_resp_needed) +static void nan_finalize_own_svc(const char *svc_name, uint8_t id, bool ndp_resp_needed, uint8_t service_hash[6]) { struct own_svc_info *p_svc = nan_find_own_svc_by_name(svc_name); if (!p_svc) { return; } p_svc->svc_id = id; + memcpy(p_svc->svc_hash, service_hash, 6); if (p_svc->type == ESP_NAN_PUBLISH) { p_svc->ndp_resp_needed = ndp_resp_needed; } @@ -1624,9 +1626,23 @@ esp_err_t esp_wifi_nan_sync_stop(void) } #endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ +#ifdef CONFIG_ESP_WIFI_NAN_PAIRING +static bool nan_check_paired_service_hash(uint8_t service_hash[6]) +{ + for (uint8_t i = 0; i < s_nan_ctx.num_peer_creds; i++) { + if (s_nan_ctx.peer_creds[i].is_valid && + os_memcmp(s_nan_ctx.peer_creds[i].service_hash, service_hash, 6) == 0) { + return true; + } + } + return false; +} +#endif + uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg) { int pub_id = 0; + uint8_t service_id[6] = {0}; if (publish_cfg->usd_discovery_flag && !s_usd_in_progress) { ESP_LOGE(TAG, "Can not start Publish function with USD Discovery " @@ -1758,6 +1774,17 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg) * into p_svc->derived_security[]. Doing the derive on WiFi task (not the * app/main task) keeps PBKDF2's hardware-SHA polling off IDLE0 and avoids * tripping the task watchdog when num_credentials > 1. */ + if (!nan_compute_service_id(publish_cfg->service_name, service_id)) { + ESP_LOGE(TAG, "Failed to compute Service ID for %s", publish_cfg->service_name); + goto fail; + } + +#ifdef CONFIG_ESP_WIFI_NAN_PAIRING + if (nan_check_paired_service_hash(service_id)) { + cfg->pairing->pairing_setup = false; + } +#endif + if (!nan_claim_own_svc_slot(ESP_NAN_PUBLISH, publish_cfg->service_name, #ifdef CONFIG_ESP_WIFI_NAN_SECURITY cfg->security_cfg, @@ -1781,7 +1808,7 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg) } ESP_LOGI(TAG, "Started Publishing %s [Service ID - %u]", publish_cfg->service_name, pub_id); - nan_finalize_own_svc(publish_cfg->service_name, pub_id, publish_cfg->ndp_resp_needed); + nan_finalize_own_svc(publish_cfg->service_name, pub_id, publish_cfg->ndp_resp_needed, service_id); if (cfg->pairing) { os_free(cfg->pairing); } @@ -1805,6 +1832,7 @@ fail: uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe_cfg) { int sub_id = 0; + uint8_t service_id[6] = {0}; if (subscribe_cfg->usd_discovery_flag && !s_usd_in_progress) { ESP_LOGE(TAG, "Can not start Subscribe function with USD Discovery " @@ -1905,6 +1933,18 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe /* Pre-claim host slot BEFORE the blob's subscribe call; see comment on * the publish path for the watchdog rationale. */ + + if (!nan_compute_service_id(subscribe_cfg->service_name, service_id)) { + ESP_LOGE(TAG, "Failed to compute Service ID for %s", subscribe_cfg->service_name); + goto fail; + } + +#ifdef CONFIG_ESP_WIFI_NAN_PAIRING + if (nan_check_paired_service_hash(service_id)) { + subscribe_cfg->pairing->pairing_setup = false; + } +#endif + if (!nan_claim_own_svc_slot(ESP_NAN_SUBSCRIBE, subscribe_cfg->service_name, subscribe_cfg->security_cfg, subscribe_cfg->pairing)) { ESP_LOGE(TAG, "No free service slot"); @@ -1918,7 +1958,7 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe } ESP_LOGI(TAG, "Started Subscribing to %s [Service ID - %u]", subscribe_cfg->service_name, sub_id); - nan_finalize_own_svc(subscribe_cfg->service_name, (uint8_t) sub_id, false); + nan_finalize_own_svc(subscribe_cfg->service_name, (uint8_t) sub_id, false, service_id); NAN_DATA_UNLOCK(); return sub_id; diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h index a46d5860ec3..d343c126aff 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h @@ -232,6 +232,7 @@ struct own_svc_info { bool nik_fup_pending; uint8_t nik_fup_pending_peer_nmi[MACADDR_LEN]; #endif + uint8_t svc_hash[6]; }; /* Per-NDP link state */ @@ -486,6 +487,8 @@ esp_err_t nan_app_register_paired_peer(const uint8_t *peer_nmi, const struct nan_paired_peer *nan_app_find_paired_peer(const uint8_t *peer_nmi); void nan_app_remove_paired_peer(const uint8_t *peer_nmi); void nan_app_clear_paired_peers(void); +bool nan_compute_service_id(const char *service_name, uint8_t service_id[6]); + #endif /* CONFIG_ESP_WIFI_NAN_SECURITY */ #ifdef __cplusplus diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index 4a4ac938adb..c24554c0901 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -868,7 +868,7 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, * for NIRA identity resolution. Caller holds NAN_DATA_LOCK. A @a npk of NULL * stores a zeroed key. When the cache is full the oldest entry (slot 0) is * reused. */ -static void nan_app_update_peer_creds(const uint8_t *peer_nik, const uint8_t *npk) +static void nan_app_update_peer_creds(const uint8_t *peer_nik, const uint8_t *npk, uint8_t service_hash[6]) { wifi_nan_peer_creds_t *slot = NULL; @@ -889,6 +889,7 @@ static void nan_app_update_peer_creds(const uint8_t *peer_nik, const uint8_t *np } memcpy(slot->peer_nik, peer_nik, ESP_WIFI_NAN_NIK_LEN); + memcpy(slot->service_hash, service_hash, 6); if (npk) { memcpy(slot->npk, npk, ESP_WIFI_NAN_NPK_LEN); } else { @@ -940,9 +941,9 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, bool already_had_nik = false; bool pairing_completed = false; - uint8_t own_svc_id_to_disable = 0; bool persist_creds = false; uint8_t persist_npk[ESP_WIFI_NAN_NPK_LEN] = {0}; + struct own_svc_info *own = NULL; NAN_DATA_LOCK(); struct peer_svc_info *p_peer_svc = nan_find_peer_svc_exact(svc_id, peer_svc_id, peer_mac); @@ -961,33 +962,33 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, if (paired) { memcpy(persist_npk, paired->nd_pmk, ESP_WIFI_NAN_NPK_LEN); } - nan_app_update_peer_creds(nik, paired ? paired->nd_pmk : NULL); - persist_creds = s_nan_ctx.use_nvs_for_caching; + + own = nan_find_own_svc(p_peer_svc->own_svc_id); if (!already_had_nik) { pairing_completed = true; - own_svc_id_to_disable = p_peer_svc->own_svc_id; } + + nan_app_update_peer_creds(nik, paired ? paired->nd_pmk : NULL, own ? own->svc_hash : NULL); + persist_creds = s_nan_ctx.use_nvs_for_caching; } NAN_DATA_UNLOCK(); /* Persist outside the lock; NVS writes can block. */ if (persist_creds) { - esp_wifi_nan_save_creds_for_peer(nik, persist_npk); + esp_wifi_nan_save_creds_for_peer(nik, persist_npk, own ? own->svc_hash : NULL); } - /* Invoke blocking calls outside NAN_DATA_LOCK to avoid deadlock. */ if (pairing_completed) { wifi_event_nan_pairing_complete_t evt = {0}; - struct own_svc_info *own = nan_find_own_svc(own_svc_id_to_disable); if (own) { nan_pairing_cancel_svc_pending(own); } evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; evt.reason_code = 0; MACADDR_COPY(evt.peer_nmi, peer_mac); - esp_nan_complete_pairing(own_svc_id_to_disable); + esp_nan_complete_pairing(p_peer_svc ? p_peer_svc->own_svc_id : 0); nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); } @@ -1047,6 +1048,7 @@ bool esp_nan_verify_nira(uint8_t *peer_mac, uint8_t *nira_attr, uint16_t nira_at if (!s_nan_ctx.peer_creds[i].is_valid) { continue; } + if (nan_pairing_derive_nira_tag(s_nan_ctx.peer_creds[i].peer_nik, peer_mac, nonce, expected_tag) != 0) { continue; @@ -1061,7 +1063,7 @@ bool esp_nan_verify_nira(uint8_t *peer_mac, uint8_t *nira_attr, uint16_t nira_at if (match) { ESP_LOGD(TAG, "NIRA verify: OK for "MACSTR, MAC2STR(peer_mac)); } else { - ESP_LOGW(TAG, "NIRA verify: no matching NIK for "MACSTR, MAC2STR(peer_mac)); + ESP_LOGD(TAG, "NIRA verify: no matching NIK for "MACSTR, MAC2STR(peer_mac)); } return match; } diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c index fa408b91742..5fbf2b8227c 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c @@ -103,7 +103,7 @@ static bool nan_csid_bitmap_has_pasn(uint16_t csid_bitmap) * Service ID = first 6 bytes of SHA256(lowercase(service_name)) * per Wi-Fi Aware v4.0 §5.1.5 (Service Name and Service ID). */ -static bool nan_compute_service_id(const char *service_name, uint8_t service_id[6]) +bool nan_compute_service_id(const char *service_name, uint8_t service_id[6]) { if (!service_name || !g_wifi_default_wpa_crypto_funcs.sha256_vector) { return false; diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h index 774e25f094d..a71272dcc4c 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -243,6 +243,7 @@ typedef enum { typedef struct { uint8_t peer_nik[ESP_WIFI_NAN_NIK_LEN]; /**< Peer's NAN Identity Key (16 bytes) */ uint8_t npk[ESP_WIFI_NAN_NPK_LEN]; /**< NAN Pairwise Key / NCS-SK PMK (32 bytes) */ + uint8_t service_hash[6]; bool is_valid; } wifi_nan_peer_creds_t; @@ -345,7 +346,7 @@ esp_err_t esp_wifi_nan_load_saved_creds(uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN], b wifi_nan_peer_creds_t peer_creds[ESP_WIFI_NAN_MAX_PEER_CREDS], uint8_t *num_peer_creds); esp_err_t esp_wifi_nan_save_own_nik(const uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN]) ; esp_err_t esp_wifi_nan_save_creds_for_peer(const uint8_t peer_nik[ESP_WIFI_NAN_NIK_LEN], - const uint8_t npk[ESP_WIFI_NAN_NPK_LEN]); + const uint8_t npk[ESP_WIFI_NAN_NPK_LEN], const uint8_t service_hash[6]); esp_err_t esp_wifi_nan_erase_all_creds(void); #endif /* _ESP_WIFI_DRIVER_H_ */ From ff5df2e245ff8bdfdb8bf14fab71c3279813b3ed Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Mon, 15 Jun 2026 11:56:53 +0530 Subject: [PATCH 19/27] Address review comments and fix build errors --- .../esp_wifi/include/esp_wifi_types_generic.h | 7 +++-- .../include/injected/esp_wifi_types_generic.h | 5 ++-- .../include/apps_private/wifi_apps_private.h | 6 +++- .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 30 +++++++++++++++++++ .../esp_wifi/wifi_apps/nan_app/src/nan_i.h | 2 +- .../wifi_apps/nan_app/src/nan_pairing.c | 16 ++++++++-- .../wifi_apps/nan_app/src/nan_security.c | 30 ------------------- .../esp_supplicant/src/esp_nan_supplicant.c | 4 +-- .../esp_supplicant/src/esp_wifi_driver.h | 6 ++-- 9 files changed, 61 insertions(+), 45 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index f3abe1aefcf..91585166ba9 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -875,7 +875,7 @@ typedef struct { #define ESP_WIFI_NAN_NDP_PMK_LEN 32 /**< Length of NAN Datapath PMK */ #define ESP_WIFI_NAN_NPK_LEN ESP_WIFI_NAN_NDP_PMK_LEN /**< Length of NAN Pairwise Key (same as NDP PMK) */ #define ESP_WIFI_NAN_NDP_PMKID_LEN 16 /**< Length of NAN Datapath PMKID */ -#define ESP_WIFI_NAN_MAX_PEER_CREDS 2 /**< cred.pincode != UINT32_MAX && + cfg->cred.pincode > NAN_PAIRING_PINCODE_MAX) { + ESP_LOGE(TAG, "Invalid pincode %u (valid range %u..%u or UINT32_MAX for default)", + cfg->cred.pincode, NAN_PAIRING_PINCODE_MIN, NAN_PAIRING_PINCODE_MAX); + return ESP_ERR_INVALID_ARG; + } + int ret; switch (cfg->self_role) { @@ -497,13 +504,16 @@ static void nan_pairing_nik_fup_timeout_cb(void *eloop_data, void *user_ctx) } own->nik_fup_pending = false; - evt.status = WIFI_NAN_PAIRING_STATUS_REJECTED; + evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; evt.reason_code = WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT; MACADDR_COPY(evt.peer_nmi, own->nik_fup_pending_peer_nmi); +#if defined(CONFIG_ESP_WIFI_NAN_SECURITY) + nan_app_remove_paired_peer(own->nik_fup_pending_peer_nmi); +#endif esp_nan_complete_pairing(own->svc_id); nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); - ESP_LOGW(TAG, "Pairing NIK follow-up timed out for peer " MACSTR, - MAC2STR(own->nik_fup_pending_peer_nmi)); + ESP_LOGW(TAG, "Pairing succeeded but NIK caching timed out for peer " MACSTR + " (reason=%u)", MAC2STR(own->nik_fup_pending_peer_nmi), evt.reason_code); } /** diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c index 5fbf2b8227c..8e6df442bcc 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c @@ -99,36 +99,6 @@ static bool nan_csid_bitmap_has_pasn(uint16_t csid_bitmap) return (csid_bitmap & WIFI_NAN_CSID_BIT_NCS_PK_PASN_128) != 0; } -/* - * Service ID = first 6 bytes of SHA256(lowercase(service_name)) - * per Wi-Fi Aware v4.0 §5.1.5 (Service Name and Service ID). - */ -bool nan_compute_service_id(const char *service_name, uint8_t service_id[6]) -{ - if (!service_name || !g_wifi_default_wpa_crypto_funcs.sha256_vector) { - return false; - } - size_t name_len = strlen(service_name); - char *lower = os_malloc(name_len + 1); - if (!lower) { - return false; - } - strlcpy(lower, service_name, name_len + 1); - for (char *p = lower; *p; p++) { - *p = tolower((unsigned char) * p); - } - uint8_t hash[32]; - const uint8_t *addr[1] = {(const uint8_t *)lower}; - size_t len[1] = {name_len}; - int ret = g_wifi_default_wpa_crypto_funcs.sha256_vector(1, addr, len, hash); - os_free(lower); - if (ret != 0) { - return false; - } - memcpy(service_id, hash, 6); - return true; -} - #define NAN_SERVICE_ID_LEN 6 /* diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_nan_supplicant.c b/components/wpa_supplicant/esp_supplicant/src/esp_nan_supplicant.c index c332d1a47bd..b5e2eee2840 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_nan_supplicant.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_nan_supplicant.c @@ -1587,7 +1587,7 @@ static void nan_pasn_auth_eloop_cb(void *eloop_ctx, void *user_data) if (ctx->pincode != UINT32_MAX) { n = os_snprintf(pin_digits, sizeof(pin_digits), "%06u", - (unsigned)(ctx->pincode % 1000000U)); + (unsigned)ctx->pincode); if (os_snprintf_error(sizeof(pin_digits), n)) { nan_pasn_data_deinit(pd); os_free(ctx); @@ -1746,7 +1746,7 @@ int pasn_responder_init(const uint8_t *peer_addr, uint32_t pincode) if (pincode != UINT32_MAX) { n = os_snprintf(pin_digits, sizeof(pin_digits), "%06u", - (unsigned)(pincode % 1000000U)); + (unsigned)pincode); if (os_snprintf_error(sizeof(pin_digits), n)) { goto fail; } diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h index a71272dcc4c..8040f4c297c 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -243,8 +243,8 @@ typedef enum { typedef struct { uint8_t peer_nik[ESP_WIFI_NAN_NIK_LEN]; /**< Peer's NAN Identity Key (16 bytes) */ uint8_t npk[ESP_WIFI_NAN_NPK_LEN]; /**< NAN Pairwise Key / NCS-SK PMK (32 bytes) */ - uint8_t service_hash[6]; - bool is_valid; + uint8_t service_hash[6]; /**< Service Hash of the corresponding service */ + bool is_valid; /**< True if this credential entry is valid */ } wifi_nan_peer_creds_t; typedef wifi_scan_channel_bitmap_t channel_bitmap_t; @@ -344,7 +344,7 @@ uint8_t esp_wifi_ap_get_owe_config_internal(void); esp_err_t esp_nan_complete_pairing(uint8_t svc_id); esp_err_t esp_wifi_nan_load_saved_creds(uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN], bool *own_nik_valid, wifi_nan_peer_creds_t peer_creds[ESP_WIFI_NAN_MAX_PEER_CREDS], uint8_t *num_peer_creds); -esp_err_t esp_wifi_nan_save_own_nik(const uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN]) ; +esp_err_t esp_wifi_nan_save_own_nik(const uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN]); esp_err_t esp_wifi_nan_save_creds_for_peer(const uint8_t peer_nik[ESP_WIFI_NAN_NIK_LEN], const uint8_t npk[ESP_WIFI_NAN_NPK_LEN], const uint8_t service_hash[6]); esp_err_t esp_wifi_nan_erase_all_creds(void); From 7475e1bced4e95a716163bb803f20c2f8190e77b Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Wed, 17 Jun 2026 10:43:09 +0530 Subject: [PATCH 20/27] Address review comments VNC --- .../esp_wifi/include/esp_private/wifi.h | 3 + .../esp_wifi/include/esp_wifi_types_generic.h | 3 - .../include/injected/esp_wifi_types_generic.h | 3 - .../include/apps_private/wifi_apps_private.h | 3 + .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 2 + .../esp_wifi/wifi_apps/nan_app/src/nan_i.h | 2 + .../wifi_apps/nan_app/src/nan_pairing.c | 9 +- .../wifi_apps/nan_app/src/nan_security.c | 137 ++++++++++++------ .../esp_supplicant/src/esp_wifi_driver.h | 2 +- 9 files changed, 108 insertions(+), 56 deletions(-) diff --git a/components/esp_wifi/include/esp_private/wifi.h b/components/esp_wifi/include/esp_private/wifi.h index f69b4e43388..cdc7a9ad66d 100644 --- a/components/esp_wifi/include/esp_private/wifi.h +++ b/components/esp_wifi/include/esp_private/wifi.h @@ -232,6 +232,9 @@ struct nan_secure_dp_funcs { * encrypted KDE payload (GTK/IGTK/BIGTK). */ int (*ndp_security_install_get_shared_desc_len)(void); + uint8_t (*get_ndp_resp_num_pmkids)(uint8_t ndp_id, const uint8_t *peer_nmi); + uint32_t (*get_ndp_resp_shared_key_desc_len)(uint8_t ndp_id, const uint8_t *peer_nmi); + /* --- CSIA / SCIA construction. Each writes a complete NAN * attribute (header + body) at @c frm and returns bytes * written, or -1 on error. --- */ diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index 91585166ba9..f44b8590de5 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -1669,9 +1669,6 @@ typedef struct { uint32_t cookie; /**< Comeback cookie from responder (0 if none) */ } wifi_event_nan_bootstrap_complete_t; -#define WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT 1 /**< Local reason: peer NIK follow-up not received within timeout. - See Wi-Fi Aware v4.0 §7.6.4.2 for the NIK-exchange procedure. */ - /** * @brief Argument structure for WIFI_EVENT_NAN_PAIRING_CONFIRM event */ diff --git a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h index 46c938bf35f..b748bb9291d 100644 --- a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h +++ b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h @@ -1669,9 +1669,6 @@ typedef struct { uint32_t cookie; /**< Comeback cookie from responder (0 if none) */ } wifi_event_nan_bootstrap_complete_t; -#define WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT 1 /**< Local reason: peer NIK follow-up not received within timeout. - See Wi-Fi Aware v4.0 §7.6.4.2 for the NIK-exchange procedure. */ - /** * @brief Argument structure for WIFI_EVENT_NAN_PAIRING_CONFIRM event */ diff --git a/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h b/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h index 0870e78883f..243ef96af99 100644 --- a/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h +++ b/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h @@ -53,6 +53,9 @@ void esp_nan_action_stop(void); #ifdef CONFIG_ESP_WIFI_NAN_PAIRING +#define WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT 1 /**< Local reason: peer NIK follow-up not received within timeout. + See Wi-Fi Aware v4.0 §7.6.4.2 for the NIK-exchange procedure. */ + #ifndef NAN_PAIRING_PINCODE_MIN #define NAN_PAIRING_PINCODE_MIN 0 #endif diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c index 79ff3b5dc92..9e0dc69212e 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c @@ -1375,6 +1375,8 @@ static struct nan_secure_dp_funcs s_nan_secure_dp_funcs = { .get_scia_len = esp_nan_get_scia_len, .get_shared_key_desc_attr_len = esp_nan_get_shared_key_desc_attr_len, .ndp_security_install_get_shared_desc_len = esp_nan_ndp_security_install_get_shared_desc_len, + .get_ndp_resp_num_pmkids = esp_nan_get_ndp_resp_num_pmkids, + .get_ndp_resp_shared_key_desc_len = esp_nan_get_ndp_resp_shared_key_desc_len, /* CSIA / SCIA construction */ .construct_csia = esp_nan_construct_csia, diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h index 001bf886f24..342ff87b92f 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h @@ -366,6 +366,8 @@ uint32_t esp_nan_get_csia_len(uint16_t own_csid_bitmap, uint16_t peer_csid_bitma uint32_t esp_nan_get_scia_len(uint8_t num_pmkids); uint32_t esp_nan_get_shared_key_desc_attr_len(uint16_t key_data_len); int esp_nan_ndp_security_install_get_shared_desc_len(void); +uint8_t esp_nan_get_ndp_resp_num_pmkids(uint8_t ndp_id, const uint8_t *peer_nmi); +uint32_t esp_nan_get_ndp_resp_shared_key_desc_len(uint8_t ndp_id, const uint8_t *peer_nmi); int esp_nan_construct_csia(uint8_t *frm, uint8_t pub_id, uint16_t own_csid_bitmap, uint16_t peer_csid_bitmap); diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index 22f509c79ba..7c20bdfa938 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -510,7 +510,9 @@ static void nan_pairing_nik_fup_timeout_cb(void *eloop_data, void *user_ctx) #if defined(CONFIG_ESP_WIFI_NAN_SECURITY) nan_app_remove_paired_peer(own->nik_fup_pending_peer_nmi); #endif - esp_nan_complete_pairing(own->svc_id); + struct peer_svc_info *peer = nan_find_peer_svc(own->svc_id, 0, + own->nik_fup_pending_peer_nmi); + esp_nan_complete_pairing(own->svc_id, peer ? peer->svc_id : 0); nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); ESP_LOGW(TAG, "Pairing succeeded but NIK caching timed out for peer " MACSTR " (reason=%u)", MAC2STR(own->nik_fup_pending_peer_nmi), evt.reason_code); @@ -811,7 +813,7 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; evt.reason_code = 0; MACADDR_COPY(evt.peer_nmi, peer_nmi); - esp_nan_complete_pairing(own->svc_id); + esp_nan_complete_pairing(own->svc_id, peer->svc_id); nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); return; } @@ -998,7 +1000,8 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; evt.reason_code = 0; MACADDR_COPY(evt.peer_nmi, peer_mac); - esp_nan_complete_pairing(p_peer_svc ? p_peer_svc->own_svc_id : 0); + esp_nan_complete_pairing(p_peer_svc ? p_peer_svc->own_svc_id : 0, + p_peer_svc ? p_peer_svc->svc_id : peer_svc_id); nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); } diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c index 8e6df442bcc..14dbd6ff34d 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c @@ -427,6 +427,91 @@ static bool nan_security_fill_from_paired_cache(struct ndl_info *ndl, const uint } #endif +static bool nan_ndp_resp_resolve_pmk(struct ndl_info *ndl, const uint8_t *peer_nmi) +{ + static const uint8_t zero_pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN] = {0}; + static const uint8_t zero_pmk[ESP_WIFI_NAN_NDP_PMK_LEN] = {0}; + + if (!ndl || !peer_nmi) { + return false; + } + + bool have_peer_pmkid = (memcmp(ndl->security_ctx.nd_pmkid, zero_pmkid, + ESP_WIFI_NAN_NDP_PMKID_LEN) != 0); + bool need_pmk = (ndl->security_ctx.type != WIFI_NAN_SECURITY_ENCRYPTED) || + (memcmp(ndl->security_ctx.nd_pmk, zero_pmk, ESP_WIFI_NAN_NDP_PMK_LEN) == 0); + + if (!need_pmk) { + return have_peer_pmkid; + } + +#if defined(CONFIG_ESP_WIFI_NAN_PAIRING) + if (nan_security_fill_from_paired_cache(ndl, peer_nmi)) { + return have_peer_pmkid; + } +#endif + + if (!have_peer_pmkid) { + return false; + } + + struct own_svc_info *p_svc = nan_find_own_svc(ndl->publisher_id); + int matched_idx = p_svc ? nan_match_pmkid(p_svc, ndl->security_ctx.nd_pmkid, + ndl->peer_nmi, ndl->peer_ndi) : -1; + if (matched_idx < 0) { + return false; + } + + ndl->security_ctx.type = WIFI_NAN_SECURITY_ENCRYPTED; + ndl->security_ctx.csid_bitmap = p_svc->derived_security[matched_idx].csid_bitmap; + memcpy(ndl->security_ctx.nd_pmk, + p_svc->derived_security[matched_idx].nd_pmk, + ESP_WIFI_NAN_NDP_PMK_LEN); + return true; +} + +uint8_t esp_nan_get_ndp_resp_num_pmkids(uint8_t ndp_id, const uint8_t *peer_nmi) +{ + static const uint8_t zero_pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN] = {0}; + + if (!peer_nmi) { + return 0; + } + + NAN_DATA_LOCK(); + struct ndl_info *ndl = nan_find_ndl(ndp_id, (uint8_t *)peer_nmi); + if (!ndl) { + ndl = nan_find_ndl(0, (uint8_t *)peer_nmi); + } + uint8_t num = 0; + if (ndl && memcmp(ndl->security_ctx.nd_pmkid, zero_pmkid, ESP_WIFI_NAN_NDP_PMKID_LEN) != 0) { + num = 1; + } + NAN_DATA_UNLOCK(); + return num; +} + +uint32_t esp_nan_get_ndp_resp_shared_key_desc_len(uint8_t ndp_id, const uint8_t *peer_nmi) +{ + if (!peer_nmi) { + return 0; + } + + NAN_DATA_LOCK(); + struct ndl_info *ndl = nan_find_ndl(ndp_id, (uint8_t *)peer_nmi); + if (!ndl) { + ndl = nan_find_ndl(0, (uint8_t *)peer_nmi); + } + if (!ndl || ndl->handshake_state != NAN_HANDSHAKE_M1_RCVD || + !nan_ndp_resp_resolve_pmk(ndl, peer_nmi)) { + NAN_DATA_UNLOCK(); + return 0; + } + NAN_DATA_UNLOCK(); + + return esp_nan_get_shared_key_desc_attr_len(0); +} + /* * Build RSNA Key Descriptor payload (95-byte EAPOL-Key layout, see * IEEE 802.11-2020 §12.7.2). NAN carries this body inside the NAN @@ -1134,9 +1219,9 @@ int esp_nan_ndp_security_install_get_shared_desc_len(void) int esp_nan_get_ndp_resp_shared_key_desc(uint8_t *buf, size_t buf_len, uint8_t ndp_id, const uint8_t *peer_nmi) { - const uint32_t attr_len = esp_nan_get_shared_key_desc_attr_len(0); + const uint32_t attr_len = esp_nan_get_ndp_resp_shared_key_desc_len(ndp_id, peer_nmi); - if (!buf || buf_len < attr_len || !peer_nmi) { + if (!buf || !peer_nmi || attr_len == 0 || buf_len < attr_len) { return 0; } @@ -1152,50 +1237,10 @@ int esp_nan_get_ndp_resp_shared_key_desc(uint8_t *buf, size_t buf_len, uint8_t n ESP_LOGW(TAG, "NDP Resp Key Desc: NDL not in M1_RCVD (state=%d)", ndl->handshake_state); return 0; } - - /* Resolve PMK from publish when: NDL not encrypted, or encrypted but nd_pmk not set */ - { - static const uint8_t zero_pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN] = {0}; - static const uint8_t zero_pmk[ESP_WIFI_NAN_NDP_PMK_LEN] = {0}; - bool have_peer_pmkid = (memcmp(ndl->security_ctx.nd_pmkid, zero_pmkid, - ESP_WIFI_NAN_NDP_PMKID_LEN) != 0); - bool need_pmk = (ndl->security_ctx.type != WIFI_NAN_SECURITY_ENCRYPTED) || - (memcmp(ndl->security_ctx.nd_pmk, zero_pmk, ESP_WIFI_NAN_NDP_PMK_LEN) == 0); - - bool resolved_from_pairing_cache = false; -#if defined(CONFIG_ESP_WIFI_NAN_PAIRING) - if (need_pmk) { - resolved_from_pairing_cache = nan_security_fill_from_paired_cache(ndl, peer_nmi); - } -#endif - - if (resolved_from_pairing_cache) { - ESP_LOGD(TAG, "NDP Resp Key Desc: resolved PMK from paired-peer cache"); - } else if (need_pmk && have_peer_pmkid) { - struct own_svc_info *p_svc = nan_find_own_svc(ndl->publisher_id); - int matched_idx = p_svc ? nan_match_pmkid(p_svc, ndl->security_ctx.nd_pmkid, - ndl->peer_nmi, ndl->peer_ndi) : -1; - if (matched_idx >= 0) { - ndl->security_ctx.type = WIFI_NAN_SECURITY_ENCRYPTED; - ndl->security_ctx.csid_bitmap = p_svc->derived_security[matched_idx].csid_bitmap; - memcpy(ndl->security_ctx.nd_pmk, - p_svc->derived_security[matched_idx].nd_pmk, - ESP_WIFI_NAN_NDP_PMK_LEN); - ESP_LOGD(TAG, "NDP Resp Key Desc: resolved PMK from cred slot %d", matched_idx); - } else if (ndl->security_ctx.type != WIFI_NAN_SECURITY_ENCRYPTED) { - NAN_DATA_UNLOCK(); - ESP_LOGW(TAG, "NDP Resp Key Desc: NDL not encrypted; send NDP Response without Shared Key Descriptor"); - return 0; - } else { - NAN_DATA_UNLOCK(); - ESP_LOGW(TAG, "NDP Resp Key Desc: no PMK for peer PMKID; ensure matching credential on both devices"); - return 0; - } - } else if (ndl->security_ctx.type != WIFI_NAN_SECURITY_ENCRYPTED) { - NAN_DATA_UNLOCK(); - ESP_LOGW(TAG, "NDP Resp Key Desc: NDL not encrypted; send NDP Response without Shared Key Descriptor"); - return 0; - } + if (!nan_ndp_resp_resolve_pmk(ndl, peer_nmi)) { + NAN_DATA_UNLOCK(); + ESP_LOGW(TAG, "NDP Resp Key Desc: no PMK for peer PMKID; ensure matching credential on both devices"); + return 0; } /* Generate SNonce and derive PTK if not yet done */ diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h index 8040f4c297c..909183f78c5 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -341,7 +341,7 @@ void esp_wifi_ap_set_group_mgmt_cipher_internal(wifi_cipher_type_t cipher); uint8_t esp_wifi_op_class_supported_internal(uint8_t op_class, uint8_t min_chan, uint8_t max_chan, uint8_t inc, uint8_t bw, channel_bitmap_t *non_pref_channels); bool esp_wifi_is_wpa3_compatible_mode_enabled(uint8_t if_index); uint8_t esp_wifi_ap_get_owe_config_internal(void); -esp_err_t esp_nan_complete_pairing(uint8_t svc_id); +esp_err_t esp_nan_complete_pairing(uint8_t svc_id, uint8_t peer_svc_id); esp_err_t esp_wifi_nan_load_saved_creds(uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN], bool *own_nik_valid, wifi_nan_peer_creds_t peer_creds[ESP_WIFI_NAN_MAX_PEER_CREDS], uint8_t *num_peer_creds); esp_err_t esp_wifi_nan_save_own_nik(const uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN]); From 478be42bd19c8990ea3d08505483495bc9b50b15 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Tue, 23 Jun 2026 10:23:49 +0530 Subject: [PATCH 21/27] feat(nan): Add aes_wrap/unwrap crypto callbacks - Use crypto callbacks instead of calling internal API's - Clean up of unused code, flags. Re-arrange functions --- .../esp_wifi/include/esp_wifi_crypto_types.h | 18 +++--- .../include/injected/esp_wifi_crypto_types.h | 20 ++++--- .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 42 +++---------- .../esp_wifi/wifi_apps/nan_app/src/nan_i.h | 59 ++++++++----------- .../wifi_apps/nan_app/src/nan_pairing.c | 32 ++-------- .../wifi_apps/nan_app/src/nan_security.c | 2 +- .../wpa_supplicant/src/crypto/crypto_ops.c | 2 + 7 files changed, 64 insertions(+), 111 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi_crypto_types.h b/components/esp_wifi/include/esp_wifi_crypto_types.h index a85b443aeb9..c260493c04a 100644 --- a/components/esp_wifi/include/esp_wifi_crypto_types.h +++ b/components/esp_wifi/include/esp_wifi_crypto_types.h @@ -78,26 +78,26 @@ typedef int (*esp_aes_128_encrypt_t)(const unsigned char *key, const unsigned ch typedef int (*esp_aes_128_decrypt_t)(const unsigned char *key, const unsigned char *iv, unsigned char *data, int data_len); /** - * @brief The AES wrap callback function used by esp_wifi. + * @brief The AES key wrap (RFC 3394) callback function used by esp_wifi. * - * @param kek 16-octet Key encryption key (KEK). + * @param kek Key encryption key (KEK). + * @param kek_len Length of the KEK in bytes. * @param n Length of the plaintext key in 64-bit units; * @param plain Plaintext key to be wrapped, n * 64 bits * @param cipher Wrapped key, (n + 1) * 64 bits - * */ -typedef int (*esp_aes_wrap_t)(const unsigned char *kek, int n, const unsigned char *plain, unsigned char *cipher); +typedef int (*esp_aes_wrap_t)(const unsigned char *kek, size_t kek_len, int n, const unsigned char *plain, unsigned char *cipher); /** - * @brief The AES unwrap callback function used by esp_wifi. + * @brief The AES key unwrap (RFC 3394) callback function used by esp_wifi. * - * @param kek 16-octet Key decryption key (KEK). + * @param kek Key encryption key (KEK). + * @param kek_len Length of the KEK in bytes. * @param n Length of the plaintext key in 64-bit units; * @param cipher Wrapped key to be unwrapped, (n + 1) * 64 bits * @param plain Plaintext key, n * 64 bits - * */ -typedef int (*esp_aes_unwrap_t)(const unsigned char *kek, int n, const unsigned char *cipher, unsigned char *plain); +typedef int (*esp_aes_unwrap_t)(const unsigned char *kek, size_t kek_len, int n, const unsigned char *cipher, unsigned char *plain); /** * @brief The SHA256 callback function used by esp_wifi. @@ -404,6 +404,8 @@ typedef struct wpa_crypto_funcs_t { esp_ccmp_encrypt_t ccmp_encrypt; /**< Encrypt data callback function using CCMP */ esp_aes_gmac_t aes_gmac; /**< One-Key GMAC hash callback function with AES for MIC computation */ esp_sha256_vector_t sha256_vector; /**< SHA256 hash callback function for data vector */ + esp_aes_wrap_t aes_wrap; /**< The AES key wrap (RFC 3394) callback function used by esp_wifi */ + esp_aes_unwrap_t aes_unwrap; /**< The AES key unwrap (RFC 3394) callback function used by esp_wifi */ } wpa_crypto_funcs_t; /** diff --git a/components/esp_wifi/remote/include/injected/esp_wifi_crypto_types.h b/components/esp_wifi/remote/include/injected/esp_wifi_crypto_types.h index a85b443aeb9..d0ffffbffd5 100644 --- a/components/esp_wifi/remote/include/injected/esp_wifi_crypto_types.h +++ b/components/esp_wifi/remote/include/injected/esp_wifi_crypto_types.h @@ -78,26 +78,28 @@ typedef int (*esp_aes_128_encrypt_t)(const unsigned char *key, const unsigned ch typedef int (*esp_aes_128_decrypt_t)(const unsigned char *key, const unsigned char *iv, unsigned char *data, int data_len); /** - * @brief The AES wrap callback function used by esp_wifi. + * @brief The AES key wrap (RFC 3394) callback function used by esp_wifi. * - * @param kek 16-octet Key encryption key (KEK). + * @param kek Key encryption key (KEK). + * @param kek_len Length of the KEK in bytes. * @param n Length of the plaintext key in 64-bit units; * @param plain Plaintext key to be wrapped, n * 64 bits * @param cipher Wrapped key, (n + 1) * 64 bits - * + * Returns: 0 on success, -1 on failure */ -typedef int (*esp_aes_wrap_t)(const unsigned char *kek, int n, const unsigned char *plain, unsigned char *cipher); +typedef int (*esp_aes_wrap_t)(const unsigned char *kek, size_t kek_len, int n, const unsigned char *plain, unsigned char *cipher); /** - * @brief The AES unwrap callback function used by esp_wifi. + * @brief The AES key unwrap (RFC 3394) callback function used by esp_wifi. * - * @param kek 16-octet Key decryption key (KEK). + * @param kek Key encryption key (KEK). + * @param kek_len Length of the KEK in bytes. * @param n Length of the plaintext key in 64-bit units; * @param cipher Wrapped key to be unwrapped, (n + 1) * 64 bits * @param plain Plaintext key, n * 64 bits - * + * Returns: 0 on success, -1 on failure */ -typedef int (*esp_aes_unwrap_t)(const unsigned char *kek, int n, const unsigned char *cipher, unsigned char *plain); +typedef int (*esp_aes_unwrap_t)(const unsigned char *kek, size_t kek_len, int n, const unsigned char *cipher, unsigned char *plain); /** * @brief The SHA256 callback function used by esp_wifi. @@ -404,6 +406,8 @@ typedef struct wpa_crypto_funcs_t { esp_ccmp_encrypt_t ccmp_encrypt; /**< Encrypt data callback function using CCMP */ esp_aes_gmac_t aes_gmac; /**< One-Key GMAC hash callback function with AES for MIC computation */ esp_sha256_vector_t sha256_vector; /**< SHA256 hash callback function for data vector */ + esp_aes_wrap_t aes_wrap; /**< The AES key wrap (RFC 3394) callback function used by esp_wifi */ + esp_aes_unwrap_t aes_unwrap; /**< The AES key unwrap (RFC 3394) callback function used by esp_wifi */ } wpa_crypto_funcs_t; /** diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c index 9e0dc69212e..517c0fbb6e5 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c @@ -24,30 +24,6 @@ #include "esp_private/esp_nan_usd.h" #endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ -bool esp_nan_ndp_info_present(void) -{ - return true; -} - -uint32_t esp_nan_ndp_get_info_len(void) -{ - return 12; -} - -int esp_nan_construct_ndp_info(uint8_t *frm) -{ - static const uint8_t ndp_info_attr[] = { - 0x01, 0x09, 0x00, 0x50, 0x6f, 0x9a, 0x02, 0x00, 0x02, 0x00, 0x05, 0x0d - }; - - if (!frm) { - return 0; - } - - memcpy(frm, ndp_info_attr, sizeof(ndp_info_attr)); - return sizeof(ndp_info_attr); -} - #if !CONFIG_ESP_WIFI_NAN_PAIRING uint32_t esp_nan_get_nira_len(void) { @@ -774,7 +750,7 @@ void nan_app_post_event(int32_t event_id, void* event_data, size_t event_data_si g_wifi_osi_funcs._event_post(WIFI_EVENT, event_id, event_data, event_data_size, OSI_FUNCS_TIME_BLOCKING); } -void nan_app_service_match_cb(uint8_t sub_id, struct nan_cb_peer_info *peer_info, +static void nan_app_service_match_cb(uint8_t sub_id, struct nan_cb_peer_info *peer_info, struct nan_cb_npba_t *npba) { if (!peer_info) { @@ -886,7 +862,7 @@ void nan_app_service_match_cb(uint8_t sub_id, struct nan_cb_peer_info *peer_info os_free(evt); } -void nan_app_replied_cb(uint8_t pub_id, struct nan_cb_peer_info *peer_info) +static void nan_app_replied_cb(uint8_t pub_id, struct nan_cb_peer_info *peer_info) { if (!peer_info) { return; @@ -925,7 +901,7 @@ void nan_app_replied_cb(uint8_t pub_id, struct nan_cb_peer_info *peer_info) os_free(evt); } -void nan_app_receive_cb(uint8_t svc_id, struct nan_cb_peer_info *peer_info, +static void nan_app_receive_cb(uint8_t svc_id, struct nan_cb_peer_info *peer_info, uint8_t *shared_key_attr, uint16_t shared_key_attr_buf_len, struct nan_cb_npba_t *npba) { @@ -978,7 +954,7 @@ void nan_app_receive_cb(uint8_t svc_id, struct nan_cb_peer_info *peer_info, os_free(evt); } -void nan_app_ndp_indication_cb(uint8_t pub_id, struct ndp_cb_peer_info *peer_info, uint32_t device_caps) +static void nan_app_ndp_indication_cb(uint8_t pub_id, struct ndp_cb_peer_info *peer_info, uint32_t device_caps) { /* * Responder-side NDP indication. Security parsers (CSIA/SCIA/ @@ -1109,7 +1085,7 @@ void nan_app_ndp_indication_cb(uint8_t pub_id, struct ndp_cb_peer_info *peer_inf os_free(evt); } -void nan_app_ndp_response_indication_cb(struct ndp_cb_peer_info *peer_info) +static void nan_app_ndp_response_indication_cb(struct ndp_cb_peer_info *peer_info) { if (!peer_info) { return; @@ -1159,7 +1135,7 @@ static void nan_ndp_confirm_teardown(const uint8_t peer_nmi[6], uint8_t ndp_id) os_event_group_set_bits(nan_event_group, NDP_REJECTED); } -void nan_app_ndp_confirm_cb(uint8_t status, struct ndp_cb_peer_info *peer_info, +static void nan_app_ndp_confirm_cb(uint8_t status, struct ndp_cb_peer_info *peer_info, uint8_t own_ndi[6], uint8_t ipv6_identifier[8]) { if (!peer_info) { @@ -1296,7 +1272,7 @@ done: return; } -void nan_app_ndp_terminated_cb(uint8_t reason, uint8_t ndp_id, uint8_t init_ndi[6]) +static void nan_app_ndp_terminated_cb(uint8_t reason, uint8_t ndp_id, uint8_t init_ndi[6]) { NAN_DATA_LOCK(); if (s_nan_ctx.nan_netif && !nan_is_datapath_active()) { @@ -1322,7 +1298,7 @@ void nan_app_ndp_terminated_cb(uint8_t reason, uint8_t ndp_id, uint8_t init_ndi[ os_event_group_set_bits(nan_event_group, NDP_TERMINATED); } -void nan_action_txdone_cb(uint32_t context, bool tx_status) +static void nan_action_txdone_cb(uint32_t context, bool tx_status) { if (nan_event_group && s_fup_context == context) { if (tx_status) { @@ -1333,7 +1309,7 @@ void nan_action_txdone_cb(uint32_t context, bool tx_status) } } -void esp_nan_ndp_tx_done_cb(uint8_t ndp_id, const uint8_t *peer_nmi, uint8_t msg_type, bool tx_status) +static void esp_nan_ndp_tx_done_cb(uint8_t ndp_id, const uint8_t *peer_nmi, uint8_t msg_type, bool tx_status) { NAN_DATA_LOCK(); diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h index 342ff87b92f..414713635d5 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_i.h @@ -329,37 +329,6 @@ struct ndl_info *nan_find_ndl(uint8_t ndp_id, uint8_t peer_nmi[]); struct ndl_info *nan_find_ndl_by_pub_id_and_peer(uint8_t pub_id, const uint8_t *peer_nmi); bool nan_compute_service_id(const char *service_name, uint8_t service_id[6]); -/* === nan_secure_dp_funcs initializer targets === */ - -/* Always-present (defined in nan_app.c) */ -void esp_nan_ndp_tx_done_cb(uint8_t ndp_id, const uint8_t *peer_nmi, - uint8_t msg_type, bool tx_status); - -#ifdef CONFIG_ESP_WIFI_NAN_PAIRING -#include "freertos/FreeRTOS.h" -#include "freertos/event_groups.h" - -void nan_app_post_event(int32_t event_id, void *event_data, size_t event_data_size); -struct peer_svc_info *nan_find_peer_svc(uint8_t own_svc_id, uint8_t peer_svc_id, uint8_t peer_nmi[]); -EventGroupHandle_t nan_pairing_get_event_group(void); -uint32_t *nan_pairing_get_fup_context(void); -const uint8_t *nan_pairing_get_null_mac(void); - -bool nan_pairing_validate_publish_bootstrapping(uint16_t bootstrapping_methods); -bool nan_pairing_validate_subscribe_bootstrapping(uint16_t bootstrapping_methods); - -uint16_t nan_app_parse_npba_from_publish(const struct nan_cb_npba_t *npba); - -void nan_app_bootstrap_indication(uint8_t peer_svc_id, uint8_t pub_id, - uint8_t peer_nmi[6], uint16_t selected_method); -void nan_app_bootstrap_completed(uint8_t status, uint8_t peer_svc_id, uint8_t sub_id, - uint8_t peer_nmi[6], uint16_t matched_method, - uint8_t reason_code); -bool nan_app_parse_npba_from_receive(uint8_t own_svc_id, uint8_t peer_svc_id, - uint8_t peer_nmi[6], const struct nan_cb_npba_t *npba); -void nan_pairing_cancel_svc_pending(struct own_svc_info *own); -#endif /* CONFIG_ESP_WIFI_NAN_PAIRING */ - #ifdef CONFIG_ESP_WIFI_NAN_SECURITY /* Security-gated (defined in nan_security.c) */ uint32_t esp_nan_get_csia_len(uint16_t own_csid_bitmap, uint16_t peer_csid_bitmap); @@ -465,13 +434,33 @@ bool nan_security_service_match(const struct own_svc_info *own_svc, const wifi_nan_peer_sdf_security_t *peer_sec); #endif /* CONFIG_ESP_WIFI_NAN_SECURITY */ #if CONFIG_ESP_WIFI_NAN_PAIRING +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" + +void nan_app_post_event(int32_t event_id, void *event_data, size_t event_data_size); +struct peer_svc_info *nan_find_peer_svc(uint8_t own_svc_id, uint8_t peer_svc_id, uint8_t peer_nmi[]); +EventGroupHandle_t nan_pairing_get_event_group(void); +uint32_t *nan_pairing_get_fup_context(void); +const uint8_t *nan_pairing_get_null_mac(void); + +bool nan_pairing_validate_publish_bootstrapping(uint16_t bootstrapping_methods); +bool nan_pairing_validate_subscribe_bootstrapping(uint16_t bootstrapping_methods); + +uint16_t nan_app_parse_npba_from_publish(const struct nan_cb_npba_t *npba); + +void nan_app_bootstrap_indication(uint8_t peer_svc_id, uint8_t pub_id, + uint8_t peer_nmi[6], uint16_t selected_method); +void nan_app_bootstrap_completed(uint8_t status, uint8_t peer_svc_id, uint8_t sub_id, + uint8_t peer_nmi[6], uint16_t matched_method, + uint8_t reason_code); +bool nan_app_parse_npba_from_receive(uint8_t own_svc_id, uint8_t peer_svc_id, + uint8_t peer_nmi[6], const struct nan_cb_npba_t *npba); +void nan_pairing_cancel_svc_pending(struct own_svc_info *own); + void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id, const uint8_t *peer_mac, const uint8_t *shared_key_attr, size_t shared_key_attr_buf_len); -#endif - -#ifdef CONFIG_ESP_WIFI_NAN_SECURITY /* * Paired-peer cache API. Called from nan_pairing.c after the PASN install * callback fires; consumed by the NDP security layer to source ND-PMK + cipher @@ -491,7 +480,7 @@ const struct nan_paired_peer *nan_app_find_paired_peer(const uint8_t *peer_nmi); void nan_app_remove_paired_peer(const uint8_t *peer_nmi); void nan_app_clear_paired_peers(void); -#endif /* CONFIG_ESP_WIFI_NAN_SECURITY */ +#endif /* CONFIG_ESP_WIFI_NAN_PAIRING */ #ifdef __cplusplus } diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index 7c20bdfa938..15cf9f366ea 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 * @@ -23,10 +23,8 @@ #include "utils/common.h" #include "utils/eloop.h" -#if defined(CONFIG_ESP_WIFI_PASN_SUPPORT) #include "esp_private/esp_supp_nan.h" #include "apps_private/wifi_apps_private.h" -#endif static const char *TAG = "nan_pairing"; @@ -35,7 +33,6 @@ static const char *TAG = "nan_pairing"; * Shared Key Descriptor (Wi-Fi Aware v4.0 §7.6.4.2). */ #define NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC 86400U -#if defined(CONFIG_ESP_WIFI_PASN_SUPPORT) struct nan_pasn_data *esp_nan_app_get_pasn_data(void) { return s_nan_ctx.nan_pasn_data; @@ -52,7 +49,6 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, const uint8_t *nd_pmk, size_t nd_pmk_len, uint32_t nik_lifetime_sec); -#endif bool nan_pairing_validate_publish_bootstrapping(uint16_t bootstrapping_methods) { @@ -254,7 +250,6 @@ esp_err_t esp_wifi_nan_pairing_start(wifi_nan_pairing_config_t *cfg) return ESP_ERR_INVALID_ARG; } -#if defined(CONFIG_ESP_WIFI_PASN_SUPPORT) if (cfg->cred.pincode != UINT32_MAX && cfg->cred.pincode > NAN_PAIRING_PINCODE_MAX) { ESP_LOGE(TAG, "Invalid pincode %u (valid range %u..%u or UINT32_MAX for default)", @@ -288,10 +283,6 @@ esp_err_t esp_wifi_nan_pairing_start(wifi_nan_pairing_config_t *cfg) return ESP_ERR_INVALID_ARG; } return ESP_OK; -#else - ESP_LOGE(TAG, "NAN PASN support not enabled"); - return ESP_ERR_NOT_SUPPORTED; -#endif } /* NIRA: ID(1) + Len(2) + CipherVersion(1) + Nonce(8) + Tag(8) = 20 */ @@ -407,10 +398,6 @@ int esp_nan_construct_nira(uint8_t *frm) return (int)(p - frm); } -#if defined(CONFIG_ESP_WIFI_NAN_PAIRING) && defined(CONFIG_ESP_WIFI_PASN_SUPPORT) && defined(CONFIG_ESP_WIFI_NAN_SECURITY) - -#include "crypto/sha256.h" -#include "crypto/aes_wrap.h" #include "common/ieee802_11_defs.h" #include "common/wpa_common.h" @@ -507,9 +494,7 @@ static void nan_pairing_nik_fup_timeout_cb(void *eloop_data, void *user_ctx) evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; evt.reason_code = WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT; MACADDR_COPY(evt.peer_nmi, own->nik_fup_pending_peer_nmi); -#if defined(CONFIG_ESP_WIFI_NAN_SECURITY) nan_app_remove_paired_peer(own->nik_fup_pending_peer_nmi); -#endif struct peer_svc_info *peer = nan_find_peer_svc(own->svc_id, 0, own->nik_fup_pending_peer_nmi); esp_nan_complete_pairing(own->svc_id, peer ? peer->svc_id : 0); @@ -689,7 +674,11 @@ static esp_err_t nan_app_send_pairing_followup(uint8_t svc_id, uint8_t peer_svc_ return ESP_ERR_INVALID_SIZE; } wrapped_len = plain_len + 8; - if (aes_wrap(saved->kek, saved->kek_len, plain_len / 8, plain, wrapped) != 0) { + if (!g_wifi_default_wpa_crypto_funcs.aes_wrap) { + ESP_LOGE(TAG, "Pairing follow-up: aes_wrap not registered"); + return ESP_FAIL; + } + if (g_wifi_default_wpa_crypto_funcs.aes_wrap(saved->kek, saved->kek_len, plain_len / 8, plain, wrapped) != 0) { return ESP_FAIL; } @@ -778,7 +767,6 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, return; } -#if defined(CONFIG_ESP_WIFI_NAN_SECURITY) uint32_t lifetime_sec = nik_lifetime_sec ? nik_lifetime_sec : NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC; @@ -793,12 +781,6 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi, "paired-peer cache not updated", MAC2STR(peer_nmi), ndp_csid, (unsigned)nd_pmk_len); } -#else - (void)ndp_csid; - (void)nd_pmk; - (void)nd_pmk_len; - (void)nik_lifetime_sec; -#endif struct peer_svc_info *peer = nan_find_peer_svc(0, 0, (uint8_t *)peer_nmi); struct own_svc_info *own = NULL; @@ -1081,6 +1063,4 @@ bool esp_nan_verify_nira(uint8_t *peer_mac, uint8_t *nira_attr, uint16_t nira_at return match; } -#endif /* CONFIG_ESP_WIFI_NAN_PAIRING && CONFIG_ESP_WIFI_PASN_SUPPORT && CONFIG_ESP_WIFI_NAN_SECURITY */ - #endif /* CONFIG_ESP_WIFI_NAN_PAIRING */ diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c index 14dbd6ff34d..9ec1cdb3ec8 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_security.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 * diff --git a/components/wpa_supplicant/src/crypto/crypto_ops.c b/components/wpa_supplicant/src/crypto/crypto_ops.c index 0346d17f5c1..ec3a3aee9f7 100644 --- a/components/wpa_supplicant/src/crypto/crypto_ops.c +++ b/components/wpa_supplicant/src/crypto/crypto_ops.c @@ -45,6 +45,8 @@ const wpa_crypto_funcs_t g_wifi_default_wpa_crypto_funcs = { .ccmp_encrypt = (esp_ccmp_encrypt_t)ccmp_encrypt, .aes_gmac = (esp_aes_gmac_t)esp_aes_gmac, .sha256_vector = (esp_sha256_vector_t)sha256_vector, + .aes_wrap = (esp_aes_wrap_t)aes_wrap, + .aes_unwrap = (esp_aes_unwrap_t)aes_unwrap, }; const mesh_crypto_funcs_t g_wifi_default_mesh_crypto_funcs = { From 2151a0003f85555d3a48164ad31a9126f872adb6 Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Tue, 23 Jun 2026 12:54:33 +0530 Subject: [PATCH 22/27] Fix unwanted encryption of NAFs --- components/esp_wifi/lib | 2 +- .../include/injected/esp_wifi_crypto_types.h | 2 - .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 2 +- .../wifi_apps/nan_app/src/nan_pairing.c | 48 +++++++++---------- 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 3555d024434..d5e8b363713 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 3555d024434f071bd9abf9f5bde3b8dd404fc1ce +Subproject commit d5e8b363713bfea5ea26d8809708752cde93597f diff --git a/components/esp_wifi/remote/include/injected/esp_wifi_crypto_types.h b/components/esp_wifi/remote/include/injected/esp_wifi_crypto_types.h index d0ffffbffd5..c260493c04a 100644 --- a/components/esp_wifi/remote/include/injected/esp_wifi_crypto_types.h +++ b/components/esp_wifi/remote/include/injected/esp_wifi_crypto_types.h @@ -85,7 +85,6 @@ typedef int (*esp_aes_128_decrypt_t)(const unsigned char *key, const unsigned ch * @param n Length of the plaintext key in 64-bit units; * @param plain Plaintext key to be wrapped, n * 64 bits * @param cipher Wrapped key, (n + 1) * 64 bits - * Returns: 0 on success, -1 on failure */ typedef int (*esp_aes_wrap_t)(const unsigned char *kek, size_t kek_len, int n, const unsigned char *plain, unsigned char *cipher); @@ -97,7 +96,6 @@ typedef int (*esp_aes_wrap_t)(const unsigned char *kek, size_t kek_len, int n, c * @param n Length of the plaintext key in 64-bit units; * @param cipher Wrapped key to be unwrapped, (n + 1) * 64 bits * @param plain Plaintext key, n * 64 bits - * Returns: 0 on success, -1 on failure */ typedef int (*esp_aes_unwrap_t)(const unsigned char *kek, size_t kek_len, int n, const unsigned char *cipher, unsigned char *plain); diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c index 517c0fbb6e5..c185d103a56 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c @@ -751,7 +751,7 @@ void nan_app_post_event(int32_t event_id, void* event_data, size_t event_data_si } static void nan_app_service_match_cb(uint8_t sub_id, struct nan_cb_peer_info *peer_info, - struct nan_cb_npba_t *npba) + struct nan_cb_npba_t *npba) { if (!peer_info) { return; diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index 15cf9f366ea..a4b9ebd6c13 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -450,7 +450,29 @@ static struct peer_svc_info *nan_find_peer_svc_exact(uint8_t own_svc_id, uint8_t return NULL; } -static void nan_pairing_nik_fup_timeout_cb(void *eloop_data, void *user_ctx); +static void nan_pairing_nik_fup_timeout_cb(void *eloop_data, void *user_ctx) +{ + struct own_svc_info *own = user_ctx; + wifi_event_nan_pairing_complete_t evt = {0}; + + (void)eloop_data; + + if (!own || !own->nik_fup_pending) { + return; + } + + own->nik_fup_pending = false; + evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; + evt.reason_code = WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT; + MACADDR_COPY(evt.peer_nmi, own->nik_fup_pending_peer_nmi); + nan_app_remove_paired_peer(own->nik_fup_pending_peer_nmi); + struct peer_svc_info *peer = nan_find_peer_svc(own->svc_id, 0, + own->nik_fup_pending_peer_nmi); + esp_nan_complete_pairing(own->svc_id, peer ? peer->svc_id : 0); + nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); + ESP_LOGW(TAG, "Pairing succeeded but NIK caching timed out for peer " MACSTR + " (reason=%u)", MAC2STR(own->nik_fup_pending_peer_nmi), evt.reason_code); +} void nan_pairing_cancel_svc_pending(struct own_svc_info *own) { @@ -479,30 +501,6 @@ static void nan_pairing_arm_pending(struct own_svc_info *own, const uint8_t *pee } } -static void nan_pairing_nik_fup_timeout_cb(void *eloop_data, void *user_ctx) -{ - struct own_svc_info *own = user_ctx; - wifi_event_nan_pairing_complete_t evt = {0}; - - (void)eloop_data; - - if (!own || !own->nik_fup_pending) { - return; - } - - own->nik_fup_pending = false; - evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED; - evt.reason_code = WIFI_NAN_PAIRING_REASON_NIK_FUP_TIMEOUT; - MACADDR_COPY(evt.peer_nmi, own->nik_fup_pending_peer_nmi); - nan_app_remove_paired_peer(own->nik_fup_pending_peer_nmi); - struct peer_svc_info *peer = nan_find_peer_svc(own->svc_id, 0, - own->nik_fup_pending_peer_nmi); - esp_nan_complete_pairing(own->svc_id, peer ? peer->svc_id : 0); - nan_app_post_event(WIFI_EVENT_NAN_PAIRING_CONFIRM, &evt, sizeof(evt)); - ESP_LOGW(TAG, "Pairing succeeded but NIK caching timed out for peer " MACSTR - " (reason=%u)", MAC2STR(own->nik_fup_pending_peer_nmi), evt.reason_code); -} - /** * Build the WFA OUI + GSP protocol header that prefixes a Generic Service * Protocol SSI (Wi-Fi Aware v4.0 §4.2.7). Ported from esp-nsd From 6a22a216875134e0153560858da585b2583e457e Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Wed, 24 Jun 2026 10:34:04 +0530 Subject: [PATCH 23/27] Remove hardcoded GSP subattributes --- .../wifi_apps/nan_app/src/nan_pairing.c | 57 +++---------------- 1 file changed, 8 insertions(+), 49 deletions(-) diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c index a4b9ebd6c13..fcca2e10ec1 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_pairing.c @@ -407,11 +407,6 @@ int esp_nan_construct_nira(uint8_t *frm) #define NAN_PASN_KEY_LIFETIME_NIK_BIT BIT(3) /* NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC is defined at file scope above. */ #define NAN_ATTR_ID_SHARED_KEY_DESC 0x24 -#define GSP_SUBATTR_TRANSPORT_PORT 0x00 -#define GSP_SUBATTR_INSTANCE_NAME 0x03 -#define NAN_PAIRING_SRV_PORT 3333 -#define NAN_PAIRING_SRV_HOSTNAME "ESP-SRV-1234" -#define NAN_PAIRING_SSI_BUF_LEN 64 #define NAN_PAIRING_NIK_FUP_TIMEOUT_SEC 2 struct nan_pairing_fup_ctx { @@ -518,50 +513,17 @@ static int nan_pairing_add_ssi_gsp_attr(uint8_t *buf) } /** - * Append a single GSP sub-attribute (TLV: ID(1) | Length(2 LE) | Value). - * Ported from esp-nsd @c add_gsp_subattr (wa_sd.c). + * Build a GSP SSI (WFA OUI + proto=Generic header only). */ -static int nan_pairing_add_gsp_subattr(uint8_t *buf, uint8_t sub_attr_id, - const void *payload, uint16_t len) +static size_t nan_pairing_build_srv_ssi(uint8_t *buf, size_t buf_len) { uint8_t *p = buf; - *p++ = sub_attr_id; - *((uint16_t *)p) = len; - p += sizeof(uint16_t); - memcpy(p, payload, len); - - return 1 + 2 + len; -} - -/** - * Build a GSP SSI carrying the SRV record (Transport Port + Instance Name). - * Ported from esp-nsd @c get_ssi_for_srv_record (wa_sd.c) with a stack - * buffer and a fixed (hostname, port) instead of dynamic allocation. - */ -static size_t nan_pairing_build_srv_ssi(uint8_t *buf, size_t buf_len, - const char *hostname, uint16_t port) -{ - uint8_t *p = buf; - size_t hostname_len; - size_t need; - - if (!buf || !hostname) { - return 0; - } - hostname_len = strlen(hostname); - need = sizeof(wifi_nan_wfa_ssi_t) - + (1 + 2 + sizeof(port)) - + (1 + 2 + hostname_len); - if (buf_len < need) { + if (!buf || buf_len < sizeof(wifi_nan_wfa_ssi_t)) { return 0; } p += nan_pairing_add_ssi_gsp_attr(p); - p += nan_pairing_add_gsp_subattr(p, GSP_SUBATTR_TRANSPORT_PORT, - &port, sizeof(port)); - p += nan_pairing_add_gsp_subattr(p, GSP_SUBATTR_INSTANCE_NAME, - hostname, hostname_len); return (size_t)(p - buf); } @@ -632,7 +594,7 @@ static esp_err_t nan_app_send_pairing_followup(uint8_t svc_id, uint8_t peer_svc_ uint8_t key_desc[sizeof(struct wpa_eapol_key)] = {0}; uint8_t shared_key_wrapped[sizeof(struct wpa_eapol_key) + sizeof(wrapped)] = {0}; uint8_t nira_attr[NAN_NIRA_ATTR_LEN] = {0}; - uint8_t srv_ssi[NAN_PAIRING_SSI_BUF_LEN] = {0}; + wifi_nan_wfa_ssi_t srv_ssi = {0}; uint8_t nik[NAN_PASN_NIK_LEN]; size_t plain_len; size_t wrapped_len; @@ -701,20 +663,17 @@ static esp_err_t nan_app_send_pairing_followup(uint8_t svc_id, uint8_t peer_svc_ memcpy(w, wrapped, wrapped_len); w += wrapped_len; - /* SSI: GSP (WFA OUI + proto=Generic) carrying an SRV record so iPhone - * has Transport Port + Instance Name to associate with this pairing. */ - srv_ssi_len = nan_pairing_build_srv_ssi(srv_ssi, sizeof(srv_ssi), - NAN_PAIRING_SRV_HOSTNAME, - NAN_PAIRING_SRV_PORT); + /* SSI: GSP (WFA OUI + proto=Generic). */ + srv_ssi_len = nan_pairing_build_srv_ssi((uint8_t *)&srv_ssi, sizeof(srv_ssi)); if (srv_ssi_len == 0) { - ESP_LOGW(TAG, "Pairing follow-up: failed to build SRV SSI"); + ESP_LOGW(TAG, "Pairing follow-up: failed to build GSP SSI"); return ESP_FAIL; } fup.inst_id = svc_id; fup.peer_inst_id = peer_svc_id; MACADDR_COPY(fup.peer_mac, peer_mac); - fup.ssi = srv_ssi; + fup.ssi = (uint8_t *)&srv_ssi; fup.ssi_len = (uint16_t)srv_ssi_len; sk_attr_len = (size_t)(w - shared_key_wrapped); From 525928eee6a0d6ca27dd9ba41ee362d34ae0b1a1 Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Thu, 25 Jun 2026 09:53:29 +0800 Subject: [PATCH 24/27] fix(wifi): added start check when calling smartconfig stop --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index d5e8b363713..b21d66a008e 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit d5e8b363713bfea5ea26d8809708752cde93597f +Subproject commit b21d66a008ec3e9aea6c45a2fef81e1bba363b1a From 183273899ffa845987051066d134167051c8a64f Mon Sep 17 00:00:00 2001 From: "igor.udot" Date: Thu, 25 Jun 2026 14:17:56 +0800 Subject: [PATCH 25/27] ci: skip h21 for coex_unit_test --- .../external_coex_function/pytest_external_coex_function.py | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp_coex/test_apps/external_coex_function/pytest_external_coex_function.py b/components/esp_coex/test_apps/external_coex_function/pytest_external_coex_function.py index 17e46d77cfe..2f3bfdae1df 100644 --- a/components/esp_coex/test_apps/external_coex_function/pytest_external_coex_function.py +++ b/components/esp_coex/test_apps/external_coex_function/pytest_external_coex_function.py @@ -11,6 +11,7 @@ from pytest_embedded_idf.utils import idf_parametrize ['esp32h2', 'esp32c3', 'esp32s2', 'esp32s3', 'esp32c6', 'esp32c61', 'esp32c5', 'esp32s31', 'esp32h4', 'esp32h21'], indirect=['target'], ) +@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners') def test_external_coex_unit_test(dut: Dut) -> None: dut.run_all_single_board_cases() From e08a582209dca84408299788f48b86a5f6f04714 Mon Sep 17 00:00:00 2001 From: yinqingzhao Date: Mon, 29 Jun 2026 09:56:54 +0800 Subject: [PATCH 26/27] fix(wifi): comment out functions from ld files --- components/esp_rom/esp32c2/ld/esp32c2.rom.ld | 2 +- components/esp_rom/esp32c3/ld/esp32c3.rom.ld | 2 +- components/esp_rom/esp32c5/ld/esp32c5.rom.pp.ld | 2 +- components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld | 2 +- components/esp_rom/esp32s3/ld/esp32s3.rom.ld | 2 +- components/esp_rom/esp32s31/ld/esp32s31.rom.pp.ld | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld index 26db884e98f..d2d42a1b3d1 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld @@ -525,7 +525,7 @@ pm_disable_sleep_delay_timer = 0x40001b74; /*pm_dream = 0x40001b78;*/ pm_mac_wakeup = 0x40001b7c; pm_mac_sleep = 0x40001b80; -pm_enable_active_timer = 0x40001b84; +//pm_enable_active_timer = 0x40001b84; pm_enable_sleep_delay_timer = 0x40001b88; pm_local_tsf_process = 0x40001b8c; //pm_set_beacon_filter = 0x40001b90; diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld index 5ef756f3b3f..1cbeb614c12 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld @@ -712,7 +712,7 @@ pm_disable_sleep_delay_timer = 0x40001650; /*pm_dream = 0x40001654;*/ pm_mac_wakeup = 0x40001658; pm_mac_sleep = 0x4000165c; -pm_enable_active_timer = 0x40001660; +//pm_enable_active_timer = 0x40001660; pm_enable_sleep_delay_timer = 0x40001664; pm_local_tsf_process = 0x40001668; //pm_set_beacon_filter = 0x4000166c; diff --git a/components/esp_rom/esp32c5/ld/esp32c5.rom.pp.ld b/components/esp_rom/esp32c5/ld/esp32c5.rom.pp.ld index d710b70b722..9e276e1c605 100644 --- a/components/esp_rom/esp32c5/ld/esp32c5.rom.pp.ld +++ b/components/esp_rom/esp32c5/ld/esp32c5.rom.pp.ld @@ -110,7 +110,7 @@ pm_disable_sleep_delay_timer = 0x40000d50; pm_dream = 0x40000d54; pm_mac_wakeup = 0x40000d58; pm_mac_sleep = 0x40000d5c; -pm_enable_active_timer = 0x40000d60; +//pm_enable_active_timer = 0x40000d60; pm_enable_sleep_delay_timer = 0x40000d64; pm_local_tsf_process = 0x40000d68; //pm_set_beacon_filter = 0x40000d6c; diff --git a/components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld b/components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld index 56dd3a26ef7..432152de049 100644 --- a/components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld +++ b/components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld @@ -107,7 +107,7 @@ pm_disable_sleep_delay_timer = 0x40000cbc; pm_dream = 0x40000cc0; pm_mac_wakeup = 0x40000cc4; pm_mac_sleep = 0x40000cc8; -pm_enable_active_timer = 0x40000ccc; +//pm_enable_active_timer = 0x40000ccc; pm_enable_sleep_delay_timer = 0x40000cd0; pm_local_tsf_process = 0x40000cd4; /*pm_set_beacon_filter = 0x40000cd8;*/ diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld index 2b9b441d211..8f30b35f71b 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld @@ -966,7 +966,7 @@ pm_disable_sleep_delay_timer = 0x40005430; /*pm_dream = 0x4000543c;*/ pm_mac_wakeup = 0x40005448; pm_mac_sleep = 0x40005454; -pm_enable_active_timer = 0x40005460; +//pm_enable_active_timer = 0x40005460; pm_enable_sleep_delay_timer = 0x4000546c; pm_local_tsf_process = 0x40005478; //pm_set_beacon_filter = 0x40005484; diff --git a/components/esp_rom/esp32s31/ld/esp32s31.rom.pp.ld b/components/esp_rom/esp32s31/ld/esp32s31.rom.pp.ld index b2f02c60683..7f1f71b0971 100644 --- a/components/esp_rom/esp32s31/ld/esp32s31.rom.pp.ld +++ b/components/esp_rom/esp32s31/ld/esp32s31.rom.pp.ld @@ -109,7 +109,7 @@ pm_disable_sleep_delay_timer = 0x2f800e6c; pm_dream = 0x2f800e70; pm_mac_wakeup = 0x2f800e74; pm_mac_sleep = 0x2f800e78; -pm_enable_active_timer = 0x2f800e7c; +//pm_enable_active_timer = 0x2f800e7c; pm_enable_sleep_delay_timer = 0x2f800e80; pm_local_tsf_process = 0x2f800e84; pm_set_beacon_filter = 0x2f800e88; @@ -139,7 +139,7 @@ pm_extend_tbtt_adaptive_servo = 0x2f800ee4; pm_scale_listen_interval = 0x2f800ee8; pm_parse_mbssid_element = 0x2f800eec; pm_disconnected_wake = 0x2f800ef0; -pm_tx_data_process = 0x2f800ef4; +//pm_tx_data_process = 0x2f800ef4; pm_is_twt_awake = 0x2f800ef8; pm_enable_twt_keep_alive = 0x2f800efc; pm_twt_on_tsf_timer = 0x2f800f00; From 5e3d5f83030ffc5f0b7891a26eaea0b9833c694f Mon Sep 17 00:00:00 2001 From: yinqingzhao Date: Mon, 29 Jun 2026 10:16:31 +0800 Subject: [PATCH 27/27] fix(wifi): fix tx issues introduced by keeping alive optimization --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index b21d66a008e..9ff50d7c694 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit b21d66a008ec3e9aea6c45a2fef81e1bba363b1a +Subproject commit 9ff50d7c6943a64f11a5962053da1be6f5687493