Просмотр исходного кода

Merge branch 'feature/mdns_dynamic_interfaces' into 'master'

mdns: Add support for dynamic network interfaces

Closes IDF-939

See merge request espressif/esp-idf!14875
David Čermák 3 лет назад
Родитель
Сommit
0b58f987cd

+ 1 - 0
.gitlab/ci/target-test.yml

@@ -309,6 +309,7 @@ example_test_001A:
 
 example_test_001B:
   extends: .example_test_esp32_template
+  parallel: 2
   tags:
     - ESP32
     - Example_EthKitV1

+ 37 - 3
components/mdns/Kconfig

@@ -1,5 +1,13 @@
 menu "mDNS"
 
+    config MDNS_MAX_INTERFACES
+        int "Max number of interfaces"
+        range 1 9
+        default 3
+        help
+            Number of network interfaces to be served by the mDNS library.
+            Lowering this number helps to reduce some static RAM usage.
+
     config MDNS_MAX_SERVICES
         int "Max number of services"
         range 1 64
@@ -64,7 +72,7 @@ menu "mDNS"
             Currently the only strict feature: Do not repeat original questions in response packets
             (defined in RFC6762 sec. 6).
             Default configuration is 0, i.e. non-strict mode, since some implementations,
-            such as lwIP mdns resolver (used by standard POSIX API like getaddrinfo, gethostbyname)
+            such as lwIP mDNS resolver (used by standard POSIX API like getaddrinfo, gethostbyname)
             could not correctly resolve advertised names.
 
     config MDNS_TIMER_PERIOD_MS
@@ -76,10 +84,10 @@ menu "mDNS"
             and schedules mDNS searches.
 
     config MDNS_NETWORKING_SOCKET
-        bool "Use BSD sockets for mdns networking"
+        bool "Use BSD sockets for mDNS networking"
         default n
         help
-            Enables optional mdns networking implementation using BSD sockets
+            Enables optional mDNS networking implementation using BSD sockets
             in UDP multicast mode.
             This option creates a new thread to serve receiving packets (TODO).
             This option uses additional N sockets, where N is number of interfaces.
@@ -90,4 +98,30 @@ menu "mDNS"
         help
             Enables adding multiple service instances under the same service type.
 
+    menu "MDNS Predefined interfaces"
+
+        config MDNS_PREDEF_NETIF_STA
+            bool "Use predefined interface for WiFi Station"
+            default y
+            help
+                Set up mDNS for the default WiFi station.
+                Disable this option if you do not need mDNS on default WiFi STA.
+
+        config MDNS_PREDEF_NETIF_AP
+            bool "Use predefined interface for WiFi Access Point"
+            default y
+            help
+                Set up mDNS for the default WiFi Access Point.
+                Disable this option if you do not need mDNS on default WiFi AP.
+
+        config MDNS_PREDEF_NETIF_ETH
+            bool "Use predefined interface for Ethernet"
+            depends on ETH_ENABLED
+            default y
+            help
+                Set up mDNS for the default Ethernet interface.
+                Disable this option if you do not need mDNS on default Ethernet.
+
+    endmenu # MDNS Predefined interfaces
+
 endmenu

+ 58 - 8
components/mdns/include/mdns.h

