fix(nan): Add service hash to NVS to maintain pairing states after reset

This commit is contained in:
Akshat Agrawal
2026-06-12 18:12:20 +05:30
parent afd5a13e71
commit 601faef85b
5 changed files with 61 additions and 15 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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_ */