mdns_networking_socket.c 18 KB

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