Files
esp-protocols/components/mdns/mdns_netif.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

434 lines
14 KiB
C
Raw Normal View History

/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_event.h"
#include "mdns.h"
#include "mdns_private.h"
#include "mdns_mem_caps.h"
#include "mdns_utils.h"
#include "mdns_debug.h"
#include "mdns_browser.h"
#include "mdns_netif.h"
#include "mdns_pcb.h"
#include "mdns_responder.h"
#include "mdns_service.h"
static const char *TAG = "mdns_netif";
#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH
#include "esp_eth.h"
#endif
#if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(5, 1, 0)
#define MDNS_ESP_WIFI_ENABLED CONFIG_SOC_WIFI_SUPPORTED
#else
#define MDNS_ESP_WIFI_ENABLED (CONFIG_ESP_WIFI_ENABLED || CONFIG_ESP_WIFI_REMOTE_ENABLED)
#endif
#if MDNS_ESP_WIFI_ENABLED && (CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP)
#include "esp_wifi.h"
#endif
typedef enum {
MDNS_IF_STA = 0,
MDNS_IF_AP = 1,
MDNS_IF_ETH = 2,
} mdns_predef_if_t;
typedef struct mdns_interfaces mdns_interfaces_t;
struct mdns_interfaces {
const bool predefined;
esp_netif_t *netif;
const mdns_predef_if_t predef_if;
mdns_if_t duplicate;
};
/*
* @brief Internal collection of mdns supported interfaces
*
*/
static mdns_interfaces_t s_esp_netifs[MDNS_MAX_INTERFACES] = {
#if CONFIG_MDNS_PREDEF_NETIF_STA
{ .predefined = true, .netif = NULL, .predef_if = MDNS_IF_STA, .duplicate = MDNS_MAX_INTERFACES },
#endif
#if CONFIG_MDNS_PREDEF_NETIF_AP
{ .predefined = true, .netif = NULL, .predef_if = MDNS_IF_AP, .duplicate = MDNS_MAX_INTERFACES },
#endif
#if CONFIG_MDNS_PREDEF_NETIF_ETH
{ .predefined = true, .netif = NULL, .predef_if = MDNS_IF_ETH, .duplicate = MDNS_MAX_INTERFACES },
#endif
};
/**
* @brief Helper to get either ETH or STA if the other is provided
* Used when two interfaces are on the same subnet
*/
mdns_if_t mdns_priv_netif_get_other_interface(mdns_if_t tcpip_if)
{
if (tcpip_if < MDNS_MAX_INTERFACES) {
return s_esp_netifs[tcpip_if].duplicate;
}
return MDNS_MAX_INTERFACES;
}
/**
* @brief Convert Predefined interface to the netif id from the internal netif list
* @param predef_if Predefined interface enum
* @return Ordinal number of internal list of mdns network interface.
* Returns MDNS_MAX_INTERFACES if the predefined interface wasn't found in the list
*/
static mdns_if_t mdns_if_from_preset(mdns_predef_if_t predef_if)
{
for (int i = 0; i < MDNS_MAX_INTERFACES; ++i) {
if (s_esp_netifs[i].predefined && s_esp_netifs[i].predef_if == predef_if) {
return i;
}
}
return MDNS_MAX_INTERFACES;
}
/**
* @brief Convert Predefined interface to esp-netif handle
* @param predef_if Predefined interface enum
* @return esp_netif pointer from system list of network interfaces
*/
static inline esp_netif_t *netif_from_preset(mdns_predef_if_t predef_if)
{
switch (predef_if) {
case MDNS_IF_STA:
return esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
case MDNS_IF_AP:
return esp_netif_get_handle_from_ifkey("WIFI_AP_DEF");
#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH
case MDNS_IF_ETH:
return esp_netif_get_handle_from_ifkey("ETH_DEF");
#endif
default:
return NULL;
}
}
esp_netif_t *mdns_priv_get_esp_netif(mdns_if_t tcpip_if)
{
if (tcpip_if < MDNS_MAX_INTERFACES) {
if (s_esp_netifs[tcpip_if].netif == NULL && s_esp_netifs[tcpip_if].predefined) {
// If the local copy is NULL and this netif is predefined -> we can find it in the global netif list
s_esp_netifs[tcpip_if].netif = netif_from_preset(s_esp_netifs[tcpip_if].predef_if);
// failing to find it means that the netif is *not* available -> return NULL
}
return s_esp_netifs[tcpip_if].netif;
}
return NULL;
}
/*
* @brief Clean internal mdns interface's pointer
*/
void mdns_priv_netif_disable(mdns_if_t tcpip_if)
{
if (tcpip_if < MDNS_MAX_INTERFACES) {
s_esp_netifs[tcpip_if].netif = NULL;
}
}
/*
* @brief Convert esp-netif handle to mdns if
*/
static mdns_if_t get_if_from_netif(esp_netif_t *esp_netif)
{
for (int i = 0; i < MDNS_MAX_INTERFACES; ++i) {
// The predefined netifs in the static array are NULL when firstly calling this function
// if IPv4 is disabled. Set these netifs here.
if (s_esp_netifs[i].netif == NULL && s_esp_netifs[i].predefined) {
s_esp_netifs[i].netif = netif_from_preset(s_esp_netifs[i].predef_if);
}
if (esp_netif == s_esp_netifs[i].netif) {
return i;
}
}
return MDNS_MAX_INTERFACES;
}
static esp_err_t post_custom_action(mdns_if_t mdns_if, mdns_event_actions_t event_action)
{
if (!mdns_priv_is_server_init() || mdns_if >= MDNS_MAX_INTERFACES) {
return ESP_ERR_INVALID_STATE;
}
mdns_action_t *action = (mdns_action_t *)mdns_mem_calloc(1, sizeof(mdns_action_t));
if (!action) {
HOOK_MALLOC_FAILED;
return ESP_ERR_NO_MEM;
}
action->type = ACTION_SYSTEM_EVENT;
action->data.sys_event.event_action = event_action;
action->data.sys_event.interface = mdns_if;
if (!mdns_priv_queue_action(action)) {
mdns_mem_free(action);
}
return ESP_OK;
}
/**
* @brief Dispatch interface changes based on system events
*/
static inline void post_disable_pcb(mdns_predef_if_t preset_if, mdns_ip_protocol_t protocol)
{
post_custom_action(mdns_if_from_preset(preset_if),
protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_EVENT_DISABLE_IP4 : MDNS_EVENT_DISABLE_IP6);
}
static inline void post_enable_pcb(mdns_predef_if_t preset_if, mdns_ip_protocol_t protocol)
{
post_custom_action(mdns_if_from_preset(preset_if),
protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_EVENT_ENABLE_IP4 : MDNS_EVENT_ENABLE_IP6);
}
static inline void post_announce_pcb(mdns_predef_if_t preset_if, mdns_ip_protocol_t protocol)
{
post_custom_action(mdns_if_from_preset(preset_if),
protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_EVENT_ANNOUNCE_IP4 : MDNS_EVENT_ANNOUNCE_IP6);
}
#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH
static void handle_system_event_for_preset(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
if (!mdns_priv_is_server_init()) {
return;
}
#if MDNS_ESP_WIFI_ENABLED && (CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP)
if (event_base == WIFI_EVENT) {
esp_netif_dhcp_status_t dcst;
switch (event_id) {
case WIFI_EVENT_STA_CONNECTED:
if (!esp_netif_dhcpc_get_status(netif_from_preset(MDNS_IF_STA), &dcst)) {
if (dcst == ESP_NETIF_DHCP_STOPPED) {
post_enable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4);
}
}
break;
case WIFI_EVENT_STA_DISCONNECTED:
post_disable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4);
post_disable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V6);
break;
case WIFI_EVENT_AP_START:
post_enable_pcb(MDNS_IF_AP, MDNS_IP_PROTOCOL_V4);
break;
case WIFI_EVENT_AP_STOP:
post_disable_pcb(MDNS_IF_AP, MDNS_IP_PROTOCOL_V4);
post_disable_pcb(MDNS_IF_AP, MDNS_IP_PROTOCOL_V6);
break;
default:
break;
}
} else
#endif
#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH
if (event_base == ETH_EVENT) {
esp_netif_dhcp_status_t dcst;
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
if (!esp_netif_dhcpc_get_status(netif_from_preset(MDNS_IF_ETH), &dcst)) {
if (dcst == ESP_NETIF_DHCP_STOPPED) {
post_enable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4);
}
}
break;
case ETHERNET_EVENT_DISCONNECTED:
post_disable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4);
post_disable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V6);
break;
default:
break;
}
} else
#endif
if (event_base == IP_EVENT) {
switch (event_id) {
case IP_EVENT_STA_GOT_IP:
post_enable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4);
post_announce_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V6);
break;
#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH
case IP_EVENT_ETH_GOT_IP:
post_enable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4);
break;
#endif
case IP_EVENT_GOT_IP6: {
ip_event_got_ip6_t *event = (ip_event_got_ip6_t *) event_data;
mdns_if_t mdns_if = get_if_from_netif(event->esp_netif);
if (mdns_if >= MDNS_MAX_INTERFACES) {
return;
}
post_enable_pcb(mdns_if, MDNS_IP_PROTOCOL_V6);
post_announce_pcb(mdns_if, MDNS_IP_PROTOCOL_V4);
mdns_priv_browse_send_all(mdns_if);
}
break;
default:
break;
}
}
}
#endif /* CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH */
static inline void set_default_duplicated_interfaces(void)
{
mdns_if_t wifi_sta_if = MDNS_MAX_INTERFACES;
mdns_if_t eth_if = MDNS_MAX_INTERFACES;
for (mdns_if_t i = 0; i < MDNS_MAX_INTERFACES; i++) {
if (s_esp_netifs[i].predefined && s_esp_netifs[i].predef_if == MDNS_IF_STA) {
wifi_sta_if = i;
}
if (s_esp_netifs[i].predefined && s_esp_netifs[i].predef_if == MDNS_IF_ETH) {
eth_if = i;
}
}
if (wifi_sta_if != MDNS_MAX_INTERFACES && eth_if != MDNS_MAX_INTERFACES) {
s_esp_netifs[wifi_sta_if].duplicate = eth_if;
s_esp_netifs[eth_if].duplicate = wifi_sta_if;
}
}
void mdns_priv_netif_unregister_predefined_handlers(void)
{
#if MDNS_ESP_WIFI_ENABLED && (CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP)
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, handle_system_event_for_preset);
#endif
#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH
esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, handle_system_event_for_preset);
#endif
#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH
esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, handle_system_event_for_preset);
#endif
}
esp_err_t mdns_priv_netif_init(void)
{
esp_err_t err = ESP_OK;
// zero-out local copy of netifs to initiate a fresh search by interface key whenever a netif ptr is needed
for (mdns_if_t i = 0; i < MDNS_MAX_INTERFACES; ++i) {
s_esp_netifs[i].netif = NULL;
}
#if MDNS_ESP_WIFI_ENABLED && (CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP)
if ((err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, handle_system_event_for_preset, NULL)) != ESP_OK) {
goto free_event_handlers;
}
#endif
#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH
if ((err = esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, handle_system_event_for_preset, NULL)) != ESP_OK) {
goto free_event_handlers;
}
#endif
#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH
if ((err = esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, handle_system_event_for_preset, NULL)) != ESP_OK) {
goto free_event_handlers;
}
#endif
#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH
set_default_duplicated_interfaces();
#endif
uint8_t i;
#ifdef CONFIG_LWIP_IPV6
esp_ip6_addr_t tmp_addr6;
#endif
#ifdef CONFIG_LWIP_IPV4
esp_netif_ip_info_t if_ip_info;
#endif
for (i = 0; i < MDNS_MAX_INTERFACES; i++) {
#ifdef CONFIG_LWIP_IPV6
if (!esp_netif_get_ip6_linklocal(mdns_priv_get_esp_netif(i), &tmp_addr6) && !mdns_utils_ipv6_address_is_zero(tmp_addr6)) {
mdns_priv_pcb_enable(i, MDNS_IP_PROTOCOL_V6);
}
#endif
#ifdef CONFIG_LWIP_IPV4
if (!esp_netif_get_ip_info(mdns_priv_get_esp_netif(i), &if_ip_info) && if_ip_info.ip.addr) {
mdns_priv_pcb_enable(i, MDNS_IP_PROTOCOL_V4);
}
#endif
}
return ESP_OK;
#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH
free_event_handlers:
mdns_priv_netif_unregister_predefined_handlers();
#endif
return err;
}
esp_err_t mdns_priv_netif_deinit(void)
{
for (int i = 0; i < MDNS_MAX_INTERFACES; i++) {
mdns_priv_pcb_disable(i, MDNS_IP_PROTOCOL_V6);
mdns_priv_pcb_disable(i, MDNS_IP_PROTOCOL_V4);
s_esp_netifs[i].duplicate = MDNS_MAX_INTERFACES;
}
return ESP_OK;
}
/*
* Public Methods
* */
esp_err_t mdns_netif_action(esp_netif_t *esp_netif, mdns_event_actions_t event_action)
{
return post_custom_action(get_if_from_netif(esp_netif), event_action);
}
esp_err_t mdns_register_netif(esp_netif_t *esp_netif)
{
if (!mdns_priv_is_server_init()) {
return ESP_ERR_INVALID_STATE;
}
esp_err_t err = ESP_ERR_NO_MEM;
mdns_priv_service_lock();
for (mdns_if_t i = 0; i < MDNS_MAX_INTERFACES; ++i) {
if (s_esp_netifs[i].netif == esp_netif) {
mdns_priv_service_unlock();
return ESP_ERR_INVALID_STATE;
}
}
for (mdns_if_t i = 0; i < MDNS_MAX_INTERFACES; ++i) {
if (!s_esp_netifs[i].predefined && s_esp_netifs[i].netif == NULL) {
s_esp_netifs[i].netif = esp_netif;
err = ESP_OK;
break;
}
}
mdns_priv_service_unlock();
return err;
}
esp_err_t mdns_unregister_netif(esp_netif_t *esp_netif)
{
if (!mdns_priv_is_server_init()) {
return ESP_ERR_INVALID_STATE;
}
esp_err_t err = ESP_ERR_NOT_FOUND;
mdns_priv_service_lock();
for (mdns_if_t i = 0; i < MDNS_MAX_INTERFACES; ++i) {
if (!s_esp_netifs[i].predefined && s_esp_netifs[i].netif == esp_netif) {
s_esp_netifs[i].netif = NULL;
err = ESP_OK;
break;
}
}
mdns_priv_service_lock();
return err;
}