1 /** @file
2  * @brief mDNS responder
3  *
4  * This listens to mDNS queries and responds to them.
5  */
6 
7 /*
8  * Copyright (c) 2017 Intel Corporation
9  * Copyright (c) 2020 Friedt Professional Engineering Services, Inc
10  *
11  * SPDX-License-Identifier: Apache-2.0
12  */
13 
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(net_mdns_responder, CONFIG_MDNS_RESPONDER_LOG_LEVEL);
16 
17 #include <zephyr/kernel.h>
18 #include <zephyr/init.h>
19 #include <string.h>
20 #include <strings.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 
24 #include <zephyr/net/net_core.h>
25 #include <zephyr/net/net_ip.h>
26 #include <zephyr/net/net_pkt.h>
27 #include <zephyr/net/dns_resolve.h>
28 #include <zephyr/net/igmp.h>
29 
30 #include "dns_sd.h"
31 #include "dns_pack.h"
32 #include "ipv6.h"
33 
34 #include "net_private.h"
35 
36 #define MDNS_LISTEN_PORT 5353
37 
38 #define MDNS_TTL CONFIG_MDNS_RESPONDER_TTL /* In seconds */
39 
40 #if defined(CONFIG_NET_IPV4)
41 #define MAX_IPV4_IFACE_COUNT CONFIG_NET_IF_MAX_IPV4_COUNT
42 static struct net_context *ipv4[MAX_IPV4_IFACE_COUNT];
43 static struct sockaddr_in local_addr4;
44 #else
45 #define MAX_IPV4_IFACE_COUNT 0
46 #endif
47 #if defined(CONFIG_NET_IPV6)
48 #define MAX_IPV6_IFACE_COUNT CONFIG_NET_IF_MAX_IPV6_COUNT
49 static struct net_context *ipv6[MAX_IPV6_IFACE_COUNT];
50 #else
51 #define MAX_IPV6_IFACE_COUNT 0
52 #endif
53 
54 static struct net_mgmt_event_callback mgmt_cb;
55 
56 #define BUF_ALLOC_TIMEOUT K_MSEC(100)
57 
58 /* This value is recommended by RFC 1035 */
59 #define DNS_RESOLVER_MAX_BUF_SIZE	512
60 #define DNS_RESOLVER_MIN_BUF		2
61 #define DNS_RESOLVER_BUF_CTR	(DNS_RESOLVER_MIN_BUF + \
62 				 CONFIG_MDNS_RESOLVER_ADDITIONAL_BUF_CTR)
63 
64 #ifndef CONFIG_NET_TEST
65 static int setup_dst_addr(struct net_context *ctx, sa_family_t family,
66 			  struct sockaddr *dst, socklen_t *dst_len);
67 #endif /* CONFIG_NET_TEST */
68 
69 NET_BUF_POOL_DEFINE(mdns_msg_pool, DNS_RESOLVER_BUF_CTR,
70 		    DNS_RESOLVER_MAX_BUF_SIZE, 0, NULL);
71 
create_ipv6_addr(struct sockaddr_in6 * addr)72 static void create_ipv6_addr(struct sockaddr_in6 *addr)
73 {
74 	addr->sin6_family = AF_INET6;
75 	addr->sin6_port = htons(MDNS_LISTEN_PORT);
76 
77 	/* Well known IPv6 ff02::fb address */
78 	net_ipv6_addr_create(&addr->sin6_addr,
79 			     0xff02, 0, 0, 0, 0, 0, 0, 0x00fb);
80 }
81 
create_ipv4_addr(struct sockaddr_in * addr)82 static void create_ipv4_addr(struct sockaddr_in *addr)
83 {
84 	addr->sin_family = AF_INET;
85 	addr->sin_port = htons(MDNS_LISTEN_PORT);
86 
87 	/* Well known IPv4 224.0.0.251 address */
88 	addr->sin_addr.s_addr = htonl(0xE00000FB);
89 }
90 
mdns_iface_event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)91 static void mdns_iface_event_handler(struct net_mgmt_event_callback *cb,
92 				     uint32_t mgmt_event, struct net_if *iface)
93 
94 {
95 	if (mgmt_event == NET_EVENT_IF_UP) {
96 #if defined(CONFIG_NET_IPV4)
97 		int ret = net_ipv4_igmp_join(iface, &local_addr4.sin_addr, NULL);
98 
99 		if (ret < 0) {
100 			NET_DBG("Cannot add IPv4 multicast address to iface %p",
101 				iface);
102 		}
103 #endif /* defined(CONFIG_NET_IPV4) */
104 	}
105 }
106 
setup_dst_addr(struct net_context * ctx,sa_family_t family,struct sockaddr * dst,socklen_t * dst_len)107 int setup_dst_addr(struct net_context *ctx, sa_family_t family,
108 		   struct sockaddr *dst, socklen_t *dst_len)
109 {
110 	if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
111 		create_ipv4_addr(net_sin(dst));
112 		*dst_len = sizeof(struct sockaddr_in);
113 		net_context_set_ipv4_mcast_ttl(ctx, 255);
114 	} else if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) {
115 		create_ipv6_addr(net_sin6(dst));
116 		*dst_len = sizeof(struct sockaddr_in6);
117 		net_context_set_ipv6_mcast_hop_limit(ctx, 255);
118 	} else {
119 		return -EPFNOSUPPORT;
120 	}
121 
122 	return 0;
123 }
124 
get_ctx(sa_family_t family)125 static struct net_context *get_ctx(sa_family_t family)
126 {
127 	struct net_context *ctx;
128 	int ret;
129 
130 	ret = net_context_get(family, SOCK_DGRAM, IPPROTO_UDP, &ctx);
131 	if (ret < 0) {
132 		NET_DBG("Cannot get context (%d)", ret);
133 		return NULL;
134 	}
135 
136 	return ctx;
137 }
138 
bind_ctx(struct net_context * ctx,struct sockaddr * local_addr,socklen_t addrlen)139 static int bind_ctx(struct net_context *ctx,
140 		    struct sockaddr *local_addr,
141 		    socklen_t addrlen)
142 {
143 	int ret;
144 
145 	if (!ctx) {
146 		return -EINVAL;
147 	}
148 
149 	ret = net_context_bind(ctx, local_addr, addrlen);
150 	if (ret < 0) {
151 		NET_DBG("Cannot bind to mDNS %s port (%d)",
152 			local_addr->sa_family == AF_INET ?
153 			"IPv4" : "IPv6", ret);
154 		return ret;
155 	}
156 
157 	return ret;
158 }
159 
setup_dns_hdr(uint8_t * buf,uint16_t answers)160 static void setup_dns_hdr(uint8_t *buf, uint16_t answers)
161 {
162 	uint16_t offset;
163 	uint16_t flags;
164 
165 	/* See RFC 1035, ch 4.1.1 for header details */
166 
167 	flags = BIT(15);  /* This is response */
168 	flags |= BIT(10); /* Authoritative Answer */
169 
170 	UNALIGNED_PUT(0, (uint16_t *)(buf)); /* Identifier, RFC 6762 ch 18.1 */
171 	offset = DNS_HEADER_ID_LEN;
172 
173 	UNALIGNED_PUT(htons(flags), (uint16_t *)(buf+offset));
174 	offset += DNS_HEADER_FLAGS_LEN;
175 
176 	UNALIGNED_PUT(0, (uint16_t *)(buf + offset));
177 	offset += DNS_QDCOUNT_LEN;
178 
179 	UNALIGNED_PUT(htons(answers), (uint16_t *)(buf + offset));
180 	offset += DNS_ANCOUNT_LEN;
181 
182 	UNALIGNED_PUT(0, (uint16_t *)(buf + offset));
183 	offset += DNS_NSCOUNT_LEN;
184 
185 	UNALIGNED_PUT(0, (uint16_t *)(buf + offset));
186 }
187 
add_answer(struct net_buf * query,enum dns_rr_type qtype,uint32_t ttl,uint16_t addr_len,uint8_t * addr)188 static void add_answer(struct net_buf *query, enum dns_rr_type qtype,
189 		       uint32_t ttl, uint16_t addr_len, uint8_t *addr)
190 {
191 	char *dot = query->data + DNS_MSG_HEADER_SIZE;
192 	char *prev = NULL;
193 	uint16_t offset;
194 
195 	while ((dot = strchr(dot, '.'))) {
196 		if (!prev) {
197 			prev = dot++;
198 			continue;
199 		}
200 
201 		*prev = dot - prev - 1;
202 		prev = dot++;
203 	}
204 
205 	if (prev) {
206 		*prev = strlen(prev) - 1;
207 	}
208 
209 	/* terminator byte (0x00) */
210 	query->len += 1;
211 
212 	offset = DNS_MSG_HEADER_SIZE + query->len;
213 	UNALIGNED_PUT(htons(qtype), (uint16_t *)(query->data+offset));
214 
215 	/* Bit 15 tells to flush the cache */
216 	offset += DNS_QTYPE_LEN;
217 	UNALIGNED_PUT(htons(DNS_CLASS_IN | BIT(15)),
218 		      (uint16_t *)(query->data+offset));
219 
220 
221 	offset += DNS_QCLASS_LEN;
222 	UNALIGNED_PUT(htonl(ttl), query->data + offset);
223 
224 	offset += DNS_TTL_LEN;
225 	UNALIGNED_PUT(htons(addr_len), query->data + offset);
226 
227 	offset += DNS_RDLENGTH_LEN;
228 	memcpy(query->data + offset, addr, addr_len);
229 }
230 
create_answer(struct net_context * ctx,struct net_buf * query,enum dns_rr_type qtype,uint16_t addr_len,uint8_t * addr)231 static int create_answer(struct net_context *ctx,
232 			 struct net_buf *query,
233 			 enum dns_rr_type qtype,
234 			 uint16_t addr_len, uint8_t *addr)
235 {
236 	/* Prepare the response into the query buffer: move the name
237 	 * query buffer has to get enough free space: dns_hdr + answer
238 	 */
239 	if ((query->size - query->len) < (DNS_MSG_HEADER_SIZE +
240 					  DNS_QTYPE_LEN + DNS_QCLASS_LEN +
241 					  DNS_TTL_LEN + DNS_RDLENGTH_LEN +
242 					  addr_len)) {
243 		return -ENOBUFS;
244 	}
245 
246 	memmove(query->data + DNS_MSG_HEADER_SIZE, query->data, query->len);
247 
248 	setup_dns_hdr(query->data, 1);
249 
250 	add_answer(query, qtype, MDNS_TTL, addr_len, addr);
251 
252 	query->len += DNS_MSG_HEADER_SIZE +
253 		DNS_QTYPE_LEN + DNS_QCLASS_LEN +
254 		DNS_TTL_LEN + DNS_RDLENGTH_LEN + addr_len;
255 
256 	return 0;
257 }
258 
send_response(struct net_context * ctx,struct net_if * iface,sa_family_t family,const void * src_addr,struct net_buf * query,enum dns_rr_type qtype)259 static int send_response(struct net_context *ctx,
260 			 struct net_if *iface,
261 			 sa_family_t family,
262 			 const void *src_addr,
263 			 struct net_buf *query,
264 			 enum dns_rr_type qtype)
265 {
266 	struct sockaddr dst;
267 	socklen_t dst_len;
268 	int ret;
269 
270 	ret = setup_dst_addr(ctx, family, &dst, &dst_len);
271 	if (ret < 0) {
272 		NET_DBG("unable to set up the response address");
273 		return ret;
274 	}
275 
276 	if (IS_ENABLED(CONFIG_NET_IPV4) && qtype == DNS_RR_TYPE_A) {
277 		const struct in_addr *addr;
278 
279 		if (family == AF_INET) {
280 			addr = net_if_ipv4_select_src_addr(iface, (struct in_addr *)src_addr);
281 		} else {
282 			struct sockaddr_in tmp_addr;
283 
284 			create_ipv4_addr(&tmp_addr);
285 			addr = net_if_ipv4_select_src_addr(iface, &tmp_addr.sin_addr);
286 		}
287 
288 		ret = create_answer(ctx, query, qtype, sizeof(struct in_addr), (uint8_t *)addr);
289 		if (ret != 0) {
290 			return ret;
291 		}
292 	} else if (IS_ENABLED(CONFIG_NET_IPV6) && qtype == DNS_RR_TYPE_AAAA) {
293 		const struct in6_addr *addr;
294 
295 		if (family == AF_INET6) {
296 			addr = net_if_ipv6_select_src_addr(iface, (struct in6_addr *)src_addr);
297 		} else {
298 			struct sockaddr_in6 tmp_addr;
299 
300 			create_ipv6_addr(&tmp_addr);
301 			addr = net_if_ipv6_select_src_addr(iface, &tmp_addr.sin6_addr);
302 		}
303 
304 		ret = create_answer(ctx, query, qtype, sizeof(struct in6_addr), (uint8_t *)addr);
305 		if (ret != 0) {
306 			return -ENOMEM;
307 		}
308 	} else {
309 		/* TODO: support also service PTRs */
310 		return -EINVAL;
311 	}
312 
313 	ret = net_context_sendto(ctx, query->data, query->len, &dst,
314 				 dst_len, NULL, K_NO_WAIT, NULL);
315 	if (ret < 0) {
316 		NET_DBG("Cannot send mDNS reply (%d)", ret);
317 	}
318 
319 	return ret;
320 }
321 
qtype_to_string(int qtype)322 static const char *qtype_to_string(int qtype)
323 {
324 	switch (qtype) {
325 	case DNS_RR_TYPE_A: return "A";
326 	case DNS_RR_TYPE_CNAME: return "CNAME";
327 	case DNS_RR_TYPE_PTR: return "PTR";
328 	case DNS_RR_TYPE_TXT: return "TXT";
329 	case DNS_RR_TYPE_AAAA: return "AAAA";
330 	case DNS_RR_TYPE_SRV: return "SRV";
331 	default: return "<unknown type>";
332 	}
333 }
334 
send_sd_response(struct net_context * ctx,struct net_if * iface,sa_family_t family,const void * src_addr,struct dns_msg_t * dns_msg,struct net_buf * result)335 static void send_sd_response(struct net_context *ctx,
336 			     struct net_if *iface,
337 			     sa_family_t family,
338 			     const void *src_addr,
339 			     struct dns_msg_t *dns_msg,
340 			     struct net_buf *result)
341 {
342 	int ret;
343 	/* filter must be zero-initialized for "wildcard" port */
344 	struct dns_sd_rec filter = {0};
345 	struct sockaddr dst;
346 	socklen_t dst_len;
347 	bool service_type_enum = false;
348 	const struct in6_addr *addr6 = NULL;
349 	const struct in_addr *addr4 = NULL;
350 	char instance_buf[DNS_SD_SERVICE_MAX_SIZE + 1];
351 	char service_buf[DNS_SD_SERVICE_MAX_SIZE + 1];
352 	char proto_buf[DNS_SD_PROTO_SIZE + 1];
353 	char domain_buf[DNS_SD_DOMAIN_MAX_SIZE + 1];
354 	char *label[4];
355 	size_t size[] = {
356 		ARRAY_SIZE(instance_buf),
357 		ARRAY_SIZE(service_buf),
358 		ARRAY_SIZE(proto_buf),
359 		ARRAY_SIZE(domain_buf),
360 	};
361 	size_t n = ARRAY_SIZE(label);
362 
363 	BUILD_ASSERT(ARRAY_SIZE(label) == ARRAY_SIZE(size), "");
364 
365 	/*
366 	 * work around for bug in compliance scripts which say that the array
367 	 * should be static const (incorrect)
368 	 */
369 	label[0] = instance_buf;
370 	label[1] = service_buf;
371 	label[2] = proto_buf;
372 	label[3] = domain_buf;
373 
374 	ret = setup_dst_addr(ctx, family, &dst, &dst_len);
375 	if (ret < 0) {
376 		NET_DBG("unable to set up the response address");
377 		return;
378 	}
379 
380 	if (IS_ENABLED(CONFIG_NET_IPV4)) {
381 		/* Look up the local IPv4 address */
382 		if (family == AF_INET) {
383 			addr4 = net_if_ipv4_select_src_addr(iface, (struct in_addr *)src_addr);
384 		} else {
385 			struct sockaddr_in tmp_addr;
386 
387 			create_ipv4_addr(&tmp_addr);
388 			addr4 = net_if_ipv4_select_src_addr(iface, &tmp_addr.sin_addr);
389 		}
390 	}
391 
392 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
393 		/* Look up the local IPv6 address */
394 		if (family == AF_INET6) {
395 			addr6 = net_if_ipv6_select_src_addr(iface, (struct in6_addr *)src_addr);
396 		} else {
397 			struct sockaddr_in6 tmp_addr;
398 
399 			create_ipv6_addr(&tmp_addr);
400 			addr6 = net_if_ipv6_select_src_addr(iface, &tmp_addr.sin6_addr);
401 		}
402 	}
403 
404 	ret = dns_sd_query_extract(dns_msg->msg,
405 		dns_msg->msg_size, &filter, label, size, &n);
406 	if (ret < 0) {
407 		NET_DBG("unable to extract query (%d)", ret);
408 		return;
409 	}
410 
411 	if (IS_ENABLED(CONFIG_MDNS_RESPONDER_DNS_SD_SERVICE_TYPE_ENUMERATION)
412 		&& dns_sd_is_service_type_enumeration(&filter)) {
413 
414 		/*
415 		 * RFC 6763, Section 9
416 		 *
417 		 * A DNS query for PTR records with the name
418 		 * "_services._dns-sd._udp.<Domain>" yields a set of PTR records,
419 		 * where the rdata of each PTR record is the two-label <Service> name,
420 		 * plus the same domain, e.g., "_http._tcp.<Domain>".
421 		 */
422 		dns_sd_create_wildcard_filter(&filter);
423 		service_type_enum = true;
424 	}
425 
426 	DNS_SD_FOREACH(record) {
427 		/* Checks validity and then compare */
428 		if (dns_sd_rec_match(record, &filter)) {
429 			NET_DBG("matched query: %s.%s.%s.%s port: %u",
430 				record->instance, record->service,
431 				record->proto, record->domain,
432 				ntohs(*(record->port)));
433 
434 			/* Construct the response */
435 			if (service_type_enum) {
436 				ret = dns_sd_handle_service_type_enum(record, addr4, addr6,
437 					result->data, result->size);
438 				if (ret < 0) {
439 					NET_DBG("dns_sd_handle_service_type_enum() failed (%d)",
440 						ret);
441 					continue;
442 				}
443 			} else {
444 				ret = dns_sd_handle_ptr_query(record, addr4, addr6,
445 					result->data, result->size);
446 				if (ret < 0) {
447 					NET_DBG("dns_sd_handle_ptr_query() failed (%d)", ret);
448 					continue;
449 				}
450 			}
451 
452 			result->len = ret;
453 
454 			/* Send the response */
455 			ret = net_context_sendto(ctx, result->data,
456 				result->len, &dst, dst_len, NULL,
457 				K_NO_WAIT, NULL);
458 			if (ret < 0) {
459 				NET_DBG("Cannot send mDNS reply (%d)", ret);
460 				continue;
461 			}
462 		}
463 	}
464 }
465 
dns_read(struct net_context * ctx,struct net_pkt * pkt,struct net_buf * dns_data,struct dns_addrinfo * info)466 static int dns_read(struct net_context *ctx,
467 		    struct net_pkt *pkt,
468 		    struct net_buf *dns_data,
469 		    struct dns_addrinfo *info)
470 {
471 	/* Helper struct to track the dns msg received from the server */
472 	const char *hostname = net_hostname_get();
473 	int hostname_len = strlen(hostname);
474 	struct net_buf *result;
475 	struct dns_msg_t dns_msg;
476 	const void *src_addr;
477 	int data_len;
478 	int queries;
479 	int ret;
480 
481 	data_len = MIN(net_pkt_remaining_data(pkt), DNS_RESOLVER_MAX_BUF_SIZE);
482 
483 	/* Store the DNS query name into a temporary net_buf, which will be
484 	 * eventually used to send a response
485 	 */
486 	result = net_buf_alloc(&mdns_msg_pool, BUF_ALLOC_TIMEOUT);
487 	if (!result) {
488 		ret = -ENOMEM;
489 		goto quit;
490 	}
491 
492 	/* TODO: Instead of this temporary copy, just use the net_pkt directly.
493 	 */
494 	ret = net_pkt_read(pkt, dns_data->data, data_len);
495 	if (ret < 0) {
496 		goto quit;
497 	}
498 
499 	dns_msg.msg = dns_data->data;
500 	dns_msg.msg_size = data_len;
501 
502 	ret = mdns_unpack_query_header(&dns_msg, NULL);
503 	if (ret < 0) {
504 		ret = -EINVAL;
505 		goto quit;
506 	}
507 
508 	queries = ret;
509 
510 	src_addr = net_pkt_family(pkt) == AF_INET
511 		 ? (const void *)&NET_IPV4_HDR(pkt)->src : (const void *)&NET_IPV6_HDR(pkt)->src;
512 
513 	NET_DBG("Received %d %s from %s", queries,
514 		queries > 1 ? "queries" : "query",
515 		net_sprint_addr(net_pkt_family(pkt), src_addr));
516 
517 	do {
518 		enum dns_rr_type qtype;
519 		enum dns_class qclass;
520 		uint8_t *lquery;
521 
522 		(void)memset(result->data, 0, net_buf_tailroom(result));
523 		result->len = 0U;
524 
525 		ret = dns_unpack_query(&dns_msg, result, &qtype, &qclass);
526 		if (ret < 0) {
527 			goto quit;
528 		}
529 
530 		/* Handle only .local queries */
531 		lquery = strrchr(result->data + 1, '.');
532 		if (!lquery || memcmp(lquery, (const void *){ ".local" }, 7)) {
533 			continue;
534 		}
535 
536 		NET_DBG("[%d] query %s/%s label %s (%d bytes)", queries,
537 			qtype_to_string(qtype), "IN",
538 			result->data, ret);
539 
540 		/* If the query matches to our hostname, then send reply.
541 		 * We skip the first dot, and make sure there is dot after
542 		 * matching hostname.
543 		 */
544 		if (!strncasecmp(hostname, result->data + 1, hostname_len) &&
545 		    (result->len - 1) >= hostname_len &&
546 		    &(result->data + 1)[hostname_len] == lquery) {
547 			NET_DBG("mDNS query to our hostname %s.local",
548 				hostname);
549 			send_response(ctx, net_pkt_iface(pkt), net_pkt_family(pkt), src_addr,
550 				      result, qtype);
551 		} else if (IS_ENABLED(CONFIG_MDNS_RESPONDER_DNS_SD)
552 			&& qtype == DNS_RR_TYPE_PTR) {
553 			send_sd_response(ctx, net_pkt_iface(pkt), net_pkt_family(pkt), src_addr,
554 					 &dns_msg, result);
555 		}
556 
557 	} while (--queries);
558 
559 	ret = 0;
560 
561 quit:
562 	if (result) {
563 		net_buf_unref(result);
564 	}
565 
566 	return ret;
567 }
568 
recv_cb(struct net_context * net_ctx,struct net_pkt * pkt,union net_ip_header * ip_hdr,union net_proto_header * proto_hdr,int status,void * user_data)569 static void recv_cb(struct net_context *net_ctx,
570 		    struct net_pkt *pkt,
571 		    union net_ip_header *ip_hdr,
572 		    union net_proto_header *proto_hdr,
573 		    int status,
574 		    void *user_data)
575 {
576 	struct net_context *ctx = user_data;
577 	struct net_buf *dns_data = NULL;
578 	struct dns_addrinfo info = { 0 };
579 	int ret;
580 
581 	ARG_UNUSED(net_ctx);
582 	ARG_UNUSED(ip_hdr);
583 	ARG_UNUSED(proto_hdr);
584 	NET_ASSERT(ctx == net_ctx);
585 
586 	if (!pkt) {
587 		return;
588 	}
589 
590 	if (status) {
591 		goto quit;
592 	}
593 
594 	dns_data = net_buf_alloc(&mdns_msg_pool, BUF_ALLOC_TIMEOUT);
595 	if (!dns_data) {
596 		goto quit;
597 	}
598 
599 	ret = dns_read(ctx, pkt, dns_data, &info);
600 	if (ret < 0 && ret != -EINVAL) {
601 		NET_DBG("mDNS read failed (%d)", ret);
602 	}
603 
604 	net_buf_unref(dns_data);
605 
606 quit:
607 	net_pkt_unref(pkt);
608 }
609 
610 #if defined(CONFIG_NET_IPV6)
iface_ipv6_cb(struct net_if * iface,void * user_data)611 static void iface_ipv6_cb(struct net_if *iface, void *user_data)
612 {
613 	struct in6_addr *addr = user_data;
614 	int ret;
615 
616 	ret = net_ipv6_mld_join(iface, addr);
617 	if (ret < 0) {
618 		NET_DBG("Cannot join %s IPv6 multicast group (%d)",
619 			net_sprint_ipv6_addr(addr), ret);
620 	}
621 }
622 
setup_ipv6_addr(struct sockaddr_in6 * local_addr)623 static void setup_ipv6_addr(struct sockaddr_in6 *local_addr)
624 {
625 	create_ipv6_addr(local_addr);
626 
627 	net_if_foreach(iface_ipv6_cb, &local_addr->sin6_addr);
628 }
629 #endif /* CONFIG_NET_IPV6 */
630 
631 #if defined(CONFIG_NET_IPV4)
iface_ipv4_cb(struct net_if * iface,void * user_data)632 static void iface_ipv4_cb(struct net_if *iface, void *user_data)
633 {
634 	struct in_addr *addr = user_data;
635 	int ret;
636 
637 	ret = net_ipv4_igmp_join(iface, addr, NULL);
638 	if (ret < 0) {
639 		NET_DBG("Cannot add IPv4 multicast address to iface %p",
640 			iface);
641 	}
642 }
643 
setup_ipv4_addr(struct sockaddr_in * local_addr)644 static void setup_ipv4_addr(struct sockaddr_in *local_addr)
645 {
646 	create_ipv4_addr(local_addr);
647 
648 	net_if_foreach(iface_ipv4_cb, &local_addr->sin_addr);
649 }
650 #endif /* CONFIG_NET_IPV4 */
651 
init_listener(void)652 static int init_listener(void)
653 {
654 	int ret, ok = 0, i;
655 	struct net_if *iface;
656 	int iface_count;
657 
658 	NET_IFACE_COUNT(&iface_count);
659 	NET_DBG("Setting mDNS listener to %d interface%s", iface_count,
660 		iface_count > 1 ? "s" : "");
661 
662 	if ((iface_count > MAX_IPV6_IFACE_COUNT && MAX_IPV6_IFACE_COUNT > 0) ||
663 	    (iface_count > MAX_IPV4_IFACE_COUNT && MAX_IPV4_IFACE_COUNT > 0)) {
664 		NET_WARN("You have %d interfaces configured but there "
665 			 "are %d network interfaces in the system.",
666 			 MAX(MAX_IPV4_IFACE_COUNT,
667 			     MAX_IPV6_IFACE_COUNT), iface_count);
668 	}
669 
670 #if defined(CONFIG_NET_IPV6)
671 	struct sockaddr_in6 local_addr6;
672 	struct net_context *v6;
673 
674 	setup_ipv6_addr(&local_addr6);
675 
676 	for (i = 0; i < MAX_IPV6_IFACE_COUNT; i++) {
677 		v6 = get_ctx(AF_INET6);
678 		if (v6 == NULL) {
679 			NET_ERR("Cannot get %s context out of %d. Max contexts is %d",
680 				"IPv6", MAX_IPV6_IFACE_COUNT, CONFIG_NET_MAX_CONTEXTS);
681 			continue;
682 		}
683 
684 		iface = net_if_get_by_index(i + 1);
685 		if (iface == NULL) {
686 			net_context_unref(v6);
687 			continue;
688 		}
689 
690 		net_context_bind_iface(v6, iface);
691 
692 		ret = bind_ctx(v6, (struct sockaddr *)&local_addr6,
693 			       sizeof(local_addr6));
694 		if (ret < 0) {
695 			net_context_put(v6);
696 			goto ipv6_out;
697 		}
698 
699 		ret = net_context_recv(v6, recv_cb, K_NO_WAIT, v6);
700 		if (ret < 0) {
701 			NET_WARN("Cannot receive %s mDNS data (%d)", "IPv6", ret);
702 			net_context_put(v6);
703 		} else {
704 			ipv6[i] = v6;
705 			ok++;
706 		}
707 	}
708 ipv6_out:
709 	; /* Added ";" to avoid clang compile error because of
710 	   * the "struct net_context *v4" after it.
711 	   */
712 #endif /* CONFIG_NET_IPV6 */
713 
714 #if defined(CONFIG_NET_IPV4)
715 	struct net_context *v4;
716 
717 	setup_ipv4_addr(&local_addr4);
718 
719 	for (i = 0; i < MAX_IPV4_IFACE_COUNT; i++) {
720 		v4 = get_ctx(AF_INET);
721 		if (v4 == NULL) {
722 			NET_ERR("Cannot get %s context out of %d. Max contexts is %d",
723 				"IPv4", MAX_IPV4_IFACE_COUNT, CONFIG_NET_MAX_CONTEXTS);
724 			continue;
725 		}
726 
727 		iface = net_if_get_by_index(i + 1);
728 		if (iface == NULL) {
729 			net_context_unref(v4);
730 			continue;
731 		}
732 
733 		net_context_bind_iface(v4, iface);
734 
735 		ret = bind_ctx(v4, (struct sockaddr *)&local_addr4,
736 			       sizeof(local_addr4));
737 		if (ret < 0) {
738 			net_context_put(v4);
739 			goto ipv4_out;
740 		}
741 
742 		ret = net_context_recv(v4, recv_cb, K_NO_WAIT, v4);
743 		if (ret < 0) {
744 			NET_WARN("Cannot receive %s mDNS data (%d)", "IPv4", ret);
745 			net_context_put(v4);
746 		} else {
747 			ipv4[i] = v4;
748 			ok++;
749 		}
750 	}
751 ipv4_out:
752 #endif /* CONFIG_NET_IPV4 */
753 
754 	if (!ok) {
755 		NET_WARN("Cannot start mDNS responder");
756 	}
757 
758 	return !ok;
759 }
760 
mdns_responder_init(void)761 static int mdns_responder_init(void)
762 {
763 
764 	net_mgmt_init_event_callback(&mgmt_cb, mdns_iface_event_handler,
765 				     NET_EVENT_IF_UP);
766 
767 	net_mgmt_add_event_callback(&mgmt_cb);
768 
769 	return init_listener();
770 }
771 
772 SYS_INIT(mdns_responder_init, APPLICATION, CONFIG_MDNS_RESPONDER_INIT_PRIO);
773