mdns_networking_socket.c 17 KB

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