mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
feat(wifi): NAN encrypted NDP example apps
nan_publisher / nan_subscriber demonstrate the secure NDP path: publisher acts as the responder + UDP echo server, subscriber as the initiator. Both support passphrase and pre-shared PMK modes via menuconfig; PMK hex strings are decoded with the same helper on both sides so endpoints derive matching PMKIDs.
This commit is contained in:
@@ -23,4 +23,38 @@ menu "Example Configuration"
|
||||
help
|
||||
Send a reply to the Follow Up sent by a Subscriber
|
||||
|
||||
menu "Security Configuration"
|
||||
config EXAMPLE_NAN_SECURITY_ENABLED
|
||||
bool "Enable NAN Security"
|
||||
depends on ESP_WIFI_NAN_SECURITY
|
||||
default y
|
||||
|
||||
choice EXAMPLE_NAN_SECURITY_METHOD
|
||||
prompt "Security Method"
|
||||
depends on EXAMPLE_NAN_SECURITY_ENABLED
|
||||
default EXAMPLE_NAN_SEC_METHOD_PASSPHRASE
|
||||
help
|
||||
Choose the method for NAN discovery security.
|
||||
|
||||
config EXAMPLE_NAN_SEC_METHOD_PASSPHRASE
|
||||
bool "Passphrase-based (Password)"
|
||||
config EXAMPLE_NAN_SEC_METHOD_PMK
|
||||
bool "Direct PMK (32-byte hex)"
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_NAN_PASSPHRASE
|
||||
string "Passphrase"
|
||||
depends on EXAMPLE_NAN_SEC_METHOD_PASSPHRASE
|
||||
default "password"
|
||||
help
|
||||
Passphrase for NAN Discovery security.
|
||||
|
||||
config EXAMPLE_NAN_PMK
|
||||
string "Direct PMK (Hex)"
|
||||
depends on EXAMPLE_NAN_SEC_METHOD_PMK
|
||||
default "ee3585063056d164d15454ad39010d4e2640b0d82fb24a2d6899862d273c68bf"
|
||||
help
|
||||
32-byte hex string representing the PMK.
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
@@ -37,6 +38,23 @@
|
||||
static EventGroupHandle_t nan_event_group;
|
||||
static const char *TAG = "publisher";
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_NAN_SEC_METHOD_PMK
|
||||
static bool decode_hex_string(const char *hex, uint8_t *out, size_t out_len)
|
||||
{
|
||||
if (!hex || !out || strlen(hex) != out_len * 2) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < out_len; i++) {
|
||||
unsigned int byte;
|
||||
if (sscanf(hex + 2 * i, "%2x", &byte) != 1) {
|
||||
return false;
|
||||
}
|
||||
out[i] = (uint8_t)byte;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int NAN_RECEIVE = BIT0;
|
||||
uint8_t g_peer_inst_id;
|
||||
static uint8_t g_peer_mac[ETH_ALEN];
|
||||
@@ -105,10 +123,30 @@ void wifi_nan_publish(void)
|
||||
.matching_filter = EXAMPLE_NAN_MATCHING_FILTER,
|
||||
.single_replied_event = 1,
|
||||
/* 0 - All incoming NDP requests will be internally accepted,
|
||||
1 - All incoming NDP requests raise NDP_INDICATION event and require esp_wifi_nan_datapath_resp to accept or reject. */
|
||||
1 - All incoming NDP requests raise NDP_INDICATION event and require esp_wifi_nan_datapath_resp to accept or reject.
|
||||
This example uses 1 to exercise nan_ndp_indication_event_handler(). */
|
||||
.ndp_resp_needed = 1,
|
||||
.datapath_reqd = 1,
|
||||
#ifdef CONFIG_EXAMPLE_NAN_SECURITY_ENABLED
|
||||
.security_reqd = 1,
|
||||
.security_cfg = {
|
||||
.csid_bitmap = WIFI_NAN_CSID_BIT_NCS_SK_128,
|
||||
#ifdef CONFIG_EXAMPLE_NAN_SEC_METHOD_PMK
|
||||
.use_pmk = true,
|
||||
#else
|
||||
.use_pmk = false,
|
||||
.passphrase = CONFIG_EXAMPLE_NAN_PASSPHRASE,
|
||||
#endif
|
||||
},
|
||||
#endif
|
||||
};
|
||||
#if defined(CONFIG_EXAMPLE_NAN_SECURITY_ENABLED) && defined(CONFIG_EXAMPLE_NAN_SEC_METHOD_PMK)
|
||||
if (!decode_hex_string(CONFIG_EXAMPLE_NAN_PMK, publish_cfg.security_cfg.pmk,
|
||||
sizeof(publish_cfg.security_cfg.pmk))) {
|
||||
ESP_LOGE(TAG, "Failed to decode CONFIG_EXAMPLE_NAN_PMK");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
pub_id = esp_wifi_nan_publish_service(&publish_cfg);
|
||||
if (pub_id == 0) {
|
||||
|
||||
@@ -33,4 +33,38 @@ menu "Example Configuration"
|
||||
help
|
||||
Send a message to the Publisher using NAN Follow Up
|
||||
|
||||
menu "Security Configuration"
|
||||
config EXAMPLE_NAN_SECURITY_ENABLED
|
||||
bool "Enable NAN Security"
|
||||
depends on ESP_WIFI_NAN_SECURITY
|
||||
default y
|
||||
|
||||
choice EXAMPLE_NAN_SECURITY_METHOD
|
||||
prompt "Security Method"
|
||||
depends on EXAMPLE_NAN_SECURITY_ENABLED
|
||||
default EXAMPLE_NAN_SEC_METHOD_PASSPHRASE
|
||||
help
|
||||
Choose the method for NAN discovery security.
|
||||
|
||||
config EXAMPLE_NAN_SEC_METHOD_PASSPHRASE
|
||||
bool "Passphrase-based (Password)"
|
||||
config EXAMPLE_NAN_SEC_METHOD_PMK
|
||||
bool "Direct PMK (32-byte hex)"
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_NAN_PASSPHRASE
|
||||
string "Passphrase"
|
||||
depends on EXAMPLE_NAN_SEC_METHOD_PASSPHRASE
|
||||
default "password"
|
||||
help
|
||||
Passphrase for NAN Discovery security. Must match the publisher.
|
||||
|
||||
config EXAMPLE_NAN_PMK
|
||||
string "Direct PMK (Hex)"
|
||||
depends on EXAMPLE_NAN_SEC_METHOD_PMK
|
||||
default "ee3585063056d164d15454ad39010d4e2640b0d82fb24a2d6899862d273c68bf"
|
||||
help
|
||||
32-byte hex string representing the PMK. Must match the publisher.
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -37,6 +37,29 @@
|
||||
|
||||
static const char *TAG = "subscriber";
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_NAN_SEC_METHOD_PMK
|
||||
/* Decode lowercase hex string into a fixed-size byte buffer. Returns true on
|
||||
* success. Mirrors the helper in the publisher example so both endpoints
|
||||
* derive the same PMK from the same hex input. */
|
||||
static bool decode_hex_string(const char *hex, uint8_t *out, size_t out_len)
|
||||
{
|
||||
if (!hex || !out) {
|
||||
return false;
|
||||
}
|
||||
if (strlen(hex) != out_len * 2) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < out_len; i++) {
|
||||
unsigned int byte;
|
||||
if (sscanf(hex + 2 * i, "%2x", &byte) != 1) {
|
||||
return false;
|
||||
}
|
||||
out[i] = (uint8_t)byte;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static EventGroupHandle_t nan_event_group;
|
||||
|
||||
const int NAN_SERVICE_MATCH = BIT0;
|
||||
@@ -45,7 +68,7 @@ const int NDP_FAILED = BIT2;
|
||||
|
||||
static wifi_event_nan_svc_match_t g_svc_match_evt;
|
||||
|
||||
static uint8_t s_ipv6_identifier[8] = {0};
|
||||
static uint8_t s_ipv6_identifier[NAN_IPV6_ADDR_ID_LEN] = {0};
|
||||
|
||||
static void nan_receive_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
@@ -60,6 +83,23 @@ static void nan_receive_event_handler(void *arg, esp_event_base_t event_base,
|
||||
#ifdef CONFIG_EXAMPLE_NAN_SEND_PING
|
||||
static uint8_t g_peer_ndi[ETH_ALEN];
|
||||
|
||||
static void nan_ndp_confirmed_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
wifi_event_ndp_confirm_t *evt = (wifi_event_ndp_confirm_t *)event_data;
|
||||
|
||||
if (evt->status == NDP_STATUS_REJECTED) {
|
||||
ESP_LOGE(TAG, "NDP request to Peer "MACSTR" rejected [NDP ID - %d]", MAC2STR(evt->peer_nmi), evt->ndp_id);
|
||||
xEventGroupSetBits(nan_event_group, NDP_FAILED);
|
||||
} else {
|
||||
memcpy(g_peer_ndi, evt->peer_ndi, sizeof(g_peer_ndi));
|
||||
memcpy(s_ipv6_identifier, evt->ipv6_identifier, sizeof(evt->ipv6_identifier));
|
||||
xEventGroupSetBits(nan_event_group, NDP_CONFIRMED);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_NAN_SEND_PING
|
||||
static void cmd_ping_on_ping_success(esp_ping_handle_t hdl, void *args)
|
||||
{
|
||||
uint8_t ttl;
|
||||
@@ -103,21 +143,6 @@ static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args)
|
||||
esp_ping_delete_session(hdl);
|
||||
}
|
||||
|
||||
static void nan_ndp_confirmed_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
wifi_event_ndp_confirm_t *evt = (wifi_event_ndp_confirm_t *)event_data;
|
||||
|
||||
if (evt->status == NDP_STATUS_REJECTED) {
|
||||
ESP_LOGE(TAG, "NDP request to Peer "MACSTR" rejected [NDP ID - %d]", MAC2STR(evt->peer_nmi), evt->ndp_id);
|
||||
xEventGroupSetBits(nan_event_group, NDP_FAILED);
|
||||
} else {
|
||||
memcpy(g_peer_ndi, evt->peer_ndi, sizeof(g_peer_ndi));
|
||||
memcpy(s_ipv6_identifier, evt->ipv6_identifier, sizeof(evt->ipv6_identifier));
|
||||
xEventGroupSetBits(nan_event_group, NDP_CONFIRMED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ping_nan_peer(esp_netif_t *netif)
|
||||
{
|
||||
esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG();
|
||||
@@ -196,7 +221,26 @@ void wifi_nan_subscribe(void)
|
||||
#endif
|
||||
.matching_filter = EXAMPLE_NAN_MATCHING_FILTER,
|
||||
.single_match_event = 1,
|
||||
#ifdef CONFIG_EXAMPLE_NAN_SECURITY_ENABLED
|
||||
.security_reqd = 1,
|
||||
.security_cfg = {
|
||||
.csid_bitmap = WIFI_NAN_CSID_BIT_NCS_SK_128,
|
||||
#ifdef CONFIG_EXAMPLE_NAN_SEC_METHOD_PMK
|
||||
.use_pmk = true,
|
||||
#else
|
||||
.use_pmk = false,
|
||||
.passphrase = CONFIG_EXAMPLE_NAN_PASSPHRASE,
|
||||
#endif
|
||||
},
|
||||
#endif
|
||||
};
|
||||
#if defined(CONFIG_EXAMPLE_NAN_SECURITY_ENABLED) && defined(CONFIG_EXAMPLE_NAN_SEC_METHOD_PMK)
|
||||
if (!decode_hex_string(CONFIG_EXAMPLE_NAN_PMK, subscribe_cfg.security_cfg.pmk,
|
||||
sizeof(subscribe_cfg.security_cfg.pmk))) {
|
||||
ESP_LOGE(TAG, "Failed to decode CONFIG_EXAMPLE_NAN_PMK");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
sub_id = esp_wifi_nan_subscribe_service(&subscribe_cfg);
|
||||
if (sub_id == 0) {
|
||||
@@ -231,7 +275,8 @@ void wifi_nan_subscribe(void)
|
||||
memcpy(ndp_req.peer_mac, g_svc_match_evt.pub_if_mac, sizeof(ndp_req.peer_mac));
|
||||
esp_wifi_nan_datapath_req(&ndp_req);
|
||||
|
||||
EventBits_t bits_2 = xEventGroupWaitBits(nan_event_group, NDP_CONFIRMED, pdFALSE, pdFALSE, portMAX_DELAY);
|
||||
EventBits_t bits_2 = xEventGroupWaitBits(nan_event_group, NDP_CONFIRMED | NDP_FAILED,
|
||||
pdFALSE, pdFALSE, portMAX_DELAY);
|
||||
if (bits_2 & NDP_CONFIRMED) {
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
ping_nan_peer(nan_netif);
|
||||
|
||||
Reference in New Issue
Block a user