1 // Copyright 2021 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 /**
16  * @brief MDNS Server Networking module implemented using BSD sockets
17  */
18 
19 #include <string.h>
20 #include "esp_event.h"
21 #include "mdns_networking.h"
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <arpa/inet.h>
25 #include <netdb.h>
26 #include <errno.h>
27 #include <stdbool.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <sys/param.h>
31 #include "esp_log.h"
32 
33 #if defined(CONFIG_IDF_TARGET_LINUX)
34 #include <sys/ioctl.h>
35 #include <net/if.h>
36 #endif
37 
38 extern mdns_server_t * _mdns_server;
39 
40 static const char *TAG = "MDNS_Networking";
41 static bool s_run_sock_recv_task = false;
42 static int create_socket(esp_netif_t *netif);
43 static int join_mdns_multicast_group(int sock, esp_netif_t *netif, mdns_ip_protocol_t ip_protocol);
44 
45 #if defined(CONFIG_IDF_TARGET_LINUX)
46 // Need to define packet buffer struct on linux
47 struct pbuf  {
48     struct pbuf * next;
49     void * payload;
50     size_t tot_len;
51     size_t len;
52 };
53 #else
54 // Compatibility define to access sock-addr struct the same way for lwip and linux
55 #define s6_addr32 un.u32_addr
56 #endif // CONFIG_IDF_TARGET_LINUX
57 
delete_socket(int sock)58 static void delete_socket(int sock)
59 {
60     close(sock);
61 }
62 
sock_to_pcb(int sock)63 static struct udp_pcb* sock_to_pcb(int sock)
64 {
65     if (sock < 0) {
66         return NULL;
67     }
68     // Note: sock=0 is a valid descriptor, so save it as +1 ("1" is a valid pointer)
69     intptr_t sock_plus_one = sock + 1;
70     return (struct udp_pcb*)sock_plus_one;
71 }
72 
pcb_to_sock(struct udp_pcb * pcb)73 static int pcb_to_sock(struct udp_pcb* pcb)
74 {
75     if (pcb == NULL) {
76         return -1;
77     }
78     intptr_t sock_plus_one = (intptr_t)pcb;
79     return sock_plus_one - 1;
80 }
81 
_mdns_get_packet_data(mdns_rx_packet_t * packet)82 void* _mdns_get_packet_data(mdns_rx_packet_t *packet)
83 {
84     return packet->pb->payload;
85 }
86 
_mdns_get_packet_len(mdns_rx_packet_t * packet)87 size_t _mdns_get_packet_len(mdns_rx_packet_t *packet)
88 {
89     return packet->pb->len;
90 }
91 
_mdns_packet_free(mdns_rx_packet_t * packet)92 void _mdns_packet_free(mdns_rx_packet_t *packet)
93 {
94     free(packet->pb->payload);
95     free(packet->pb);
96     free(packet);
97 }
98 
_mdns_pcb_deinit(mdns_if_t tcpip_if,mdns_ip_protocol_t ip_protocol)99 esp_err_t _mdns_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
100 {
101     struct udp_pcb * pcb = _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb;
102     _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb = NULL;
103     if (_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb == NULL &&
104         _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb == NULL) {
105         // if the interface for both protocol uninitialized, close the interface socket
106         int sock = pcb_to_sock(pcb);
107         if (sock >= 0) {
108             delete_socket(sock);
109         }
110     }
111 
112     for (int i=0; i<MDNS_IF_MAX; i++) {
113         for (int j=0; j<MDNS_IP_PROTOCOL_MAX; j++) {
114             if (_mdns_server->interfaces[i].pcbs[j].pcb)
115                 // If any of the interfaces/protocol initialized
116                 return ESP_OK;
117         }
118     }
119 
120     // no interface alive, stop the rx task
121     s_run_sock_recv_task = false;
122     vTaskDelay(pdMS_TO_TICKS(500));
123     return ESP_OK;
124 }
125 
126 #if defined(CONFIG_IDF_TARGET_LINUX)
127 #ifdef CONFIG_LWIP_IPV6
inet6_ntoa_r(struct in6_addr addr,char * ptr,size_t size)128 static char* inet6_ntoa_r(struct in6_addr addr, char* ptr, size_t size)
129 {
130     inet_ntop(AF_INET6, &(addr.s6_addr32[0]), ptr, size);
131     return ptr;
132 }
133 #endif // CONFIG_LWIP_IPV6
inet_ntoa_r(struct in_addr addr,char * ptr,size_t size)134 static char* inet_ntoa_r(struct in_addr addr, char* ptr, size_t size)
135 {
136     char * res = inet_ntoa(addr);
137     if (res && strlen(res) < size) {
138         strcpy(ptr, res);
139     }
140     return res;
141 }
142 #endif // CONFIG_IDF_TARGET_LINUX
143 
get_string_address(struct sockaddr_storage * source_addr)144 static inline char* get_string_address(struct sockaddr_storage *source_addr)
145 {
146     static char address_str[40]; // 40=(8*4+7+term) is the max size of ascii IPv6 addr "XXXX:XX...XX:XXXX"
147     char *res = NULL;
148     // Convert ip address to string
149     if (source_addr->ss_family == PF_INET) {
150         res = inet_ntoa_r(((struct sockaddr_in *)source_addr)->sin_addr, address_str, sizeof(address_str));
151     }
152 #ifdef CONFIG_LWIP_IPV6
153     else if (source_addr->ss_family == PF_INET6) {
154         res = inet6_ntoa_r(((struct sockaddr_in6 *)source_addr)->sin6_addr, address_str, sizeof(address_str));
155     }
156 #endif
157     if (!res) {
158         address_str[0] = '\0'; // Returns empty string if conversion didn't succeed
159     }
160     return address_str;
161 }
162 
163 
espaddr_to_inet(const esp_ip_addr_t * addr,const uint16_t port,const mdns_ip_protocol_t ip_protocol,struct sockaddr_storage * in_addr)164 static inline size_t espaddr_to_inet(const esp_ip_addr_t *addr, const uint16_t port, const mdns_ip_protocol_t ip_protocol, struct sockaddr_storage *in_addr)
165 {
166     size_t ss_addr_len = 0;
167     memset(in_addr, 0, sizeof(struct sockaddr_storage));
168     if (ip_protocol == MDNS_IP_PROTOCOL_V4 && addr->type == ESP_IPADDR_TYPE_V4) {
169         in_addr->ss_family = PF_INET;
170 #if !defined(CONFIG_IDF_TARGET_LINUX)
171         in_addr->s2_len = sizeof(struct sockaddr_in);
172 #endif
173         ss_addr_len = sizeof(struct sockaddr_in);
174         struct sockaddr_in *in_addr_ip4 = (struct sockaddr_in *) in_addr;
175         in_addr_ip4->sin_port = port;
176         in_addr_ip4->sin_addr.s_addr = addr->u_addr.ip4.addr;
177     }
178 #if CONFIG_LWIP_IPV6
179     else if (ip_protocol == MDNS_IP_PROTOCOL_V6 && addr->type == ESP_IPADDR_TYPE_V6) {
180         memset(in_addr, 0, sizeof(struct sockaddr_storage));
181         in_addr->ss_family = PF_INET6;
182 #if !defined(CONFIG_IDF_TARGET_LINUX)
183         in_addr->s2_len = sizeof(struct sockaddr_in6);
184 #endif
185         ss_addr_len = sizeof(struct sockaddr_in6);
186         struct sockaddr_in6 * in_addr_ip6 = (struct sockaddr_in6 *)in_addr;
187         uint32_t *u32_addr = in_addr_ip6->sin6_addr.s6_addr32;
188         in_addr_ip6->sin6_port = port;
189         u32_addr[0] = addr->u_addr.ip6.addr[0];
190         u32_addr[1] = addr->u_addr.ip6.addr[1];
191         u32_addr[2] = addr->u_addr.ip6.addr[2];
192         u32_addr[3] = addr->u_addr.ip6.addr[3];
193     }
194 #endif // CONFIG_LWIP_IPV6
195     return ss_addr_len;
196 }
197 
_mdns_udp_pcb_write(mdns_if_t tcpip_if,mdns_ip_protocol_t ip_protocol,const esp_ip_addr_t * ip,uint16_t port,uint8_t * data,size_t len)198 size_t _mdns_udp_pcb_write(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const esp_ip_addr_t *ip, uint16_t port, uint8_t * data, size_t len)
199 {
200     int sock = pcb_to_sock(_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb);
201     if (sock < 0) {
202         return 0;
203     }
204     struct sockaddr_storage in_addr;
205     size_t ss_size = espaddr_to_inet(ip, htons(port), ip_protocol, &in_addr);
206     if (!ss_size) {
207         ESP_LOGE(TAG, "espaddr_to_inet() failed: Mismatch of IP protocols");
208         return 0;
209     }
210     ESP_LOGD(TAG, "[sock=%d]: Sending to IP %s port %d", sock, get_string_address(&in_addr), port);
211     ssize_t actual_len = sendto(sock, data, len, 0, (struct sockaddr *)&in_addr, ss_size);
212     if (actual_len < 0) {
213         ESP_LOGE(TAG, "[sock=%d]: _mdns_udp_pcb_write sendto() has failed\n error=%d: %s", sock, errno, strerror(errno));
214     }
215     return actual_len;
216 }
217 
inet_to_espaddr(const struct sockaddr_storage * in_addr,esp_ip_addr_t * addr,uint16_t * port)218 static inline void inet_to_espaddr(const struct sockaddr_storage *in_addr, esp_ip_addr_t *addr, uint16_t *port)
219 {
220     if (in_addr->ss_family == PF_INET) {
221         struct sockaddr_in * in_addr_ip4 = (struct sockaddr_in *)in_addr;
222         memset(addr, 0, sizeof(esp_ip_addr_t));
223         *port = in_addr_ip4->sin_port;
224         addr->u_addr.ip4.addr = in_addr_ip4->sin_addr.s_addr;
225         addr->type = ESP_IPADDR_TYPE_V4;
226     }
227 #if CONFIG_LWIP_IPV6
228     else if (in_addr->ss_family == PF_INET6) {
229         struct sockaddr_in6 * in_addr_ip6 = (struct sockaddr_in6 *)in_addr;
230         memset(addr, 0, sizeof(esp_ip_addr_t));
231         *port = in_addr_ip6->sin6_port;
232         uint32_t *u32_addr = in_addr_ip6->sin6_addr.s6_addr32;
233         if (u32_addr[0] == 0 && u32_addr[1] == 0 && u32_addr[2] == esp_netif_htonl(0x0000FFFFUL)) {
234             // Mapped IPv4 address, convert directly to IPv4
235             addr->type = ESP_IPADDR_TYPE_V4;
236             addr->u_addr.ip4.addr = u32_addr[3];
237         } else {
238             addr->type = ESP_IPADDR_TYPE_V6;
239             addr->u_addr.ip6.addr[0] = u32_addr[0];
240             addr->u_addr.ip6.addr[1] = u32_addr[1];
241             addr->u_addr.ip6.addr[2] = u32_addr[2];
242             addr->u_addr.ip6.addr[3] = u32_addr[3];
243         }
244     }
245 #endif // CONFIG_LWIP_IPV6
246 }
247 
sock_recv_task(void * arg)248 void sock_recv_task(void* arg)
249 {
250     while (s_run_sock_recv_task) {
251         struct timeval tv = {
252             .tv_sec = 1,
253             .tv_usec = 0,
254         };
255         fd_set rfds;
256         FD_ZERO(&rfds);
257         int max_sock = -1;
258         for (int i=0; i<MDNS_IF_MAX; i++) {
259             for (int j=0; j<MDNS_IP_PROTOCOL_MAX; j++) {
260                 int sock = pcb_to_sock(_mdns_server->interfaces[i].pcbs[j].pcb);
261                 if (sock >= 0) {
262                     FD_SET(sock, &rfds);
263                     max_sock = MAX(max_sock, sock);
264                 }
265             }
266         }
267         if (max_sock < 0) {
268             vTaskDelay(pdMS_TO_TICKS(1000));
269             ESP_LOGI(TAG, "No sock!");
270             continue;
271         }
272 
273         int s = select(max_sock + 1, &rfds, NULL, NULL, &tv);
274         if (s < 0) {
275             ESP_LOGE(TAG, "Select failed: errno %d", errno);
276             break;
277         } else if (s > 0) {
278             for (int tcpip_if=0; tcpip_if<MDNS_IF_MAX; tcpip_if++) {
279                 // Both protocols share once socket
280                 int sock = pcb_to_sock(_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb);
281                 if (sock < 0) {
282                     sock = pcb_to_sock(_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb);
283                 }
284                 if (sock < 0) {
285                     continue;
286                 }
287                 if (FD_ISSET(sock, &rfds)) {
288                     static char recvbuf[MDNS_MAX_PACKET_SIZE];
289                     uint16_t port = 0;
290 
291                     struct sockaddr_storage raddr; // Large enough for both IPv4 or IPv6
292                     socklen_t socklen = sizeof(struct sockaddr_storage);
293                     esp_ip_addr_t addr = {0};
294                     int len = recvfrom(sock, recvbuf, sizeof(recvbuf), 0,
295                                        (struct sockaddr *) &raddr, &socklen);
296                     if (len < 0) {
297                         ESP_LOGE(TAG, "multicast recvfrom failed: errno %d", errno);
298                         break;
299                     }
300                     ESP_LOGD(TAG, "[sock=%d]: Received from IP:%s", sock, get_string_address(&raddr));
301                     ESP_LOG_BUFFER_HEXDUMP(TAG, recvbuf, len, ESP_LOG_VERBOSE);
302                     inet_to_espaddr(&raddr, &addr, &port);
303 
304                     // Allocate the packet structure and pass it to the mdns main engine
305                     mdns_rx_packet_t *packet = (mdns_rx_packet_t *) calloc(1, sizeof(mdns_rx_packet_t));
306                     struct pbuf *packet_pbuf = calloc(1, sizeof(struct pbuf));
307                     uint8_t *buf = malloc(len);
308                     if (packet == NULL || packet_pbuf == NULL || buf == NULL ) {
309                         free(buf);
310                         free(packet_pbuf);
311                         free(packet);
312                         HOOK_MALLOC_FAILED;
313                         ESP_LOGE(TAG, "Failed to allocate the mdns packet");
314                         continue;
315                     }
316                     memcpy(buf, recvbuf, len);
317                     packet_pbuf->next = NULL;
318                     packet_pbuf->payload = buf;
319                     packet_pbuf->tot_len = len;
320                     packet_pbuf->len = len;
321                     packet->tcpip_if = tcpip_if;
322                     packet->pb = packet_pbuf;
323                     packet->src_port = ntohs(port);
324                     memcpy(&packet->src, &addr, sizeof(esp_ip_addr_t));
325                     // TODO(IDF-3651): Add the correct dest addr -- for mdns to decide multicast/unicast
326                     // Currently it's enough to assume the packet is multicast and mdns to check the source port of the packet
327                     memset(&packet->dest, 0, sizeof(esp_ip_addr_t));
328                     packet->multicast = 1;
329                     packet->dest.type = packet->src.type;
330                     packet->ip_protocol =
331                             packet->src.type == ESP_IPADDR_TYPE_V4 ? MDNS_IP_PROTOCOL_V4 : MDNS_IP_PROTOCOL_V6;
332                     if (!_mdns_server || !_mdns_server->action_queue || _mdns_send_rx_action(packet) != ESP_OK) {
333                         ESP_LOGE(TAG, "_mdns_send_rx_action failed!");
334                         free(packet->pb->payload);
335                         free(packet->pb);
336                         free(packet);
337                     }
338                 }
339             }
340         }
341     }
342     vTaskDelete(NULL);
343 }
344 
mdns_networking_init(void)345 static void mdns_networking_init(void)
346 {
347     if (s_run_sock_recv_task == false) {
348         s_run_sock_recv_task = true;
349         xTaskCreate( sock_recv_task, "mdns recv task", 3*1024, NULL, 5, NULL );
350     }
351 }
352 
create_pcb(mdns_if_t tcpip_if,mdns_ip_protocol_t ip_protocol)353 static struct udp_pcb* create_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
354 {
355     if (_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb) {
356         return _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb;
357     }
358     mdns_ip_protocol_t other_ip_proto = ip_protocol==MDNS_IP_PROTOCOL_V4?MDNS_IP_PROTOCOL_V6:MDNS_IP_PROTOCOL_V4;
359     esp_netif_t *netif = _mdns_get_esp_netif(tcpip_if);
360     if (_mdns_server->interfaces[tcpip_if].pcbs[other_ip_proto].pcb) {
361         struct udp_pcb* other_pcb = _mdns_server->interfaces[tcpip_if].pcbs[other_ip_proto].pcb;
362         int err = join_mdns_multicast_group(pcb_to_sock(other_pcb), netif, ip_protocol);
363         if (err < 0) {
364             ESP_LOGE(TAG, "Failed to add ipv6 multicast group for protocol %d", ip_protocol);
365             return NULL;
366         }
367         return other_pcb;
368     }
369     int sock = create_socket(netif);
370     if (sock < 0) {
371         ESP_LOGE(TAG, "Failed to create the socket!");
372         return NULL;
373     }
374     int err = join_mdns_multicast_group(sock, netif, ip_protocol);
375     if (err < 0) {
376         ESP_LOGE(TAG, "Failed to add ipv6 multicast group for protocol %d", ip_protocol);
377     }
378     return sock_to_pcb(sock);
379 }
380 
_mdns_pcb_init(mdns_if_t tcpip_if,mdns_ip_protocol_t ip_protocol)381 esp_err_t _mdns_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
382 {
383     ESP_LOGI(TAG, "_mdns_pcb_init(tcpip_if=%d, ip_protocol=%d)", tcpip_if, ip_protocol);
384     _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb = create_pcb(tcpip_if, ip_protocol);
385     _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].failed_probes = 0;
386 
387     mdns_networking_init();
388     return ESP_OK;
389 }
390 
create_socket(esp_netif_t * netif)391 static int create_socket(esp_netif_t *netif)
392 {
393 #if CONFIG_LWIP_IPV6
394     int sock = socket(PF_INET6, SOCK_DGRAM, 0);
395 #else
396     int sock = socket(PF_INET, SOCK_DGRAM, 0);
397 #endif
398     if (sock < 0) {
399         ESP_LOGE(TAG, "Failed to create socket. Error %d", errno);
400         return -1;
401     }
402 
403     int on = 1;
404     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
405         ESP_LOGE(TAG, "setsockopt SO_REUSEADDR: %s\n", strerror(errno));
406     }
407     // Bind the socket to any address
408 #if CONFIG_LWIP_IPV6
409     struct sockaddr_in6 saddr = { INADDR_ANY };
410     saddr.sin6_family = AF_INET6;
411     saddr.sin6_port = htons(5353);
412     bzero(&saddr.sin6_addr.s6_addr, sizeof(saddr.sin6_addr.s6_addr));
413     int err = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6));
414     if (err < 0) {
415         ESP_LOGE(TAG, "Failed to bind socket. Error %d", errno);
416         goto err;
417     }
418 #else
419     struct sockaddr_in saddr = { 0 };
420     saddr.sin_family = AF_INET;
421     saddr.sin_port = htons(5353);
422     bzero(&saddr.sin_addr.s_addr, sizeof(saddr.sin_addr.s_addr));
423     int err = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
424     if (err < 0) {
425         ESP_LOGE(TAG, "Failed to bind socket. Error %d", errno);
426         goto err;
427     }
428 #endif // CONFIG_LWIP_IPV6
429     struct ifreq ifr;
430     esp_netif_get_netif_impl_name(netif, ifr.ifr_name);
431     int ret = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,  (void*)&ifr, sizeof(struct ifreq));
432     if (ret < 0) {
433         ESP_LOGE(TAG, "\"%s\" Unable to bind socket to specified interface: errno %d", esp_netif_get_desc(netif), errno);
434         goto err;
435     }
436 
437     return sock;
438 
439 err:
440     close(sock);
441     return -1;
442 }
443 
444 #if CONFIG_LWIP_IPV6
socket_add_ipv6_multicast_group(int sock,esp_netif_t * netif)445 static int socket_add_ipv6_multicast_group(int sock, esp_netif_t *netif)
446 {
447     int ifindex = esp_netif_get_netif_impl_index(netif);
448     int err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex));
449     if (err < 0) {
450         ESP_LOGE(TAG, "Failed to set IPV6_MULTICAST_IF. Error %d", errno);
451         return err;
452     }
453 
454     struct ipv6_mreq v6imreq = { 0 };
455     esp_ip_addr_t multi_addr = ESP_IP6ADDR_INIT(0x000002ff, 0, 0, 0xfb000000);
456     memcpy(&v6imreq.ipv6mr_multiaddr, &multi_addr.u_addr.ip6.addr, sizeof(v6imreq.ipv6mr_multiaddr));
457     v6imreq.ipv6mr_interface = ifindex;
458     err = setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &v6imreq, sizeof(struct ipv6_mreq));
459     if (err < 0) {
460         ESP_LOGE(TAG, "Failed to set IPV6_ADD_MEMBERSHIP. Error %d", errno);
461         return err;
462     }
463     return err;
464 }
465 #endif // CONFIG_LWIP_IPV6
466 
socket_add_ipv4_multicast_group(int sock,esp_netif_t * netif)467 static int socket_add_ipv4_multicast_group(int sock, esp_netif_t *netif)
468 {
469     struct ip_mreq imreq = { 0 };
470     int err = 0;
471     esp_netif_ip_info_t ip_info = { 0 };
472 
473     if (esp_netif_get_ip_info(netif, &ip_info) != ESP_OK) {
474         ESP_LOGE(TAG, "Failed to esp_netif_get_ip_info()");
475         goto err;
476     }
477     imreq.imr_interface.s_addr = ip_info.ip.addr;
478 
479     esp_ip_addr_t multicast_addr = ESP_IP4ADDR_INIT(224, 0, 0, 251);
480     imreq.imr_multiaddr.s_addr = multicast_addr.u_addr.ip4.addr;
481 
482     err = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(struct ip_mreq));
483     if (err < 0) {
484         ESP_LOGE(TAG, "%d %s", sock, strerror(errno));
485         ESP_LOGE(TAG, "Failed to set IP_ADD_MEMBERSHIP. Error %d", errno);
486         goto err;
487     }
488 
489  err:
490     return err;
491 }
492 
join_mdns_multicast_group(int sock,esp_netif_t * netif,mdns_ip_protocol_t ip_protocol)493 static int join_mdns_multicast_group(int sock, esp_netif_t *netif, mdns_ip_protocol_t ip_protocol)
494 {
495     if (ip_protocol == MDNS_IP_PROTOCOL_V4) {
496         return socket_add_ipv4_multicast_group(sock, netif);
497     }
498 #if CONFIG_LWIP_IPV6
499     if (ip_protocol == MDNS_IP_PROTOCOL_V6) {
500         return socket_add_ipv6_multicast_group(sock, netif);
501     }
502 #endif // CONFIG_LWIP_IPV6
503     return -1;
504 }
505