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