[wifi] Fix crash when WiFi is enabled late alongside ESP-NOW (#17239)

This commit is contained in:
Jonathan Swoboda
2026-06-28 15:16:42 -04:00
committed by Jesse Hills
parent 24d8e99c50
commit 4fbe0d87ec
@@ -179,12 +179,53 @@ void WiFiComponent::wifi_lazy_init_() {
// nor re-register the default WiFi handlers.
if (s_sta_netif == nullptr)
s_sta_netif = esp_netif_create_default_wifi_sta();
if (s_sta_netif == nullptr) {
// Allocation failed; leave wifi_initialized_ false so a later enable() retries.
ESP_LOGE(TAG, "esp_netif_create_default_wifi_sta failed");
return;
}
#ifdef USE_WIFI_AP
if (s_ap_netif == nullptr)
s_ap_netif = esp_netif_create_default_wifi_ap();
#endif // USE_WIFI_AP
// The WiFi driver was started (e.g. by ESP-NOW with the wifi component disabled at
// boot) before our STA netif existed. The default WIFI_EVENT_STA_START handler
// therefore ran with no netif and never called esp_wifi_register_if_rxcb() -- the
// only thing that points the driver's RX path at a netif (it sets
// s_wifi_netifs[WIFI_IF_STA]). A bare esp_netif_action_start() would stop the
// immediate crash (#17232) but leaves RX unbound, so the first association
// associates at L2 yet never receives DHCP replies and times out (#17239). Restart
// the driver now that the netif exists so STA_START re-runs the default handler and
// wires RX correctly. ESP-NOW survives the stop/start (its peer state persists).
// This also matches a self-retry: if esp_wifi_set_storage() below failed on a
// previous wifi_lazy_init_() it returned without setting wifi_initialized_, and
// esp_wifi_init() has since run, so esp_wifi_get_mode() now succeeds here too.
wifi_mode_t mode;
if (esp_wifi_get_mode(&mode) == ESP_OK) {
ESP_LOGD(TAG, "WiFi driver already started without STA netif; restarting to bind it");
esp_err_t err = esp_wifi_stop();
if (err != ESP_OK) {
ESP_LOGW(TAG, "esp_wifi_stop failed: %s", esp_err_to_name(err));
}
// Re-apply RAM storage; the normal init path does this, but it is skipped on
// the self-retry case above, which would otherwise let the driver persist
// credentials to NVS for the rest of the boot.
err = esp_wifi_set_storage(WIFI_STORAGE_RAM);
if (err != ESP_OK) {
ESP_LOGW(TAG, "esp_wifi_set_storage failed: %s", esp_err_to_name(err));
}
err = esp_wifi_start();
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_wifi_start failed: %s", esp_err_to_name(err));
return;
}
s_wifi_started = true;
this->wifi_initialized_ = true;
return;
}
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
if (global_preferences->nvs_handle == 0) {
ESP_LOGW(TAG, "starting wifi without nvs");