@@ -26,6 +26,16 @@ extern "C" {
  */
 typedef struct mdns_search_once_s mdns_search_once_t;
 
+
+typedef enum {
+    MDNS_EVENT_ENABLE_IP4                   = 1 << 1,
+    MDNS_EVENT_ENABLE_IP6                   = 1 << 2,
+    MDNS_EVENT_ANNOUNCE_IP4                 = 1 << 3,
+    MDNS_EVENT_ANNOUNCE_IP6                 = 1 << 4,
+    MDNS_EVENT_DISABLE_IP4                  = 1 << 5,
+    MDNS_EVENT_DISABLE_IP6                  = 1 << 6,
+} mdns_event_actions_t;
+
 /**
  * @brief   mDNS enum to specify the ip_protocol type
  */
@@ -52,13 +62,6 @@ typedef struct mdns_ip_addr_s {
     struct mdns_ip_addr_s * next;           /*!< next IP, or NULL for the last IP in the list */
 } mdns_ip_addr_t;
 
-typedef enum mdns_if_internal {
-    MDNS_IF_STA = 0,
-    MDNS_IF_AP = 1,
-    MDNS_IF_ETH = 2,
-    MDNS_IF_MAX
-} mdns_if_t;
-
 /**
  * @brief mDNS query type to be explicitly set to either Unicast or Multicast
  */
@@ -73,7 +76,7 @@ typedef enum {
 typedef struct mdns_result_s {
     struct mdns_result_s * next;            /*!< next result, or NULL for the last result in the list */
 
-    mdns_if_t tcpip_if;                     /*!< interface index */
+    esp_netif_t* esp_netif;                 /*!< ptr to corresponding esp-netif */
     uint32_t ttl;                           /*!< time to live */
 
     mdns_ip_protocol_t ip_protocol;         /*!< ip_protocol type of the interface (v4/v6) */
@@ -716,6 +719,53 @@ esp_err_t mdns_query_a(const char * host_name, uint32_t timeout, esp_ip4_addr_t
 esp_err_t mdns_query_aaaa(const char * host_name, uint32_t timeout, esp_ip6_addr_t * addr);
 #endif
 
+
+/**
+ * @brief   Register custom esp_netif with mDNS functionality
+ *          mDNS service runs by default on preconfigured interfaces (STA, AP, ETH).
+ *          This API enables running the service on any customized interface,
+ *          either using standard WiFi or Ethernet driver or any kind of user defined driver.
+ *
+ * @param   esp_netif Pointer to esp-netif interface
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_STATE  mDNS is not running or this netif is already registered
+ *     - ESP_ERR_NO_MEM         not enough memory for this in interface in the netif list (see CONFIG_MDNS_MAX_INTERFACES)
+ */
+esp_err_t mdns_register_netif(esp_netif_t *esp_netif);
+
+/**
+ * @brief   Unregister esp-netif already registered in mDNS service
+ *
+ * @param   esp_netif Pointer to esp-netif interface
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_STATE  mDNS is not running
+ *     - ESP_ERR_NOT_FOUND      this esp-netif was not registered in mDNS service
+ */
+esp_err_t mdns_unregister_netif(esp_netif_t *esp_netif);
+
+/**
+ * @brief   Set esp_netif to a desired state, or perform a desired action, such as enable/disable this interface
+ *          or send announcement packets to this netif
+ *
+ *  * This function is used to enable (probe, resolve conflicts and announce), announce, or disable (send bye) mDNS
+ *  services on the specified network interface.
+ *  * This function must be called if users registers a specific interface using mdns_register_netif()
+ *  to enable mDNS services on that interface.
+ *  * This function could be used in IP/connection event handlers to automatically enable/announce mDNS services
+ *  when network properties change and/or disable them on disconnection.
+ *
+ * @param esp_netif  Pointer to esp-netif interface
+ * @param event_action  Disable/Enable/Announce on this interface over IPv4/IPv6 protocol.
+ *                      Actions enumerated in mdns_event_actions_t type.
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_STATE  mDNS is not running or this netif is not registered
+ *     - ESP_ERR_NO_MEM         memory error
+ */
+esp_err_t mdns_netif_action(esp_netif_t *esp_netif, mdns_event_actions_t event_action);
+
 #ifdef __cplusplus
 }
 #endif

+ 295 - 102
components/mdns/mdns.c

@@ -57,32 +57,98 @@ static mdns_result_t * _mdns_search_result_add_ptr(mdns_search_once_t * search,
 static bool _mdns_append_host_list_in_services(mdns_out_answer_t ** destination, mdns_srv_item_t * services[], size_t services_len, bool flush, bool bye);
 static bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool bye);
 static void _mdns_remap_self_service_hostname(const char *old_hostname, const char *new_hostname);
+static esp_err_t mdns_post_custom_action_tcpip_if(mdns_if_t mdns_if, mdns_event_actions_t event_action);
+
+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 esp_netif_t * s_esp_netifs[MDNS_IF_MAX] = {};
+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  Convert mdns if to esp-netif handle
+
+/**
+ * @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
  */
-esp_netif_t *_mdns_get_esp_netif(mdns_if_t tcpip_if)
+static mdns_if_t mdns_if_from_preset_if(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 *esp_netif_from_preset_if(mdns_predef_if_t predef_if)
 {
-    if (tcpip_if < MDNS_IF_MAX) {
-        if (s_esp_netifs[tcpip_if] == NULL) {
-            // if local netif copy is NULL, try to search for the default interface key
-            if (tcpip_if == MDNS_IF_STA) {
-                s_esp_netifs[MDNS_IF_STA] = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
-            } else if (tcpip_if == MDNS_IF_AP) {
-                s_esp_netifs[MDNS_IF_AP] = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF");
+    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
-            } else if (tcpip_if == MDNS_IF_ETH) {
-                s_esp_netifs[MDNS_IF_ETH] = esp_netif_get_handle_from_ifkey("ETH_DEF");
+        case MDNS_IF_ETH:
+            return esp_netif_get_handle_from_ifkey("ETH_DEF");
 #endif
-            }
+        default:
+            return NULL;
+    }
+}
+
+/**
+ * @brief Gets the actual esp_netif pointer from the internal network interface list
+ *
+ * The supplied ordinal number could
+ * - point to a predef netif -> "STA", "AP", "ETH"
+ *      - if no entry in the list (NULL) -> check if the system added this netif
+ * - point to a custom netif -> just return the entry in the list
+ *      - users is responsible for the lifetime of this netif (to be valid between mdns-init -> deinit)
+ *
+ * @param tcpip_if Ordinal number of the interface
+ * @return Pointer ot the esp_netif object if the interface is available, NULL otherwise
+ */
+esp_netif_t *_mdns_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 = esp_netif_from_preset_if(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];
+        return s_esp_netifs[tcpip_if].netif;
     }
     return NULL;
 }
@@ -92,8 +158,8 @@ esp_netif_t *_mdns_get_esp_netif(mdns_if_t tcpip_if)
  * @brief Clean internal mdns interface's pointer
  */
 static inline void _mdns_clean_netif_ptr(mdns_if_t tcpip_if) {
-    if (tcpip_if < MDNS_IF_MAX) {
-        s_esp_netifs[tcpip_if] = NULL;
+    if (tcpip_if < MDNS_MAX_INTERFACES) {
+        s_esp_netifs[tcpip_if].netif = NULL;
     }
 }
 
@@ -101,13 +167,14 @@ static inline void _mdns_clean_netif_ptr(mdns_if_t tcpip_if) {
 /*
  * @brief  Convert esp-netif handle to mdns if
  */
-static mdns_if_t _mdns_get_if_from_esp_netif(esp_netif_t *interface)
+static mdns_if_t _mdns_get_if_from_esp_netif(esp_netif_t *esp_netif)
 {
-    for (int i=0; i<MDNS_IF_MAX; ++i) {
-        if (interface == s_esp_netifs[i])
+    for (int i=0; i<MDNS_MAX_INTERFACES; ++i) {
+        if (esp_netif == s_esp_netifs[i].netif) {
             return i;
+        }
     }
-    return MDNS_IF_MAX;
+    return MDNS_MAX_INTERFACES;
 }
 
 
@@ -1057,12 +1124,10 @@ static uint16_t _mdns_append_question(uint8_t * packet, uint16_t * index, mdns_o
  */
 static mdns_if_t _mdns_get_other_if (mdns_if_t tcpip_if)
 {
-    if (tcpip_if == MDNS_IF_STA) {
-        return MDNS_IF_ETH;
-    } else if (tcpip_if == MDNS_IF_ETH) {
-        return MDNS_IF_STA;
+    if (tcpip_if < MDNS_MAX_INTERFACES) {
+        return s_esp_netifs[tcpip_if].duplicate;
     }
-    return MDNS_IF_MAX;
+    return MDNS_MAX_INTERFACES;
 }
 
 /**
@@ -1071,7 +1136,7 @@ static mdns_if_t _mdns_get_other_if (mdns_if_t tcpip_if)
 static bool _mdns_if_is_dup(mdns_if_t tcpip_if)
 {
     mdns_if_t other_if = _mdns_get_other_if (tcpip_if);
-    if (other_if == MDNS_IF_MAX) {
+    if (other_if == MDNS_MAX_INTERFACES) {
         return false;
     }
     if (_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].state == PCB_DUP
@@ -2077,7 +2142,7 @@ static void _mdns_send_bye(mdns_srv_item_t ** services, size_t len, bool include
         return;
     }
 
-    for (i=0; i<MDNS_IF_MAX; i++) {
+    for (i=0; i<MDNS_MAX_INTERFACES; i++) {
         for (j=0; j<MDNS_IP_PROTOCOL_MAX; j++) {
             if (_mdns_server->interfaces[i].pcbs[j].pcb && _mdns_server->interfaces[i].pcbs[j].state == PCB_RUNNING) {
                 _mdns_pcb_send_bye((mdns_if_t)i, (mdns_ip_protocol_t)j, services, len, include_ip);
@@ -2135,7 +2200,7 @@ static void _mdns_announce_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protoco
 static void _mdns_probe_all_pcbs(mdns_srv_item_t ** services, size_t len, bool probe_ip, bool clear_old_probe)
 {
     uint8_t i, j;
-    for (i=0; i<MDNS_IF_MAX; i++) {
+    for (i=0; i<MDNS_MAX_INTERFACES; i++) {
         for (j=0; j<MDNS_IP_PROTOCOL_MAX; j++) {
             if (_mdns_server->interfaces[i].pcbs[j].pcb) {
                 mdns_pcb_t * _pcb = &_mdns_server->interfaces[i].pcbs[j];
@@ -2157,7 +2222,7 @@ static void _mdns_probe_all_pcbs(mdns_srv_item_t ** services, size_t len, bool p
 static void _mdns_announce_all_pcbs(mdns_srv_item_t ** services, size_t len, bool include_ip)
 {
     uint8_t i, j;
-    for (i=0; i<MDNS_IF_MAX; i++) {
+    for (i=0; i<MDNS_MAX_INTERFACES; i++) {
         for (j=0; j<MDNS_IP_PROTOCOL_MAX; j++) {
             _mdns_announce_pcb((mdns_if_t)i, (mdns_ip_protocol_t)j, services, len, include_ip);
         }
@@ -2642,7 +2707,7 @@ static void _mdns_dup_interface(mdns_if_t tcpip_if)
 {
     uint8_t i;
     mdns_if_t other_if = _mdns_get_other_if (tcpip_if);
-    if (other_if == MDNS_IF_MAX) {
+    if (other_if == MDNS_MAX_INTERFACES) {
         return; // no other interface found
     }
     for (i=0; i<MDNS_IP_PROTOCOL_MAX; i++) {
@@ -2678,7 +2743,7 @@ static int _mdns_check_a_collision(esp_ip4_addr_t * ip, mdns_if_t tcpip_if)
     } else if (ret < 0) {
         //is it the other interface?
         mdns_if_t other_if = _mdns_get_other_if (tcpip_if);
-        if (other_if == MDNS_IF_MAX) {
+        if (other_if == MDNS_MAX_INTERFACES) {
             return 1;//AP interface! They win
         }
         if (esp_netif_get_ip_info(_mdns_get_esp_netif(other_if), &other_ip_info)) {
@@ -2713,7 +2778,7 @@ static int _mdns_check_aaaa_collision(esp_ip6_addr_t * ip, mdns_if_t tcpip_if)
     } else if (ret < 0) {
         //is it the other interface?
         mdns_if_t other_if = _mdns_get_other_if (tcpip_if);
-        if (other_if == MDNS_IF_MAX) {
+        if (other_if == MDNS_MAX_INTERFACES) {
             return 1;//AP interface! They win
         }
         if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(other_if), &other_ip6)) {
@@ -3460,7 +3525,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet)
                 if (search_result && search_result->type == MDNS_TYPE_PTR) {
                     result = search_result->result;
                     while (result) {
-                        if (packet->tcpip_if == result->tcpip_if
+                        if (_mdns_get_esp_netif(packet->tcpip_if) == result->esp_netif
                             && packet->ip_protocol == result->ip_protocol
                             && result->instance_name && !strcmp(name->host, result->instance_name)) {
                             break;
@@ -3560,7 +3625,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet)
                     if (search_result->type == MDNS_TYPE_PTR) {
                         result = search_result->result;
                         while (result) {
-                            if (packet->tcpip_if == result->tcpip_if
+                            if (_mdns_get_esp_netif(packet->tcpip_if) == result->esp_netif
                                 && packet->ip_protocol == result->ip_protocol
                                 && result->instance_name && !strcmp(name->host, result->instance_name)) {
                                 break;
@@ -3768,7 +3833,7 @@ void _mdns_disable_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
         _mdns_clear_pcb_tx_queue_head(tcpip_if, ip_protocol);
         _mdns_pcb_deinit(tcpip_if, ip_protocol);
         mdns_if_t other_if = _mdns_get_other_if (tcpip_if);
-        if (other_if != MDNS_IF_MAX && _mdns_server->interfaces[other_if].pcbs[ip_protocol].state == PCB_DUP) {
+        if (other_if != MDNS_MAX_INTERFACES && _mdns_server->interfaces[other_if].pcbs[ip_protocol].state == PCB_DUP) {
             _mdns_server->interfaces[other_if].pcbs[ip_protocol].state = PCB_OFF;
             _mdns_enable_pcb(other_if, ip_protocol);
         }
@@ -3776,11 +3841,54 @@ void _mdns_disable_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
     _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].state = PCB_OFF;
 }
 
+/**
+ * @brief  Performs interface changes based on system events or custom commands
+ */
+static void perform_event_action(mdns_if_t mdns_if, mdns_event_actions_t action)
+{
+    if (!_mdns_server || mdns_if >= MDNS_MAX_INTERFACES) {
+        return;
+    }
+    if (action & MDNS_EVENT_ENABLE_IP4) {
+        _mdns_enable_pcb(mdns_if, MDNS_IP_PROTOCOL_V4);
+    }
+    if (action & MDNS_EVENT_ENABLE_IP6) {
+        _mdns_enable_pcb(mdns_if, MDNS_IP_PROTOCOL_V6);
+    }
+    if (action & MDNS_EVENT_DISABLE_IP4) {
+        _mdns_disable_pcb(mdns_if, MDNS_IP_PROTOCOL_V4);
+    }
+    if (action & MDNS_EVENT_DISABLE_IP6) {
+        _mdns_disable_pcb(mdns_if, MDNS_IP_PROTOCOL_V6);
+    }
+    if (action & MDNS_EVENT_ANNOUNCE_IP4) {
+        _mdns_announce_pcb(mdns_if, MDNS_IP_PROTOCOL_V4, NULL, 0, true);
+    }
+    if (action & MDNS_EVENT_ANNOUNCE_IP6) {
+        _mdns_announce_pcb(mdns_if, MDNS_IP_PROTOCOL_V6, NULL, 0, true);
+    }
+}
+
 /**
  * @brief  Dispatch interface changes based on system events
  */
-static void _mdns_handle_system_event(esp_event_base_t event_base,
-                                      int32_t event_id, esp_netif_t* interface)
+static inline void post_mdns_disable_pcb(mdns_predef_if_t preset_if, mdns_ip_protocol_t protocol)
+{
+    mdns_post_custom_action_tcpip_if(mdns_if_from_preset_if(preset_if), protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_EVENT_DISABLE_IP4 : MDNS_EVENT_DISABLE_IP6);
+}
+
+static inline void post_mdns_enable_pcb(mdns_predef_if_t preset_if, mdns_ip_protocol_t protocol)
+{
+    mdns_post_custom_action_tcpip_if(mdns_if_from_preset_if(preset_if), protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_EVENT_ENABLE_IP4 : MDNS_EVENT_ENABLE_IP6);
+}
+
+static inline void post_mdns_announce_pcb(mdns_predef_if_t preset_if, mdns_ip_protocol_t protocol)
+{
+    mdns_post_custom_action_tcpip_if(mdns_if_from_preset_if(preset_if), protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_EVENT_ANNOUNCE_IP4 : MDNS_EVENT_ANNOUNCE_IP6);
+}
+
+void mdns_preset_if_handle_system_event(void *arg, esp_event_base_t event_base,
+                                        int32_t event_id, void *event_data)
 {
     if (!_mdns_server) {
         return;
@@ -3790,22 +3898,22 @@ static void _mdns_handle_system_event(esp_event_base_t event_base,
     if (event_base == WIFI_EVENT) {
         switch(event_id) {
             case WIFI_EVENT_STA_CONNECTED:
-                if (!esp_netif_dhcpc_get_status(_mdns_get_esp_netif(MDNS_IF_STA), &dcst)) {
+                if (!esp_netif_dhcpc_get_status(esp_netif_from_preset_if(MDNS_IF_STA), &dcst)) {
                     if (dcst == ESP_NETIF_DHCP_STOPPED) {
-                        _mdns_enable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4);
+                        post_mdns_enable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4);
                     }
                 }
                 break;
             case WIFI_EVENT_STA_DISCONNECTED:
-                _mdns_disable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4);
-                _mdns_disable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V6);
+                post_mdns_disable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4);
+                post_mdns_disable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V6);
                 break;
             case WIFI_EVENT_AP_START:
-                _mdns_enable_pcb(MDNS_IF_AP, MDNS_IP_PROTOCOL_V4);
+                post_mdns_enable_pcb(MDNS_IF_AP, MDNS_IP_PROTOCOL_V4);
                 break;
             case WIFI_EVENT_AP_STOP:
-                _mdns_disable_pcb(MDNS_IF_AP, MDNS_IP_PROTOCOL_V4);
-                _mdns_disable_pcb(MDNS_IF_AP, MDNS_IP_PROTOCOL_V6);
+                post_mdns_disable_pcb(MDNS_IF_AP, MDNS_IP_PROTOCOL_V4);
+                post_mdns_disable_pcb(MDNS_IF_AP, MDNS_IP_PROTOCOL_V6);
                 break;
             default:
                 break;
@@ -3815,15 +3923,15 @@ static void _mdns_handle_system_event(esp_event_base_t event_base,
     else if (event_base == ETH_EVENT) {
         switch (event_id) {
             case ETHERNET_EVENT_CONNECTED:
-                if (!esp_netif_dhcpc_get_status(_mdns_get_esp_netif(MDNS_IF_ETH), &dcst)) {
+                if (!esp_netif_dhcpc_get_status(esp_netif_from_preset_if(MDNS_IF_ETH), &dcst)) {
                     if (dcst == ESP_NETIF_DHCP_STOPPED) {
-                        _mdns_enable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4);
+                        post_mdns_enable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4);
                     }
                 }
                 break;
             case ETHERNET_EVENT_DISCONNECTED:
-                _mdns_disable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4);
-                _mdns_disable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V6);
+                post_mdns_disable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4);
+                post_mdns_disable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V6);
                 break;
             default:
                 break;
@@ -3833,20 +3941,21 @@ static void _mdns_handle_system_event(esp_event_base_t event_base,
     else if (event_base == IP_EVENT) {
         switch (event_id) {
             case IP_EVENT_STA_GOT_IP:
-                _mdns_enable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4);
-                _mdns_announce_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V6, NULL, 0, true);
+                post_mdns_enable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4);
+                post_mdns_announce_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V6);
                 break;
 #if CONFIG_ETH_ENABLED
             case IP_EVENT_ETH_GOT_IP:
-                _mdns_enable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4);
+                post_mdns_enable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4);
                 break;
 #endif
             case IP_EVENT_GOT_IP6:
             {
-                mdns_if_t mdns_if = _mdns_get_if_from_esp_netif(interface);
-                if (mdns_if != MDNS_IF_MAX) {
-                    _mdns_enable_pcb(mdns_if, MDNS_IP_PROTOCOL_V6);
-                    _mdns_announce_pcb(mdns_if, MDNS_IP_PROTOCOL_V4, NULL, 0, true);
+                ip_event_got_ip6_t* event = (ip_event_got_ip6_t*) event_data;
+                mdns_if_t mdns_if = _mdns_get_if_from_esp_netif(event->esp_netif);
+                if (mdns_if < MDNS_MAX_INTERFACES) {
+                    post_mdns_enable_pcb(mdns_if, MDNS_IP_PROTOCOL_V6);
+                    post_mdns_announce_pcb(mdns_if, MDNS_IP_PROTOCOL_V4);
                 }
 
             }
@@ -4033,7 +4142,7 @@ static void _mdns_search_result_add_ip(mdns_search_once_t * search, const char *
       || search->type == MDNS_TYPE_ANY) {
         r = search->result;
         while (r) {
-            if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol) {
+            if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol) {
                 _mdns_result_add_ip(r, ip);
                 _mdns_result_update_ttl(r, ttl);
                 return;
@@ -4057,7 +4166,7 @@ static void _mdns_search_result_add_ip(mdns_search_once_t * search, const char *
             a->next = r->addr;
             r->hostname = strdup(hostname);
             r->addr = a;
-            r->tcpip_if = tcpip_if;
+            r->esp_netif = _mdns_get_esp_netif(tcpip_if);
             r->ip_protocol = ip_protocol;
             r->next = search->result;
             r->ttl = ttl;
@@ -4067,7 +4176,7 @@ static void _mdns_search_result_add_ip(mdns_search_once_t * search, const char *
     } else if (search->type == MDNS_TYPE_PTR || search->type == MDNS_TYPE_SRV) {
         r = search->result;
         while (r) {
-            if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(hostname, r->hostname)) {
+            if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(hostname, r->hostname)) {
                 _mdns_result_add_ip(r, ip);
                 _mdns_result_update_ttl(r, ttl);
                 break;
@@ -4086,7 +4195,7 @@ static mdns_result_t * _mdns_search_result_add_ptr(mdns_search_once_t * search,
 {
     mdns_result_t * r = search->result;
     while (r) {
-        if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->instance_name) && !strcasecmp(instance, r->instance_name)) {
+        if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->instance_name) && !strcasecmp(instance, r->instance_name)) {
             _mdns_result_update_ttl(r, ttl);
             return r;
         }
@@ -4108,7 +4217,7 @@ static mdns_result_t * _mdns_search_result_add_ptr(mdns_search_once_t * search,
             return NULL;
         }
 
-        r->tcpip_if = tcpip_if;
+        r->esp_netif = _mdns_get_esp_netif(tcpip_if);
         r->ip_protocol = ip_protocol;
         r->ttl = ttl;
         r->next = search->result;
@@ -4127,7 +4236,7 @@ static void _mdns_search_result_add_srv(mdns_search_once_t *search, const char *
 {
     mdns_result_t * r = search->result;
     while (r) {
-        if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(hostname, r->hostname)) {
+        if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(hostname, r->hostname)) {
             _mdns_result_update_ttl(r, ttl);
             return;
         }
@@ -4152,7 +4261,7 @@ static void _mdns_search_result_add_srv(mdns_search_once_t *search, const char *
         r->service_type = strdup(search->service);
         r->proto = strdup(search->proto);
         r->port = port;
-        r->tcpip_if = tcpip_if;
+        r->esp_netif = _mdns_get_esp_netif(tcpip_if);
         r->ip_protocol = ip_protocol;
         r->ttl = ttl;
         r->next = search->result;
@@ -4170,7 +4279,7 @@ static void _mdns_search_result_add_txt(mdns_search_once_t *search, mdns_txt_ite
 {
     mdns_result_t * r = search->result;
     while (r) {
-        if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol) {
+        if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol) {
             if (r->txt) {
                 goto free_txt;
             }
@@ -4193,7 +4302,7 @@ static void _mdns_search_result_add_txt(mdns_search_once_t *search, mdns_txt_ite
         r->txt = txt;
         r->txt_value_len = txt_value_len;
         r->txt_count = txt_count;
-        r->tcpip_if = tcpip_if;
+        r->esp_netif = _mdns_get_esp_netif(tcpip_if);
         r->ip_protocol = ip_protocol;
         r->ttl = ttl;
         r->next = search->result;
@@ -4238,7 +4347,7 @@ static mdns_search_once_t * _mdns_search_find_from(mdns_search_once_t * s, mdns_
             }
             r = s->result;
             while (r) {
-                if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(name->host, r->hostname)) {
+                if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(name->host, r->hostname)) {
                     return s;
                 }
                 r = r->next;
@@ -4311,7 +4420,7 @@ static mdns_tx_packet_t * _mdns_create_search_packet(mdns_search_once_t * search
         r = search->result;
         while (r) {
             //full record on the same interface is available
-            if (r->tcpip_if != tcpip_if || r->ip_protocol != ip_protocol || r->instance_name == NULL || r->hostname == NULL || r->addr == NULL) {
+            if (r->esp_netif != _mdns_get_esp_netif(tcpip_if) || r->ip_protocol != ip_protocol || r->instance_name == NULL || r->hostname == NULL || r->addr == NULL) {
                 r = r->next;
                 continue;
             }
@@ -4375,7 +4484,7 @@ static void _mdns_search_send(mdns_search_once_t * search)
     }
 
     uint8_t i, j;
-    for (i=0; i<MDNS_IF_MAX; i++) {
+    for (i=0; i<MDNS_MAX_INTERFACES; i++) {
         for (j=0; j<MDNS_IP_PROTOCOL_MAX; j++) {
             _mdns_search_send_pcb(search, (mdns_if_t)i, (mdns_ip_protocol_t)j);
         }
@@ -4525,8 +4634,7 @@ static void _mdns_execute_action(mdns_action_t * action)
 
     switch(action->type) {
     case ACTION_SYSTEM_EVENT:
-        _mdns_handle_system_event(action->data.sys_event.event_base,
-            action->data.sys_event.event_id, action->data.sys_event.interface);
+        perform_event_action(action->data.sys_event.interface, action->data.sys_event.event_action);
         break;
     case ACTION_HOSTNAME_SET:
         _mdns_send_bye_all_pcbs_no_instance(true);
@@ -4939,35 +5047,113 @@ static esp_err_t _mdns_service_task_stop(void)
     return ESP_OK;
 }
 
-/*
- * Public Methods
- * */
-
-static void event_handler(void* arg, esp_event_base_t event_base,
-                     int32_t event_id, void* event_data)
+static esp_err_t mdns_post_custom_action_tcpip_if(mdns_if_t mdns_if, mdns_event_actions_t event_action)
 {
-    if (!_mdns_server) {
-        return;
+    if (!_mdns_server || mdns_if >= MDNS_MAX_INTERFACES) {
+        return ESP_ERR_INVALID_STATE;
     }
 
     mdns_action_t * action = (mdns_action_t *)calloc(1, sizeof(mdns_action_t));
     if (!action) {
         HOOK_MALLOC_FAILED;
-        return;
+        return ESP_ERR_NO_MEM;
     }
     action->type = ACTION_SYSTEM_EVENT;
-    action->data.sys_event.event_base = event_base;
-    action->data.sys_event.event_id = event_id;
-    if (event_base == IP_EVENT && event_id == IP_EVENT_GOT_IP6) {
-        ip_event_got_ip6_t* event = (ip_event_got_ip6_t*) event_data;
-        action->data.sys_event.interface = event->esp_netif;
-    }
+    action->data.sys_event.event_action = event_action;
+    action->data.sys_event.interface = mdns_if;
 
     if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) {
         free(action);
     }
+    return ESP_OK;
 }
 
+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;
+    }
+}
+
+static inline void unregister_predefined_handlers(void)
+{
+#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP
+    esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, mdns_preset_if_handle_system_event);
+#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, mdns_preset_if_handle_system_event);
+#endif
+#if defined(CONFIG_ETH_ENABLED) && CONFIG_MDNS_PREDEF_NETIF_ETH
+    esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, mdns_preset_if_handle_system_event);
+#endif
+}
+
+/*
+ * Public Methods
+ * */
+
+esp_err_t mdns_netif_action(esp_netif_t *esp_netif, mdns_event_actions_t event_action)
+{
+    return mdns_post_custom_action_tcpip_if(_mdns_get_if_from_esp_netif(esp_netif), event_action);
+}
+
+esp_err_t mdns_register_netif(esp_netif_t *esp_netif)
+{
+    if (!_mdns_server) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    esp_err_t err = ESP_ERR_NO_MEM;
+    MDNS_SERVICE_LOCK();
+    for (mdns_if_t i=0; i<MDNS_MAX_INTERFACES; ++i) {
+        if (s_esp_netifs[i].netif == esp_netif) {
+            MDNS_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_SERVICE_UNLOCK();
+    return err;
+}
+
+esp_err_t mdns_unregister_netif(esp_netif_t *esp_netif)
+{
+    if (!_mdns_server) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    esp_err_t err = ESP_ERR_NOT_FOUND;
+    MDNS_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_SERVICE_UNLOCK();
+    return err;
+}
+
+
 esp_err_t mdns_init(void)
 {
     esp_err_t err = ESP_OK;
@@ -4983,7 +5169,9 @@ esp_err_t mdns_init(void)
     }
     memset((uint8_t*)_mdns_server, 0, sizeof(mdns_server_t));
     // zero-out local copy of netifs to initiate a fresh search by interface key whenever a netif ptr is needed
-    memset(s_esp_netifs, 0, sizeof(s_esp_netifs));
+    for (mdns_if_t i = 0; i < MDNS_MAX_INTERFACES; ++i) {
+        s_esp_netifs[i].netif = NULL;
+    }
 
     _mdns_server->lock = xSemaphoreCreateMutex();
     if (!_mdns_server->lock) {
@@ -4996,24 +5184,34 @@ esp_err_t mdns_init(void)
         err = ESP_ERR_NO_MEM;
         goto free_lock;
     }
-    if ((err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)) != ESP_OK) {
+
+#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP
+    if ((err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, mdns_preset_if_handle_system_event, NULL)) != ESP_OK) {
         goto free_event_handlers;
     }
-    if ((err = esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)) != ESP_OK) {
+#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, mdns_preset_if_handle_system_event, NULL)) != ESP_OK) {
         goto free_event_handlers;
     }
-#if CONFIG_ETH_ENABLED
-    if ((err = esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)) != ESP_OK) {
+#endif
+#if defined(CONFIG_ETH_ENABLED) && CONFIG_MDNS_PREDEF_NETIF_ETH
+    if ((err = esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, mdns_preset_if_handle_system_event, 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;
 #if CONFIG_LWIP_IPV6
     esp_ip6_addr_t tmp_addr6;
 #endif
     esp_netif_ip_info_t if_ip_info;
 
-    for (i=0; i<MDNS_IF_MAX; i++) {
+    for (i=0; i<MDNS_MAX_INTERFACES; i++) {
 #if CONFIG_LWIP_IPV6
         if (!esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(i), &tmp_addr6) && !_ipv6_address_is_zero(tmp_addr6)) {
             _mdns_enable_pcb(i, MDNS_IP_PROTOCOL_V6);
@@ -5033,15 +5231,14 @@ esp_err_t mdns_init(void)
     return ESP_OK;
 
 free_all_and_disable_pcbs:
-    for (i=0; i<MDNS_IF_MAX; i++) {
+    for (i=0; i<MDNS_MAX_INTERFACES; i++) {
         _mdns_disable_pcb(i, MDNS_IP_PROTOCOL_V6);
         _mdns_disable_pcb(i, MDNS_IP_PROTOCOL_V4);
+        s_esp_netifs[i].duplicate = MDNS_MAX_INTERFACES;
     }
+#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH
 free_event_handlers:
-    esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler);
-    esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, &event_handler);
-#if CONFIG_ETH_ENABLED
-    esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, &event_handler);
+    unregister_predefined_handlers();
 #endif
     vQueueDelete(_mdns_server->action_queue);
 free_lock:
@@ -5060,16 +5257,12 @@ void mdns_free(void)
     }
 
     // Unregister handlers before destroying the mdns internals to avoid receiving async events while deinit
-    esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler);
-    esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, &event_handler);
-#if CONFIG_ETH_ENABLED
-    esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, &event_handler);
-#endif
+    unregister_predefined_handlers();
 
     mdns_service_remove_all();
     free_delegated_hostnames();
     _mdns_service_task_stop();
-    for (i=0; i<MDNS_IF_MAX; i++) {
+    for (i=0; i<MDNS_MAX_INTERFACES; i++) {
         for (j=0; j<MDNS_IP_PROTOCOL_MAX; j++) {
             _mdns_pcb_deinit(i, j);
         }

+ 6 - 15
components/mdns/mdns_console.c

@@ -1,23 +1,14 @@
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 #include <stdio.h>
 #include <string.h>
 #include "esp_console.h"
 #include "argtable3/argtable3.h"
 #include "mdns.h"
 
-static const char * if_str[] = {"STA", "AP", "ETH", "MAX"};
 static const char * ip_protocol_str[] = {"V4", "V6", "MAX"};
 
 static void mdns_print_results(mdns_result_t * results)
@@ -26,7 +17,7 @@ static void mdns_print_results(mdns_result_t * results)
     mdns_ip_addr_t * a = NULL;
     int i = 1;
     while (r) {
-        printf("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol]);
+        printf("%d: Interface: %s, Type: %s\n", i++, esp_netif_get_ifkey(r->esp_netif), ip_protocol_str[r->ip_protocol]);
         if (r->instance_name) {
             printf("  PTR : %s\n", r->instance_name);
         }

+ 3 - 3
components/mdns/mdns_networking_lwip.c

@@ -134,7 +134,7 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip
             continue;
         }
 
-        packet->tcpip_if = MDNS_IF_MAX;
+        packet->tcpip_if = MDNS_MAX_INTERFACES;
         packet->pb = this_pb;
         packet->src_port = rport;
 #if CONFIG_LWIP_IPV6
@@ -164,7 +164,7 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip
         //lwip does not return the proper pcb if you have more than one for the same multicast address (but different interfaces)
         struct netif * netif = NULL;
         struct udp_pcb * pcb = NULL;
-        for (i=0; i<MDNS_IF_MAX; i++) {
+        for (i=0; i<MDNS_MAX_INTERFACES; i++) {
             pcb = _mdns_server->interfaces[i].pcbs[packet->ip_protocol].pcb;
             netif = esp_netif_get_netif_impl(_mdns_get_esp_netif(i));
             if (pcb && netif && netif == ip_current_input_netif ()) {
@@ -198,7 +198,7 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip
  */
 static bool _udp_pcb_is_in_use(void){
     int i, p;
-    for (i=0; i<MDNS_IF_MAX; i++) {
+    for (i=0; i<MDNS_MAX_INTERFACES; i++) {
         for (p=0; p<MDNS_IP_PROTOCOL_MAX; p++) {
             if(_mdns_server->interfaces[i].pcbs[p].pcb){
                 return true;

+ 4 - 4
components/mdns/mdns_networking_socket.c

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -101,7 +101,7 @@ esp_err_t _mdns_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
         }
     }
 
-    for (int i=0; i<MDNS_IF_MAX; i++) {
+    for (int i=0; i<MDNS_MAX_INTERFACES; i++) {
         for (int j=0; j<MDNS_IP_PROTOCOL_MAX; j++) {
             if (_mdns_server->interfaces[i].pcbs[j].pcb)
                 // If any of the interfaces/protocol initialized
@@ -247,7 +247,7 @@ void sock_recv_task(void* arg)
         fd_set rfds;
         FD_ZERO(&rfds);
         int max_sock = -1;
-        for (int i=0; i<MDNS_IF_MAX; i++) {
+        for (int i=0; i<MDNS_MAX_INTERFACES; i++) {
             for (int j=0; j<MDNS_IP_PROTOCOL_MAX; j++) {
                 int sock = pcb_to_sock(_mdns_server->interfaces[i].pcbs[j].pcb);
                 if (sock >= 0) {
@@ -267,7 +267,7 @@ void sock_recv_task(void* arg)
             ESP_LOGE(TAG, "Select failed. errno=%d: %s", errno, strerror(errno));
             break;
         } else if (s > 0) {
-            for (int tcpip_if=0; tcpip_if<MDNS_IF_MAX; tcpip_if++) {
+            for (int tcpip_if=0; tcpip_if<MDNS_MAX_INTERFACES; tcpip_if++) {
                 // Both protocols share once socket
                 int sock = pcb_to_sock(_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb);
                 if (sock < 0) {

+ 26 - 4
components/mdns/private_include/mdns_private.h

@@ -41,6 +41,27 @@
  * any item in question field */
 #define  MDNS_REPEAT_QUERY_IN_RESPONSE 1
 #endif
+
+/** Number of predefined interfaces */
+#ifndef CONFIG_MDNS_PREDEF_NETIF_STA
+#define CONFIG_MDNS_PREDEF_NETIF_STA 0
+#endif
+#ifndef CONFIG_MDNS_PREDEF_NETIF_AP
+#define CONFIG_MDNS_PREDEF_NETIF_AP 0
+#endif
+#ifndef CONFIG_MDNS_PREDEF_NETIF_ETH
+#define CONFIG_MDNS_PREDEF_NETIF_ETH 0
+#endif
+#define MDNS_MAX_PREDEF_INTERFACES (CONFIG_MDNS_PREDEF_NETIF_STA + CONFIG_MDNS_PREDEF_NETIF_AP + CONFIG_MDNS_PREDEF_NETIF_ETH)
+
+/** Number of configured interfaces */
+#if MDNS_MAX_PREDEF_INTERFACES > CONFIG_MDNS_MAX_INTERFACES
+#warning Number of configured interfaces is less then number of predefined interfaces. Please update CONFIG_MDNS_MAX_INTERFACES.
+#define MDNS_MAX_INTERFACES (MDNS_MAX_PREDEF_INTERFACES)
+#else
+#define MDNS_MAX_INTERFACES (CONFIG_MDNS_MAX_INTERFACES)
+#endif
+
 /** The maximum number of services */
 #define MDNS_MAX_SERVICES           CONFIG_MDNS_MAX_SERVICES
 
@@ -150,6 +171,8 @@
 #define HOOK_MALLOC_FAILED  ESP_LOGE(TAG, "Cannot allocate memory (line: %d, free heap: %d bytes)", __LINE__, esp_get_free_heap_size());
 #endif
 
+typedef size_t mdns_if_t;
+
 typedef enum {
     PCB_OFF, PCB_DUP, PCB_INIT,
     PCB_PROBE_1, PCB_PROBE_2, PCB_PROBE_3,
@@ -384,7 +407,7 @@ typedef struct mdns_search_once_s {
 typedef struct mdns_server_s {
     struct {
         mdns_pcb_t pcbs[MDNS_IP_PROTOCOL_MAX];
-    } interfaces[MDNS_IF_MAX];
+    } interfaces[MDNS_MAX_INTERFACES];
     const char * hostname;
     const char * instance;
     mdns_srv_item_t * services;
@@ -404,9 +427,8 @@ typedef struct {
         } hostname_set;
         char * instance;
         struct {
-            esp_event_base_t event_base;
-            int32_t event_id;
-            esp_netif_t* interface;
+            mdns_if_t interface;
+            mdns_event_actions_t event_action;
         } sys_event;
         struct {
             mdns_srv_item_t * service;

+ 1 - 0
components/mdns/test_afl_fuzz_host/sdkconfig.h

@@ -284,6 +284,7 @@
 #define CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED 1
 #define CONFIG_MBEDTLS_ECP_NIST_OPTIM 1
 #define CONFIG_MDNS_MAX_SERVICES 25
+#define CONFIG_MDNS_MAX_INTERFACES 3
 #define CONFIG_MDNS_TASK_PRIORITY 1
 #define CONFIG_MDNS_TASK_STACK_SIZE 4096
 #define CONFIG_MDNS_TASK_AFFINITY_CPU0 1

+ 4 - 2
components/mdns/test_afl_fuzz_host/test.c

@@ -34,8 +34,10 @@ extern mdns_server_t * _mdns_server;
 // mdns function wrappers for mdns setup in test mode
 static int mdns_test_hostname_set(const char * mdns_hostname)
 {
-    _mdns_server->interfaces[MDNS_IF_STA].pcbs[MDNS_IP_PROTOCOL_V4].state = PCB_RUNNING;    // mark the PCB running to exercise mdns in fully operational mode
-    _mdns_server->interfaces[MDNS_IF_STA].pcbs[MDNS_IP_PROTOCOL_V6].state = PCB_RUNNING;
+    for (int i=0; i<MDNS_MAX_INTERFACES; i++) {
+        _mdns_server->interfaces[i].pcbs[MDNS_IP_PROTOCOL_V4].state = PCB_RUNNING;    // mark the PCB running to exercise mdns in fully operational mode
+        _mdns_server->interfaces[i].pcbs[MDNS_IP_PROTOCOL_V6].state = PCB_RUNNING;
+    }
     int ret = mdns_hostname_set(mdns_hostname);
     mdns_action_t * a = NULL;
     GetLastItem(&a);

+ 9 - 0
examples/protocols/mdns/main/Kconfig.projbuild

@@ -48,4 +48,13 @@ menu "Example Configuration"
         help
             Set the GPIO number used as mDNS test button
 
+    config MDNS_ADD_CUSTOM_NETIF
+        bool "Add user netif to mdns service"
+        default n
+        help
+            If enabled, we try to add a custom netif to mdns service.
+            Note that for using with common connection example code, we have to disable
+            all predefined interfaces in mdns component setup (since we're adding one
+            of the default interfaces)
+
 endmenu

+ 13 - 4
examples/protocols/mdns/main/mdns_example_main.c

@@ -83,9 +83,6 @@ static void initialise_mdns(void)
     free(hostname);
 }
 
-/* these strings match tcpip_adapter_if_t enumeration */
-static const char * if_str[] = {"STA", "AP", "ETH", "MAX"};
-
 /* these strings match mdns_ip_protocol_t enumeration */
 static const char * ip_protocol_str[] = {"V4", "V6", "MAX"};
 
@@ -95,7 +92,7 @@ static void mdns_print_results(mdns_result_t *results)
     mdns_ip_addr_t *a = NULL;
     int i = 1, t;
     while (r) {
-        printf("%d: Interface: %s, Type: %s, TTL: %u\n", i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol],
+        printf("%d: Interface: %s, Type: %s, TTL: %u\n", i++, esp_netif_get_ifkey(r->esp_netif), ip_protocol_str[r->ip_protocol],
                r->ttl);
         if (r->instance_name) {
             printf("  PTR : %s.%s.%s\n", r->instance_name, r->service_type, r->proto);
@@ -269,6 +266,18 @@ void app_main(void)
      */
     ESP_ERROR_CHECK(example_connect());
 
+#if defined(CONFIG_MDNS_ADD_CUSTOM_NETIF) && !defined(CONFIG_MDNS_PREDEF_NETIF_STA) && !defined(CONFIG_MDNS_PREDEF_NETIF_ETH)
+    /* Demonstration of adding a custom netif to mdns service, but we're adding the default example one,
+     * so we must disable all predefined interfaces (PREDEF_NETIF_STA, AP and ETH) first
+     */
+    ESP_ERROR_CHECK(mdns_register_netif(EXAMPLE_INTERFACE));
+    /* It is not enough to just register the interface, we have to enable is manually.
+     * This is typically performed in "GOT_IP" event handler, but we call it here directly
+     * since the `EXAMPLE_INTERFACE` netif is connected already, to keep the example simple.
+     */
+    ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_ENABLE_IP4));
+    ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_ANNOUNCE_IP4));
+#endif
     initialise_button();
     xTaskCreate(&mdns_example_task, "mdns_example_task", 2048, NULL, 5, NULL);
 }

+ 35 - 25
examples/protocols/mdns/mdns_example_test.py

@@ -13,10 +13,6 @@ import ttfw_idf
 from tiny_test_fw import DUT
 from tiny_test_fw.Utility import console_log
 
-stop_mdns_server = Event()
-esp_answered = Event()
-esp_delegated_answered = Event()
-
 
 def get_dns_query_for_esp(esp_host):
     dns = dpkt.dns.DNS(b'\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01')
@@ -34,7 +30,7 @@ def get_dns_answer_to_mdns(tester_host):
     arr.type = dpkt.dns.DNS_A
     arr.name = tester_host
     arr.ip = socket.inet_aton('127.0.0.1')
-    dns. an.append(arr)
+    dns.an.append(arr)
     console_log('Created answer to mdns query: {} '.format(dns.__repr__()))
     return dns.pack()
 
@@ -52,8 +48,7 @@ def get_dns_answer_to_mdns_lwip(tester_host, id):
     return dns.pack()
 
 
-def mdns_server(esp_host):
-    global esp_answered
+def mdns_server(esp_host, events):
     UDP_IP = '0.0.0.0'
     UDP_PORT = 5353
     MCAST_GRP = '224.0.0.251'
@@ -64,19 +59,19 @@ def mdns_server(esp_host):
     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
     sock.setblocking(False)
-    sock.bind((UDP_IP,UDP_PORT))
+    sock.bind((UDP_IP, UDP_PORT))
     mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
     sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
     last_query_timepoint = time.time()
-    while not stop_mdns_server.is_set():
+    while not events['stop'].is_set():
         try:
             current_time = time.time()
             if current_time - last_query_timepoint > QUERY_TIMEOUT:
                 last_query_timepoint = current_time
-                if not esp_answered.is_set():
-                    sock.sendto(get_dns_query_for_esp(esp_host), (MCAST_GRP,UDP_PORT))
-                if not esp_delegated_answered.is_set():
-                    sock.sendto(get_dns_query_for_esp(esp_host + '-delegated'), (MCAST_GRP,UDP_PORT))
+                if not events['esp_answered'].is_set():
+                    sock.sendto(get_dns_query_for_esp(esp_host), (MCAST_GRP, UDP_PORT))
+                if not events['esp_delegated_answered'].is_set():
+                    sock.sendto(get_dns_query_for_esp(esp_host + '-delegated'), (MCAST_GRP, UDP_PORT))
             timeout = max(0, QUERY_TIMEOUT - (current_time - last_query_timepoint))
             read_socks, _, _ = select.select([sock], [], [], timeout)
             if not read_socks:
@@ -86,7 +81,7 @@ def mdns_server(esp_host):
             if len(dns.qd) > 0 and dns.qd[0].type == dpkt.dns.DNS_A:
                 if dns.qd[0].name == TESTER_NAME:
                     console_log('Received query: {} '.format(dns.__repr__()))
-                    sock.sendto(get_dns_answer_to_mdns(TESTER_NAME), (MCAST_GRP,UDP_PORT))
+                    sock.sendto(get_dns_answer_to_mdns(TESTER_NAME), (MCAST_GRP, UDP_PORT))
                 elif dns.qd[0].name == TESTER_NAME_LWIP:
                     console_log('Received query: {} '.format(dns.__repr__()))
                     sock.sendto(get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id), addr)
@@ -94,19 +89,17 @@ def mdns_server(esp_host):
                 console_log('Received answer from {}'.format(dns.an[0].name))
                 if dns.an[0].name == esp_host + u'.local':
                     console_log('Received answer to esp32-mdns query: {}'.format(dns.__repr__()))
-                    esp_answered.set()
+                    events['esp_answered'].set()
                 if dns.an[0].name == esp_host + u'-delegated.local':
                     console_log('Received answer to esp32-mdns-delegate query: {}'.format(dns.__repr__()))
-                    esp_delegated_answered.set()
+                    events['esp_delegated_answered'].set()
         except socket.timeout:
             break
         except dpkt.UnpackError:
             continue
 
 
-@ttfw_idf.idf_example_test(env_tag='Example_EthKitV1')
-def test_examples_protocol_mdns(env, extra_data):
-    global stop_mdns_server
+def test_examples_protocol_mdns(env, config):
     """
     steps: |
       1. obtain IP address + init mdns example
@@ -114,7 +107,7 @@ def test_examples_protocol_mdns(env, extra_data):
       3. check the mdns name is accessible
       4. check DUT output if mdns advertized host is resolved
     """
-    dut1 = env.get_dut('mdns-test', 'examples/protocols/mdns', dut_class=ttfw_idf.ESP32DUT, app_config_name='eth_kit')
+    dut1 = env.get_dut('mdns-test', 'examples/protocols/mdns', dut_class=ttfw_idf.ESP32DUT, app_config_name=config)
     # check and log bin size
     binary_file = os.path.join(dut1.app.binary_path, 'mdns_test.bin')
     bin_size = os.path.getsize(binary_file)
@@ -123,7 +116,9 @@ def test_examples_protocol_mdns(env, extra_data):
     dut1.start_app()
     # 2. get the dut host name (and IP address)
     specific_host = dut1.expect(re.compile(r'mdns hostname set to: \[([^\]]+)\]'), timeout=30)[0]
-    mdns_responder = Thread(target=mdns_server, args=(str(specific_host),))
+
+    mdns_server_events = {'stop': Event(), 'esp_answered': Event(), 'esp_delegated_answered': Event()}
+    mdns_responder = Thread(target=mdns_server, args=(str(specific_host), mdns_server_events))
     try:
         ip_address = dut1.expect(re.compile(r' eth ip: ([^,]+),'), timeout=30)[0]
         console_log('Connected to AP with IP: {}'.format(ip_address))
@@ -132,9 +127,9 @@ def test_examples_protocol_mdns(env, extra_data):
     try:
         # 3. check the mdns name is accessible
         mdns_responder.start()
-        if not esp_answered.wait(timeout=30):
+        if not mdns_server_events['esp_answered'].wait(timeout=30):
             raise ValueError('Test has failed: did not receive mdns answer within timeout')
-        if not esp_delegated_answered.wait(timeout=30):
+        if not mdns_server_events['esp_delegated_answered'].wait(timeout=30):
             raise ValueError('Test has failed: did not receive mdns answer for delegated host within timeout')
         # 4. check DUT output if mdns advertized host is resolved
         dut1.expect(re.compile(r'mdns-test: Query A: tinytester.local resolved to: 127.0.0.1'), timeout=30)
@@ -148,9 +143,24 @@ def test_examples_protocol_mdns(env, extra_data):
             raise ValueError('Test has failed: Incorrectly resolved DUT hostname using dig'
                              "Output should've contained DUT's IP address:{}".format(ip_address))
     finally:
-        stop_mdns_server.set()
+        mdns_server_events['stop'].set()
         mdns_responder.join()
 
 
+@ttfw_idf.idf_example_test(env_tag='Example_EthKitV1')
+def test_examples_protocol_mdns_default(env, _):
+    test_examples_protocol_mdns(env, 'eth_def')
+
+
+@ttfw_idf.idf_example_test(env_tag='Example_EthKitV1')
+def test_examples_protocol_mdns_socket(env, _):
+    test_examples_protocol_mdns(env, 'eth_socket')
+
+
+@ttfw_idf.idf_example_test(env_tag='Example_EthKitV1')
+def test_examples_protocol_mdns_custom_netif(env, _):
+    test_examples_protocol_mdns(env, 'eth_custom_netif')
+
+
 if __name__ == '__main__':
-    test_examples_protocol_mdns()
+    test_examples_protocol_mdns_default()

+ 19 - 0
examples/protocols/mdns/sdkconfig.ci.eth_custom_netif

@@ -0,0 +1,19 @@
+CONFIG_IDF_TARGET="esp32"
+CONFIG_MDNS_RESOLVE_TEST_SERVICES=y
+CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y
+CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y
+CONFIG_MDNS_PREDEF_NETIF_STA=n
+CONFIG_MDNS_PREDEF_NETIF_AP=n
+CONFIG_MDNS_PREDEF_NETIF_ETH=n
+CONFIG_MDNS_ADD_CUSTOM_NETIF=y
+CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
+CONFIG_EXAMPLE_CONNECT_ETHERNET=y
+CONFIG_EXAMPLE_CONNECT_WIFI=n
+CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
+CONFIG_EXAMPLE_ETH_PHY_IP101=y
+CONFIG_EXAMPLE_ETH_MDC_GPIO=23
+CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
+CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
+CONFIG_EXAMPLE_ETH_PHY_ADDR=1
+CONFIG_EXAMPLE_CONNECT_IPV6=y
+CONFIG_MDNS_BUTTON_GPIO=32

+ 0 - 0
examples/protocols/mdns/sdkconfig.ci.eth_kit → examples/protocols/mdns/sdkconfig.ci.eth_def


+ 16 - 0
examples/protocols/mdns/sdkconfig.ci.eth_socket

@@ -0,0 +1,16 @@
+CONFIG_IDF_TARGET="esp32"
+CONFIG_MDNS_RESOLVE_TEST_SERVICES=y
+CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y
+CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y
+CONFIG_MDNS_NETWORKING_SOCKET=y
+CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
+CONFIG_EXAMPLE_CONNECT_ETHERNET=y
+CONFIG_EXAMPLE_CONNECT_WIFI=n
+CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
+CONFIG_EXAMPLE_ETH_PHY_IP101=y
+CONFIG_EXAMPLE_ETH_MDC_GPIO=23
+CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
+CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
+CONFIG_EXAMPLE_ETH_PHY_ADDR=1
+CONFIG_EXAMPLE_CONNECT_IPV6=y
+CONFIG_MDNS_BUTTON_GPIO=32

+ 0 - 1
tools/ci/check_copyright_ignore.txt

@@ -1133,7 +1133,6 @@ components/mdns/host_test/components/freertos_linux/queue_unique_ptr.cpp
 components/mdns/host_test/components/freertos_linux/queue_unique_ptr.hpp
 components/mdns/host_test/main/main.c
 components/mdns/include/mdns_console.h
-components/mdns/mdns_console.c
 components/mdns/mdns_networking_lwip.c
 components/mdns/private_include/mdns_networking.h
 components/mdns/test/test_mdns.c