ReactOS 0.4.16-dev-1292-g1ece139
mdns.c
Go to the documentation of this file.
1
25/*
26 * Copyright (c) 2015 Verisure Innovation AB
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without modification,
30 * are permitted provided that the following conditions are met:
31 *
32 * 1. Redistributions of source code must retain the above copyright notice,
33 * this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright notice,
35 * this list of conditions and the following disclaimer in the documentation
36 * and/or other materials provided with the distribution.
37 * 3. The name of the author may not be used to endorse or promote products
38 * derived from this software without specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
41 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
42 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
43 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
44 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
45 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
46 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
48 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
49 * OF SUCH DAMAGE.
50 *
51 * This file is part of the lwIP TCP/IP stack.
52 *
53 * Author: Erik Ekman <erik@kryo.se>
54 * Author: Jasper Verschueren <jasper.verschueren@apart-audio.com>
55 *
56 */
57
58#include "lwip/apps/mdns.h"
59#include "lwip/apps/mdns_priv.h"
61#include "lwip/apps/mdns_out.h"
62#include "lwip/netif.h"
63#include "lwip/udp.h"
64#include "lwip/ip_addr.h"
65#include "lwip/mem.h"
66#include "lwip/memp.h"
67#include "lwip/prot/dns.h"
68#include "lwip/prot/iana.h"
69#include "lwip/timeouts.h"
70#include "lwip/sys.h"
71
72#include <string.h> /* memset */
73#include <stdio.h> /* snprintf */
74
75#if LWIP_MDNS_RESPONDER
76
77#if (LWIP_IPV4 && !LWIP_IGMP)
78#error "If you want to use MDNS with IPv4, you have to define LWIP_IGMP=1 in your lwipopts.h"
79#endif
80#if (LWIP_IPV6 && !LWIP_IPV6_MLD)
81#error "If you want to use MDNS with IPv6, you have to define LWIP_IPV6_MLD=1 in your lwipopts.h"
82#endif
83#if (!LWIP_UDP)
84#error "If you want to use MDNS, you have to define LWIP_UDP=1 in your lwipopts.h"
85#endif
86#ifndef LWIP_RAND
87#error "If you want to use MDNS, you have to define LWIP_RAND=(random function) in your lwipopts.h"
88#endif
89
90#if LWIP_IPV4
91#include "lwip/igmp.h"
92/* IPv4 multicast group 224.0.0.251 */
93static const ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT;
94#endif
95
96#if LWIP_IPV6
97#include "lwip/mld6.h"
98/* IPv6 multicast group FF02::FB */
99static const ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT;
100#endif
101
102#define MDNS_IP_TTL 255
103
104#if LWIP_MDNS_SEARCH
105static struct mdns_request mdns_requests[MDNS_MAX_REQUESTS];
106#endif
107
108static u8_t mdns_netif_client_id;
109static struct udp_pcb *mdns_pcb;
110#if MDNS_RESP_USENETIF_EXTCALLBACK
111NETIF_DECLARE_EXT_CALLBACK(netif_callback)
112#endif
113static mdns_name_result_cb_t mdns_name_result_cb;
114
115#define NETIF_TO_HOST(netif) (struct mdns_host*)(netif_get_client_data(netif, mdns_netif_client_id))
116
118#define MDNS_RESPONSE_DELAY_MAX 120
119#define MDNS_RESPONSE_DELAY_MIN 20
120#define MDNS_RESPONSE_DELAY (LWIP_RAND() %(MDNS_RESPONSE_DELAY_MAX - \
121 MDNS_RESPONSE_DELAY_MIN) + MDNS_RESPONSE_DELAY_MIN)
122/* Delayed response for truncated question defines */
123#define MDNS_RESPONSE_TC_DELAY_MAX 500
124#define MDNS_RESPONSE_TC_DELAY_MIN 400
125#define MDNS_RESPONSE_TC_DELAY_MS (LWIP_RAND() % (MDNS_RESPONSE_TC_DELAY_MAX - \
126 MDNS_RESPONSE_TC_DELAY_MIN) + MDNS_RESPONSE_TC_DELAY_MIN)
127
129#define MDNS_PROBE_COUNT 3
130#ifdef LWIP_RAND
131/* first probe timeout SHOULD be random 0-250 ms*/
132#define MDNS_INITIAL_PROBE_DELAY_MS (LWIP_RAND() % MDNS_PROBE_DELAY_MS)
133#else
134#define MDNS_INITIAL_PROBE_DELAY_MS MDNS_PROBE_DELAY_MS
135#endif
136
137#define MDNS_PROBE_TIEBREAK_CONFLICT_DELAY_MS 1000
138#define MDNS_PROBE_TIEBREAK_MAX_ANSWERS 5
139
140#define MDNS_LEXICOGRAPHICAL_EQUAL 0
141#define MDNS_LEXICOGRAPHICAL_EARLIER 1
142#define MDNS_LEXICOGRAPHICAL_LATER 2
143
144/* Delay between successive announcements (RFC6762 section 8.3)
145 * -> increase by a factor 2 with every response sent.
146 */
147#define MDNS_ANNOUNCE_DELAY_MS 1000
148/* Minimum 2 announces, may send up to 8 (RFC6762 section 8.3) */
149#define MDNS_ANNOUNCE_COUNT 2
150
152struct mdns_packet {
154 ip_addr_t source_addr;
155 u16_t source_port;
157 u16_t recv_unicast;
159 struct pbuf *pbuf;
161 u16_t parse_offset;
163 u16_t tx_id;
166 u16_t questions;
168 u16_t questions_left;
170 u16_t answers;
172 u16_t answers_left;
174 u16_t authoritative;
176 u16_t authoritative_left;
178 u16_t additional;
180 u16_t additional_left;
182 struct mdns_packet *next_answer;
184 struct mdns_packet *next_tc_question;
185};
186
187/* list of received questions with TC flags set, waiting for known answers */
188static struct mdns_packet *pending_tc_questions;
189
190/* pool of received packets */
191LWIP_MEMPOOL_DECLARE(MDNS_PKTS, MDNS_MAX_STORED_PKTS, sizeof (struct mdns_packet), "Stored mDNS packets")
192
193struct mdns_question {
194 struct mdns_rr_info info;
196 u16_t unicast;
197};
198
199struct mdns_answer_list {
200 u16_t offset[MDNS_PROBE_TIEBREAK_MAX_ANSWERS];
201 u16_t size;
202};
203
204static err_t mdns_parse_pkt_questions(struct netif *netif,
205 struct mdns_packet *pkt,
206 struct mdns_outmsg *reply);
207static void mdns_define_probe_rrs_to_send(struct netif *netif,
208 struct mdns_outmsg *outmsg);
209static void mdns_probe_and_announce(void* arg);
210static void mdns_conflict_save_time(struct netif *netif);
211
221struct mdns_host*
222netif_mdns_data(struct netif *netif) {
223 return NETIF_TO_HOST(netif);
224}
225
231struct udp_pcb*
232get_mdns_pcb(void)
233{
234 return mdns_pcb;
235}
236
245static int
246check_host(struct netif *netif, struct mdns_rr_info *rr, u8_t *reverse_v6_reply)
247{
248 err_t res;
249 int replies = 0;
250 struct mdns_domain mydomain;
251
252 LWIP_UNUSED_ARG(reverse_v6_reply); /* if ipv6 is disabled */
253
254 if (rr->klass != DNS_RRCLASS_IN && rr->klass != DNS_RRCLASS_ANY) {
255 /* Invalid class */
256 return replies;
257 }
258
259 /* Handle PTR for our addresses */
260 if (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY) {
261#if LWIP_IPV6
262 int i;
263 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
264 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
265 res = mdns_build_reverse_v6_domain(&mydomain, netif_ip6_addr(netif, i));
266 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) {
267 replies |= REPLY_HOST_PTR_V6;
268 /* Mark which addresses where requested */
269 if (reverse_v6_reply) {
270 *reverse_v6_reply |= (1 << i);
271 }
272 }
273 }
274 }
275#endif
276#if LWIP_IPV4
277 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
278 res = mdns_build_reverse_v4_domain(&mydomain, netif_ip4_addr(netif));
279 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) {
280 replies |= REPLY_HOST_PTR_V4;
281 }
282 }
283#endif
284 }
285
286 res = mdns_build_host_domain(&mydomain, NETIF_TO_HOST(netif));
287 /* Handle requests for our hostname */
288 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) {
289 /* TODO return NSEC if unsupported protocol requested */
290#if LWIP_IPV4
291 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))
292 && (rr->type == DNS_RRTYPE_A || rr->type == DNS_RRTYPE_ANY)) {
293 replies |= REPLY_HOST_A;
294 }
295#endif
296#if LWIP_IPV6
297 if (rr->type == DNS_RRTYPE_AAAA || rr->type == DNS_RRTYPE_ANY) {
298 replies |= REPLY_HOST_AAAA;
299 }
300#endif
301 }
302
303 return replies;
304}
305
312static int
313check_service(struct mdns_service *service, struct mdns_rr_info *rr)
314{
315 err_t res;
316 int replies = 0;
317 struct mdns_domain mydomain;
318
319 if (rr->klass != DNS_RRCLASS_IN && rr->klass != DNS_RRCLASS_ANY) {
320 /* Invalid class */
321 return 0;
322 }
323
324 res = mdns_build_dnssd_domain(&mydomain);
325 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain) &&
326 (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY)) {
327 /* Request for all service types */
328 replies |= REPLY_SERVICE_TYPE_PTR;
329 }
330
331 res = mdns_build_service_domain(&mydomain, service, 0);
332 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain) &&
333 (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY)) {
334 /* Request for the instance of my service */
335 replies |= REPLY_SERVICE_NAME_PTR;
336 }
337
338 res = mdns_build_service_domain(&mydomain, service, 1);
339 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) {
340 /* Request for info about my service */
341 if (rr->type == DNS_RRTYPE_SRV || rr->type == DNS_RRTYPE_ANY) {
342 replies |= REPLY_SERVICE_SRV;
343 }
344 if (rr->type == DNS_RRTYPE_TXT || rr->type == DNS_RRTYPE_ANY) {
345 replies |= REPLY_SERVICE_TXT;
346 }
347 }
348
349 return replies;
350}
351
352#if LWIP_MDNS_SEARCH
359static int
360check_request(struct mdns_request *request, struct mdns_rr_info *rr)
361{
362 err_t res;
363 int replies = 0;
364 struct mdns_domain mydomain;
365
366 if (rr->klass != DNS_RRCLASS_IN && rr->klass != DNS_RRCLASS_ANY) {
367 /* Invalid class */
368 return 0;
369 }
370
371 res = mdns_build_request_domain(&mydomain, request, 0);
372 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain) &&
373 (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY)) {
374 /* Request for the instance of my service */
375 replies |= REPLY_SERVICE_TYPE_PTR;
376 }
377 res = mdns_build_request_domain(&mydomain, request, 1);
378 if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) {
379 /* Request for info about my service */
380 if (rr->type == DNS_RRTYPE_SRV || rr->type == DNS_RRTYPE_ANY) {
381 replies |= REPLY_SERVICE_SRV;
382 }
383 if (rr->type == DNS_RRTYPE_TXT || rr->type == DNS_RRTYPE_ANY) {
384 replies |= REPLY_SERVICE_TXT;
385 }
386 }
387 return replies;
388}
389#endif
390
399static err_t
400mdns_read_rr_info(struct mdns_packet *pkt, struct mdns_rr_info *info)
401{
402 u16_t field16, copied;
403 pkt->parse_offset = mdns_readname(pkt->pbuf, pkt->parse_offset, &info->domain);
404 if (pkt->parse_offset == MDNS_READNAME_ERROR) {
405 return ERR_VAL;
406 }
407
408 copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset);
409 if (copied != sizeof(field16)) {
410 return ERR_VAL;
411 }
412 pkt->parse_offset += copied;
413 info->type = lwip_ntohs(field16);
414
415 copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset);
416 if (copied != sizeof(field16)) {
417 return ERR_VAL;
418 }
419 pkt->parse_offset += copied;
420 info->klass = lwip_ntohs(field16);
421
422 return ERR_OK;
423}
424
433static err_t
434mdns_read_question(struct mdns_packet *pkt, struct mdns_question *question)
435{
436 /* Safety check */
437 if (pkt->pbuf->tot_len < pkt->parse_offset) {
438 return ERR_VAL;
439 }
440
441 if (pkt->questions_left) {
442 err_t res;
443 pkt->questions_left--;
444
445 memset(question, 0, sizeof(struct mdns_question));
446 res = mdns_read_rr_info(pkt, &question->info);
447 if (res != ERR_OK) {
448 return res;
449 }
450
451 /* Extract unicast flag from class field */
452 question->unicast = question->info.klass & 0x8000;
453 question->info.klass &= 0x7FFF;
454
455 return ERR_OK;
456 }
457 return ERR_VAL;
458}
459
469static err_t
470mdns_read_answer(struct mdns_packet *pkt, struct mdns_answer *answer, u16_t *num_left)
471{
472 /* Read questions first */
473 if (pkt->questions_left) {
474 return ERR_VAL;
475 }
476
477 /* Safety check */
478 if (pkt->pbuf->tot_len < pkt->parse_offset) {
479 return ERR_VAL;
480 }
481
482 if (*num_left) {
483 u16_t copied, field16;
484 u32_t ttl;
485 err_t res;
486 (*num_left)--;
487
488 memset(answer, 0, sizeof(struct mdns_answer));
489 res = mdns_read_rr_info(pkt, &answer->info);
490 if (res != ERR_OK) {
491 return res;
492 }
493
494 /* Extract cache_flush flag from class field */
495 answer->cache_flush = answer->info.klass & 0x8000;
496 answer->info.klass &= 0x7FFF;
497
498 copied = pbuf_copy_partial(pkt->pbuf, &ttl, sizeof(ttl), pkt->parse_offset);
499 if (copied != sizeof(ttl)) {
500 return ERR_VAL;
501 }
502 pkt->parse_offset += copied;
503 answer->ttl = lwip_ntohl(ttl);
504
505 copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset);
506 if (copied != sizeof(field16)) {
507 return ERR_VAL;
508 }
509 pkt->parse_offset += copied;
510 answer->rd_length = lwip_ntohs(field16);
511
512 answer->rd_offset = pkt->parse_offset;
513 pkt->parse_offset += answer->rd_length;
514
515 return ERR_OK;
516 }
517 return ERR_VAL;
518}
519
525static void
526mdns_announce(struct netif *netif, const ip_addr_t *destination)
527{
528 struct mdns_outmsg announce;
529 int i;
530 struct mdns_host *mdns = NETIF_TO_HOST(netif);
531
532 memset(&announce, 0, sizeof(announce));
533 announce.cache_flush = 1;
534#if LWIP_IPV4
535 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
536 announce.host_replies = REPLY_HOST_A | REPLY_HOST_PTR_V4;
537 }
538#endif
539#if LWIP_IPV6
540 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
541 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
542 announce.host_replies |= REPLY_HOST_AAAA | REPLY_HOST_PTR_V6;
543 announce.host_reverse_v6_replies |= (1 << i);
544 }
545 }
546#endif
547
548 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
549 struct mdns_service *serv = mdns->services[i];
550 if (serv) {
551 announce.serv_replies[i] = REPLY_SERVICE_TYPE_PTR | REPLY_SERVICE_NAME_PTR |
552 REPLY_SERVICE_SRV | REPLY_SERVICE_TXT;
553 }
554 }
555
556 announce.dest_port = LWIP_IANA_PORT_MDNS;
557 SMEMCPY(&announce.dest_addr, destination, sizeof(announce.dest_addr));
558 announce.flags = DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE;
559 mdns_send_outpacket(&announce, netif);
560}
561
574static err_t
575mdns_lexicographical_comparison(struct mdns_packet *pkt_a, struct mdns_packet *pkt_b,
576 struct mdns_answer *ans_a, struct mdns_answer *ans_b,
577 u8_t *result)
578{
579 int len, i;
580 u8_t a_rd, b_rd;
581 u16_t res;
582 struct mdns_domain domain_a, domain_b;
583
584 /* Compare classes */
585 if (ans_a->info.klass != ans_b->info.klass) {
586 if (ans_a->info.klass > ans_b->info.klass) {
587 *result = MDNS_LEXICOGRAPHICAL_LATER;
588 return ERR_OK;
589 }
590 else {
591 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
592 return ERR_OK;
593 }
594 }
595 /* Compare types */
596 if (ans_a->info.type != ans_b->info.type) {
597 if (ans_a->info.type > ans_b->info.type) {
598 *result = MDNS_LEXICOGRAPHICAL_LATER;
599 return ERR_OK;
600 }
601 else {
602 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
603 return ERR_OK;
604 }
605 }
606
607 /* Compare rr data section
608 * Name compression:
609 * We have 4 different RR types in our authoritative section (if IPv4 and IPv6 is enabled): A,
610 * AAAA, SRV and TXT. Only one of the 4 can be subject to name compression in the rdata, the SRV
611 * record. As stated in the RFC6762 section 8.2: the names must be uncompressed before comparison.
612 * We only need to take the SRV record into account. It's the only one that in a comparison with
613 * compressed data could lead to rdata comparison. Others will already stop after the type
614 * comparison. So if we get passed the class and type comparison we need to check if the
615 * comparison contains an SRV record. If so, we need a different comparison method.
616 */
617
618 /* The answers do not contain an SRV record */
619 if (ans_a->info.type != DNS_RRTYPE_SRV && ans_b->info.type != DNS_RRTYPE_SRV) {
620 len = LWIP_MIN(ans_a->rd_length, ans_b->rd_length);
621 for (i = 0; i < len; i++) {
622 a_rd = pbuf_get_at(pkt_a->pbuf, (u16_t)(ans_a->rd_offset + i));
623 b_rd = pbuf_get_at(pkt_b->pbuf, (u16_t)(ans_b->rd_offset + i));
624 if (a_rd != b_rd) {
625 if (a_rd > b_rd) {
626 *result = MDNS_LEXICOGRAPHICAL_LATER;
627 return ERR_OK;
628 }
629 else {
630 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
631 return ERR_OK;
632 }
633 }
634 }
635 /* If the overlapping data is the same, compare the length */
636 if (ans_a->rd_length != ans_b->rd_length) {
637 if (ans_a->rd_length > ans_b->rd_length) {
638 *result = MDNS_LEXICOGRAPHICAL_LATER;
639 return ERR_OK;
640 }
641 else {
642 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
643 return ERR_OK;
644 }
645 }
646 }
647 /* Because the types are guaranteed equal here, we know they are both SRV RRs */
648 else {
649 /* We will first compare the priority, weight and port */
650 for (i = 0; i < 6; i++) {
651 a_rd = pbuf_get_at(pkt_a->pbuf, (u16_t)(ans_a->rd_offset + i));
652 b_rd = pbuf_get_at(pkt_b->pbuf, (u16_t)(ans_b->rd_offset + i));
653 if (a_rd != b_rd) {
654 if (a_rd > b_rd) {
655 *result = MDNS_LEXICOGRAPHICAL_LATER;
656 return ERR_OK;
657 }
658 else {
659 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
660 return ERR_OK;
661 }
662 }
663 }
664 /* Decompress names if compressed and save in domain_a or domain_b */
665 res = mdns_readname(pkt_a->pbuf, ans_a->rd_offset + 6, &domain_a);
666 if (res == MDNS_READNAME_ERROR) {
667 return ERR_VAL;
668 }
669 res = mdns_readname(pkt_b->pbuf, ans_b->rd_offset + 6, &domain_b);
670 if (res == MDNS_READNAME_ERROR) {
671 return ERR_VAL;
672 }
673 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: domain a: len = %d, name = ", domain_a.name[0]));
674 mdns_domain_debug_print(&domain_a);
675 LWIP_DEBUGF(MDNS_DEBUG, ("\n"));
676 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: domain b: len = %d, name = ", domain_b.name[0]));
677 mdns_domain_debug_print(&domain_b);
678 LWIP_DEBUGF(MDNS_DEBUG, ("\n"));
679 /* Compare names pairwise */
680 len = LWIP_MIN(domain_a.length, domain_b.length);
681 for (i = 0; i < len; i++) {
682 if (domain_a.name[i] != domain_b.name[i]) {
683 if (domain_a.name[i] > domain_b.name[i]) {
684 *result = MDNS_LEXICOGRAPHICAL_LATER;
685 return ERR_OK;
686 }
687 else {
688 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
689 return ERR_OK;
690 }
691 }
692 }
693 /* If the overlapping data is the same, compare the length */
694 if (domain_a.length != domain_b.length) {
695 if (domain_a.length > domain_b.length) {
696 *result = MDNS_LEXICOGRAPHICAL_LATER;
697 return ERR_OK;
698 }
699 else {
700 *result = MDNS_LEXICOGRAPHICAL_EARLIER;
701 return ERR_OK;
702 }
703 }
704 }
705 /* They are exactly the same */
706 *result = MDNS_LEXICOGRAPHICAL_EQUAL;
707 return ERR_OK;
708}
709
715static void
716mdns_init_answer_list(struct mdns_answer_list *a_list)
717{
718 int i;
719 a_list->size = 0;
720 for(i = 0; i < MDNS_PROBE_TIEBREAK_MAX_ANSWERS; i++) {
721 a_list->offset[i] = 0;
722 }
723}
724
736static err_t
737mdns_push_answer_to_sorted_list(struct mdns_answer_list *a_list,
738 struct mdns_packet *pkt,
739 u16_t new_offset,
740 struct mdns_answer *new_answer)
741{
742 int i;
743 struct mdns_answer a;
744 int pos = a_list->size;
745 err_t res = ERR_OK;
746 u8_t result;
747 u16_t num_left = pkt->authoritative;
748 u16_t parse_offset = pkt->parse_offset;
749
750 /* Check size */
751 if ((a_list->size + 1) >= MDNS_PROBE_TIEBREAK_MAX_ANSWERS) {
752 return ERR_MEM;
753 }
754 /* Search location and open a location */
755 for (i = 0; i < a_list->size; i++) {
756 /* Read answers already in the list from pkt */
757 pkt->parse_offset = a_list->offset[i];
758 res = mdns_read_answer(pkt, &a, &num_left);
759 if (res != ERR_OK) {
760 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n"));
761 return res;
762 }
763 /* Compare them with the new answer to find it's place */
764 res = mdns_lexicographical_comparison(pkt, pkt, &a, new_answer, &result);
765 if (res != ERR_OK) {
766 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to compare answers, skipping probe packet\n"));
767 return res;
768 }
769 if (result == MDNS_LEXICOGRAPHICAL_LATER) {
770 int j;
771 pos = i;
772 for (j = (a_list->size + 1); j>i; j--) {
773 a_list->offset[j] = a_list->offset[j-1];
774 }
775 break;
776 }
777 }
778 /* Insert new value */
779 a_list->offset[pos] = new_offset;
780 a_list->size++;
781 /* Reset parse offset for further evaluation */
782 pkt->parse_offset = parse_offset;
783 return res;
784}
785
793static u8_t
794mdns_is_answer_to_question(struct mdns_question *q, struct mdns_answer *a)
795{
796 if (q->info.type == DNS_RRTYPE_ANY || q->info.type == a->info.type) {
797 /* The types match or question type is any */
798 if (mdns_domain_eq(&q->info.domain, &a->info.domain)) {
799 return 1;
800 }
801 }
802 return 0;
803}
804
811static void
812mdns_convert_out_to_in_pkt(struct mdns_packet *inpkt, struct mdns_outpacket *outpkt)
813{
814 inpkt->pbuf = outpkt->pbuf;
815 inpkt->parse_offset = SIZEOF_DNS_HDR;
816
817 inpkt->questions = inpkt->questions_left = outpkt->questions;
818 inpkt->answers = inpkt->answers_left = outpkt->answers;
819 inpkt->authoritative = inpkt->authoritative_left = outpkt->authoritative;
820 inpkt->additional = inpkt->additional_left = outpkt->additional;
821}
822
829static void
830mdns_debug_print_answer(struct mdns_packet *pkt, struct mdns_answer *a)
831{
832#ifdef LWIP_DEBUG
833 /* Arbitrarily chose 200 -> don't want to see more then that. It's only
834 * for debug so not that important. */
835 char string[200];
836 int i;
837 int pos;
838
839 pos = snprintf(string, sizeof(string), "Type = %2d, class = %1d, rdata = ", a->info.type, a->info.klass);
840 for (i = 0; ((i < a->rd_length) && ((pos + 4*i) < 195)) ; i++) {
841 snprintf(&string[pos + 4*i], 5, "%3d ", (u8_t)pbuf_get_at(pkt->pbuf, (u16_t)(a->rd_offset + i)));
842 }
843 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: %s\n", string));
844#else
845 LWIP_UNUSED_ARG(pkt);
847#endif
848}
849
856static void
857mdns_handle_probe_tiebreaking(struct netif *netif, struct mdns_packet *pkt)
858{
859 struct mdns_question pkt_q, my_q, q_dummy;
860 struct mdns_answer pkt_a, my_a;
861 struct mdns_outmsg myprobe_msg;
862 struct mdns_outpacket myprobe_outpkt;
863 struct mdns_packet myprobe_inpkt;
864 struct mdns_answer_list pkt_a_list, my_a_list;
865 u16_t save_parse_offset;
866 u16_t pkt_parse_offset, myprobe_parse_offset, myprobe_questions_left;
867 err_t res;
869 int min, i;
870
871 /* Generate probe packet to perform comparison.
872 * This is a lot of calculation at this stage without any pre calculation
873 * needed. It should be evaluated if this is the best approach.
874 */
875 mdns_define_probe_rrs_to_send(netif, &myprobe_msg);
876 memset(&myprobe_outpkt, 0, sizeof(myprobe_outpkt));
877 memset(&myprobe_inpkt, 0, sizeof(myprobe_inpkt));
878 res = mdns_create_outpacket(netif, &myprobe_msg, &myprobe_outpkt);
879 if (res != ERR_OK) {
880 goto cleanup;
881 }
882 mdns_convert_out_to_in_pkt(&myprobe_inpkt, &myprobe_outpkt);
883
884 /* Loop over all our probes to search for matches */
885 while (myprobe_inpkt.questions_left) {
886 /* Read one of our probe questions to check if pkt contains same question */
887 res = mdns_read_question(&myprobe_inpkt, &my_q);
888 if (res != ERR_OK) {
889 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping probe packet\n"));
890 goto cleanup;
891 }
892 /* Remember parse offsets so we can restart the search for the next question */
893 pkt_parse_offset = pkt->parse_offset;
894 myprobe_parse_offset = myprobe_inpkt.parse_offset;
895 /* Remember questions left of our probe packet */
896 myprobe_questions_left = myprobe_inpkt.questions_left;
897 /* Reset match flag */
898 match = 0;
899 /* Search for a matching probe in the incoming packet */
900 while (pkt->questions_left) {
901 /* Read probe questions one by one */
902 res = mdns_read_question(pkt, &pkt_q);
903 if (res != ERR_OK) {
904 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping probe packet\n"));
905 goto cleanup;
906 }
907 /* Stop evaluating if the class is not supported */
908 if (pkt_q.info.klass != DNS_RRCLASS_IN && pkt_q.info.klass != DNS_RRCLASS_ANY) {
909 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: question class not supported, skipping probe packet\n"));
910 goto cleanup;
911 }
912 /* We probe for type any, so we do not have to compare types */
913 /* Compare if we are probing for the same domain */
914 if (mdns_domain_eq(&pkt_q.info.domain, &my_q.info.domain)) {
915 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: We are probing for the same rr\n"));
916 match = 1;
917 break;
918 }
919 }
920 /* When matched start evaluating the authoritative section */
921 if (match) {
922 /* Ignore all following questions to be able to get to the authoritative answers */
923 while (pkt->questions_left) {
924 res = mdns_read_question(pkt, &q_dummy);
925 if (res != ERR_OK) {
926 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping probe packet\n"));
927 goto cleanup;
928 }
929 }
930 while (myprobe_inpkt.questions_left) {
931 res = mdns_read_question(&myprobe_inpkt, &q_dummy);
932 if (res != ERR_OK) {
933 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping probe packet\n"));
934 goto cleanup;
935 }
936 }
937
938 /* Extract and sort our authoritative answers that answer our question */
939 mdns_init_answer_list(&my_a_list);
940 while(myprobe_inpkt.authoritative_left) {
941 save_parse_offset = myprobe_inpkt.parse_offset;
942 res = mdns_read_answer(&myprobe_inpkt, &my_a, &myprobe_inpkt.authoritative_left);
943 if (res != ERR_OK) {
944 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n"));
945 goto cleanup;
946 }
947 if (mdns_is_answer_to_question(&my_q, &my_a)) {
948 /* Add to list */
949 res = mdns_push_answer_to_sorted_list(&my_a_list, &myprobe_inpkt, save_parse_offset, &my_a);
950 if (res != ERR_OK) {
951 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to add answer, skipping probe packet\n"));
952 goto cleanup;
953 }
954 }
955 }
956 /* Extract and sort the packets authoritative answers that answer the
957 question */
958 mdns_init_answer_list(&pkt_a_list);
959 while(pkt->authoritative_left) {
960 save_parse_offset = pkt->parse_offset;
961 res = mdns_read_answer(pkt, &pkt_a, &pkt->authoritative_left);
962 if (res != ERR_OK) {
963 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n"));
964 goto cleanup;
965 }
966 if (mdns_is_answer_to_question(&my_q, &pkt_a)) {
967 /* Add to list */
968 res = mdns_push_answer_to_sorted_list(&pkt_a_list, pkt, save_parse_offset, &pkt_a);
969 if (res != ERR_OK) {
970 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to add answer, skipping probe packet\n"));
971 goto cleanup;
972 }
973 }
974 }
975
976 /* Reinitiate authoritative left */
977 myprobe_inpkt.authoritative_left = myprobe_inpkt.authoritative;
978 pkt->authoritative_left = pkt->authoritative;
979
980 /* Compare pairwise.
981 * - lexicographically later? -> we win, ignore the packet.
982 * - lexicographically earlier? -> we loose, wait one second and retry.
983 * - lexicographically equal? -> no conflict, check other probes.
984 */
985 min = LWIP_MIN(my_a_list.size, pkt_a_list.size);
986 for (i = 0; i < min; i++) {
987 /* Get answer of our own list */
988 myprobe_inpkt.parse_offset = my_a_list.offset[i];
989 res = mdns_read_answer(&myprobe_inpkt, &my_a, &myprobe_inpkt.authoritative_left);
990 if (res != ERR_OK) {
991 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n"));
992 goto cleanup;
993 }
994 /* Get answer of the packets list */
995 pkt->parse_offset = pkt_a_list.offset[i];
996 res = mdns_read_answer(pkt, &pkt_a, &pkt->authoritative_left);
997 if (res != ERR_OK) {
998 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping probe packet\n"));
999 goto cleanup;
1000 }
1001 /* Print both answers for debugging */
1002 mdns_debug_print_answer(pkt, &pkt_a);
1003 mdns_debug_print_answer(&myprobe_inpkt, &my_a);
1004 /* Define the winner */
1005 res = mdns_lexicographical_comparison(&myprobe_inpkt, pkt, &my_a, &pkt_a, &result);
1006 if (res != ERR_OK) {
1007 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to compare answers, skipping probe packet\n"));
1008 goto cleanup;
1009 }
1010 if (result == MDNS_LEXICOGRAPHICAL_LATER) {
1011 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: we win, we are lexicographically later\n"));
1012 goto cleanup;
1013 }
1014 else if (result == MDNS_LEXICOGRAPHICAL_EARLIER) {
1015 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: we loose, we are lexicographically earlier. 1s timeout started\n"));
1016 /* Increase the number of conflicts occurred */
1017 mdns_conflict_save_time(netif);
1018 /* then restart with 1s delay */
1019 mdns_resp_restart_delay(netif, MDNS_PROBE_TIEBREAK_CONFLICT_DELAY_MS);
1020 goto cleanup;
1021 }
1022 else {
1023 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: lexicographically equal, so no conclusion\n"));
1024 }
1025 }
1026 /* All compared RR were equal, otherwise we would not be here
1027 * -> check if one of both have more answers to the question */
1028 if (my_a_list.size != pkt_a_list.size) {
1029 if (my_a_list.size > pkt_a_list.size) {
1030 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: we win, we have more records answering the probe\n"));
1031 goto cleanup;
1032 }
1033 else {
1034 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: we loose, we have less records. 1s timeout started\n"));
1035 /* Increase the number of conflicts occurred */
1036 mdns_conflict_save_time(netif);
1037 /* then restart with 1s delay */
1038 mdns_resp_restart_delay(netif, MDNS_PROBE_TIEBREAK_CONFLICT_DELAY_MS);
1039 goto cleanup;
1040 }
1041 }
1042 else {
1043 /* There is no conflict on this probe, both devices have the same data
1044 * in the authoritative section. We should still check the other probes
1045 * for conflicts. */
1046 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: no conflict, all records answering the probe are equal\n"));
1047 }
1048 }
1049 /* Evaluate other probes if any. */
1050 /* Reinitiate parse offsets */
1051 pkt->parse_offset = pkt_parse_offset;
1052 myprobe_inpkt.parse_offset = myprobe_parse_offset;
1053 /* Reinitiate questions_left and authoritative_left */
1054 pkt->questions_left = pkt->questions;
1055 pkt->authoritative_left = pkt->authoritative;
1056 myprobe_inpkt.questions_left = myprobe_questions_left;
1057 myprobe_inpkt.authoritative_left = myprobe_inpkt.authoritative;
1058 }
1059
1060cleanup:
1061 if (myprobe_inpkt.pbuf != NULL) {
1062 pbuf_free(myprobe_inpkt.pbuf);
1063 }
1064}
1065
1074static err_t
1075mdns_parse_pkt_questions(struct netif *netif, struct mdns_packet *pkt,
1076 struct mdns_outmsg *reply)
1077{
1078 struct mdns_host *mdns = NETIF_TO_HOST(netif);
1079 struct mdns_service *service;
1080 int i;
1081 err_t res;
1082
1083 while (pkt->questions_left) {
1084 struct mdns_question q;
1085
1086 res = mdns_read_question(pkt, &q);
1087 if (res != ERR_OK) {
1088 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping query packet\n"));
1089 return res;
1090 }
1091
1092 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Query for domain "));
1093 mdns_domain_debug_print(&q.info.domain);
1094 LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", q.info.type, q.info.klass));
1095
1096 if (q.unicast) {
1097 /* Reply unicast if it is requested in the question */
1098 reply->unicast_reply_requested = 1;
1099 }
1100
1101 reply->host_replies |= check_host(netif, &q.info, &reply->host_reverse_v6_replies);
1102
1103 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1104 service = mdns->services[i];
1105 if (!service) {
1106 continue;
1107 }
1108 reply->serv_replies[i] |= check_service(service, &q.info);
1109 }
1110 }
1111
1112 return ERR_OK;
1113}
1114
1123static err_t
1124mdns_parse_pkt_known_answers(struct netif *netif, struct mdns_packet *pkt,
1125 struct mdns_outmsg *reply)
1126{
1127 struct mdns_host *mdns = NETIF_TO_HOST(netif);
1128 struct mdns_service *service;
1129 int i;
1130 err_t res;
1131
1132 while (pkt->answers_left) {
1133 struct mdns_answer ans;
1134 u8_t rev_v6;
1135 int match;
1136 u32_t rr_ttl = MDNS_TTL_120;
1137
1138 res = mdns_read_answer(pkt, &ans, &pkt->answers_left);
1139 if (res != ERR_OK) {
1140 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping query packet\n"));
1141 return res;
1142 }
1143
1144 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Known answer for domain "));
1145 mdns_domain_debug_print(&ans.info.domain);
1146 LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass));
1147
1148
1149 if (ans.info.type == DNS_RRTYPE_ANY || ans.info.klass == DNS_RRCLASS_ANY) {
1150 /* Skip known answers for ANY type & class */
1151 continue;
1152 }
1153
1154 rev_v6 = 0;
1155 match = reply->host_replies & check_host(netif, &ans.info, &rev_v6);
1156 if (match && (ans.ttl > (rr_ttl / 2))) {
1157 /* The RR in the known answer matches an RR we are planning to send,
1158 * and the TTL is less than half gone.
1159 * If the payload matches we should not send that answer.
1160 */
1161 if (ans.info.type == DNS_RRTYPE_PTR) {
1162 /* Read domain and compare */
1163 struct mdns_domain known_ans, my_ans;
1164 u16_t len;
1165 len = mdns_readname(pkt->pbuf, ans.rd_offset, &known_ans);
1166 res = mdns_build_host_domain(&my_ans, mdns);
1167 if (len != MDNS_READNAME_ERROR && res == ERR_OK && mdns_domain_eq(&known_ans, &my_ans)) {
1168#if LWIP_IPV4
1169 if (match & REPLY_HOST_PTR_V4) {
1170 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: v4 PTR\n"));
1171 reply->host_replies &= ~REPLY_HOST_PTR_V4;
1172 }
1173#endif
1174#if LWIP_IPV6
1175 if (match & REPLY_HOST_PTR_V6) {
1176 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: v6 PTR\n"));
1177 reply->host_reverse_v6_replies &= ~rev_v6;
1178 if (reply->host_reverse_v6_replies == 0) {
1179 reply->host_replies &= ~REPLY_HOST_PTR_V6;
1180 }
1181 }
1182#endif
1183 }
1184 } else if (match & REPLY_HOST_A) {
1185#if LWIP_IPV4
1186 if (ans.rd_length == sizeof(ip4_addr_t) &&
1187 pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip4_addr(netif), ans.rd_length) == 0) {
1188 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: A\n"));
1189 reply->host_replies &= ~REPLY_HOST_A;
1190 }
1191#endif
1192 } else if (match & REPLY_HOST_AAAA) {
1193#if LWIP_IPV6
1194 if (ans.rd_length == sizeof(ip6_addr_p_t) &&
1195 /* TODO this clears all AAAA responses if first addr is set as known */
1196 pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip6_addr(netif, 0), ans.rd_length) == 0) {
1197 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: AAAA\n"));
1198 reply->host_replies &= ~REPLY_HOST_AAAA;
1199 }
1200#endif
1201 }
1202 }
1203
1204 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1205 service = mdns->services[i];
1206 if (!service) {
1207 continue;
1208 }
1209 match = reply->serv_replies[i] & check_service(service, &ans.info);
1210 if (match & REPLY_SERVICE_TYPE_PTR) {
1211 rr_ttl = MDNS_TTL_4500;
1212 }
1213 if (match && (ans.ttl > (rr_ttl / 2))) {
1214 /* The RR in the known answer matches an RR we are planning to send,
1215 * and the TTL is less than half gone.
1216 * If the payload matches we should not send that answer.
1217 */
1218 if (ans.info.type == DNS_RRTYPE_PTR) {
1219 /* Read domain and compare */
1220 struct mdns_domain known_ans, my_ans;
1221 u16_t len;
1222 len = mdns_readname(pkt->pbuf, ans.rd_offset, &known_ans);
1223 if (len != MDNS_READNAME_ERROR) {
1224 if (match & REPLY_SERVICE_TYPE_PTR) {
1225 res = mdns_build_service_domain(&my_ans, service, 0);
1226 if (res == ERR_OK && mdns_domain_eq(&known_ans, &my_ans)) {
1227 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: service type PTR\n"));
1228 reply->serv_replies[i] &= ~REPLY_SERVICE_TYPE_PTR;
1229 }
1230 }
1231 if (match & REPLY_SERVICE_NAME_PTR) {
1232 res = mdns_build_service_domain(&my_ans, service, 1);
1233 if (res == ERR_OK && mdns_domain_eq(&known_ans, &my_ans)) {
1234 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: service name PTR\n"));
1235 reply->serv_replies[i] &= ~REPLY_SERVICE_NAME_PTR;
1236 }
1237 }
1238 }
1239 } else if (match & REPLY_SERVICE_SRV) {
1240 /* Read and compare to my SRV record */
1241 u16_t field16, len, read_pos;
1242 struct mdns_domain known_ans, my_ans;
1243 read_pos = ans.rd_offset;
1244 do {
1245 /* Check priority field */
1246 len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
1247 if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_PRIORITY) {
1248 break;
1249 }
1250 read_pos += len;
1251 /* Check weight field */
1252 len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
1253 if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_WEIGHT) {
1254 break;
1255 }
1256 read_pos += len;
1257 /* Check port field */
1258 len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
1259 if (len != sizeof(field16) || lwip_ntohs(field16) != service->port) {
1260 break;
1261 }
1262 read_pos += len;
1263 /* Check host field */
1264 len = mdns_readname(pkt->pbuf, read_pos, &known_ans);
1265 mdns_build_host_domain(&my_ans, mdns);
1266 if (len == MDNS_READNAME_ERROR || !mdns_domain_eq(&known_ans, &my_ans)) {
1267 break;
1268 }
1269 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: SRV\n"));
1270 reply->serv_replies[i] &= ~REPLY_SERVICE_SRV;
1271 } while (0);
1272 } else if (match & REPLY_SERVICE_TXT) {
1273 mdns_prepare_txtdata(service);
1274 if (service->txtdata.length == ans.rd_length &&
1275 pbuf_memcmp(pkt->pbuf, ans.rd_offset, service->txtdata.name, ans.rd_length) == 0) {
1276 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: TXT\n"));
1277 reply->serv_replies[i] &= ~REPLY_SERVICE_TXT;
1278 }
1279 }
1280 }
1281 }
1282 }
1283
1284 return ERR_OK;
1285}
1286
1296static err_t
1297mdns_parse_pkt_authoritative_answers(struct netif *netif, struct mdns_packet *pkt,
1298 struct mdns_outmsg *reply)
1299{
1300 struct mdns_host *mdns = NETIF_TO_HOST(netif);
1301 struct mdns_service *service;
1302 int i;
1303 err_t res;
1304
1305 while (pkt->authoritative_left) {
1306 struct mdns_answer ans;
1307 u8_t rev_v6;
1308 int match;
1309
1310 res = mdns_read_answer(pkt, &ans, &pkt->authoritative_left);
1311 if (res != ERR_OK) {
1312 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping query packet\n"));
1313 return res;
1314 }
1315
1316 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Authoritative answer for domain "));
1317 mdns_domain_debug_print(&ans.info.domain);
1318 LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass));
1319
1320
1321 if (ans.info.type == DNS_RRTYPE_ANY || ans.info.klass == DNS_RRCLASS_ANY) {
1322 /* Skip known answers for ANY type & class */
1323 continue;
1324 }
1325
1326 rev_v6 = 0;
1327 match = reply->host_replies & check_host(netif, &ans.info, &rev_v6);
1328 if (match) {
1329 reply->probe_query_recv = 1;
1330 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe for own host info received\n"));
1331 }
1332
1333 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1334 service = mdns->services[i];
1335 if (!service) {
1336 continue;
1337 }
1338 match = reply->serv_replies[i] & check_service(service, &ans.info);
1339
1340 if (match) {
1341 reply->probe_query_recv = 1;
1342 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe for own service info received\n"));
1343 }
1344 }
1345 }
1346
1347 return ERR_OK;
1348}
1349
1356static void
1357mdns_add_msg_to_delayed(struct mdns_outmsg *dest, struct mdns_outmsg *src)
1358{
1359 int i;
1360
1361 dest->host_questions |= src->host_questions;
1362 dest->host_replies |= src->host_replies;
1363 dest->host_reverse_v6_replies |= src->host_reverse_v6_replies;
1364 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1365 dest->serv_questions[i] |= src->serv_questions[i];
1366 dest->serv_replies[i] |= src->serv_replies[i];
1367 }
1368
1369 dest->flags = src->flags;
1370 dest->cache_flush = src->cache_flush;
1371 dest->tx_id = src->tx_id;
1372 dest->legacy_query = src->legacy_query;
1373}
1374
1386static void
1387mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
1388{
1389 struct mdns_host *mdns = NETIF_TO_HOST(netif);
1390 struct mdns_outmsg reply;
1391 u8_t rrs_to_send;
1392 u8_t shared_answer = 0;
1393 u8_t delay_response = 1;
1394 u8_t send_unicast = 0;
1395 u8_t listen_to_QU_bit = 0;
1396 int i;
1397 err_t res;
1398
1399 if ((mdns->state == MDNS_STATE_PROBING) ||
1400 (mdns->state == MDNS_STATE_ANNOUNCE_WAIT)) {
1401 /* Probe Tiebreaking */
1402 /* Check if packet is a probe message */
1403 if ((pkt->questions > 0) && (pkt->answers == 0) &&
1404 (pkt->authoritative > 0) && (pkt->additional == 0)) {
1405 /* This should be a probe message -> call probe handler */
1406 mdns_handle_probe_tiebreaking(netif, pkt);
1407 }
1408 }
1409
1410 if ((mdns->state != MDNS_STATE_COMPLETE) &&
1411 (mdns->state != MDNS_STATE_ANNOUNCING)) {
1412 /* Don't answer questions until we've verified our domains via probing */
1413 /* @todo we should check incoming questions during probing for tiebreaking */
1414 return;
1415 }
1416
1417 memset(&reply, 0, sizeof(struct mdns_outmsg));
1418
1419 /* Parse question */
1420 res = mdns_parse_pkt_questions(netif, pkt, &reply);
1421 if (res != ERR_OK) {
1422 return;
1423 }
1424 /* Parse answers -> count as known answers because it's a question */
1425 res = mdns_parse_pkt_known_answers(netif, pkt, &reply);
1426 if (res != ERR_OK) {
1427 return;
1428 }
1429 if (pkt->next_answer) {
1430 /* Also parse known-answers from additional packets */
1431 struct mdns_packet *pkta = pkt->next_answer;
1432 while (pkta) {
1433 res = mdns_parse_pkt_known_answers(netif, pkta, &reply);
1434 if (res != ERR_OK) {
1435 return;
1436 }
1437 pkta = pkta->next_answer;
1438 }
1439 }
1440 /* Parse authoritative answers -> probing */
1441 /* If it's a probe query, we need to directly answer via unicast. */
1442 res = mdns_parse_pkt_authoritative_answers(netif, pkt, &reply);
1443 if (res != ERR_OK) {
1444 return;
1445 }
1446 /* Ignore additional answers -> do not have any need for them at the moment */
1447 if(pkt->additional) {
1449 ("MDNS: Query contains additional answers -> they are discarded\n"));
1450 }
1451
1452 /* Any replies on question? */
1453 rrs_to_send = reply.host_replies | reply.host_questions;
1454 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1455 rrs_to_send |= reply.serv_replies[i] | reply.serv_questions[i];
1456 }
1457
1458 if (!rrs_to_send) {
1459 /* This case is most common */
1460 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Nothing to answer\n"));
1461 return;
1462 }
1463
1465
1466 /* Detect if it's a legacy querier asking the question
1467 * How to detect legacy DNS query? (RFC6762 section 6.7)
1468 * - source port != 5353
1469 * - a legacy query can only contain 1 question
1470 */
1471 if (pkt->source_port != LWIP_IANA_PORT_MDNS) {
1472 if (pkt->questions == 1) {
1473 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: request from legacy querier\n"));
1474 reply.legacy_query = 1;
1475 reply.tx_id = pkt->tx_id;
1476 reply.cache_flush = 0;
1477 }
1478 else {
1479 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: ignore query if (src UDP port != 5353) && (!= legacy query)\n"));
1480 return;
1481 }
1482 }
1483 else {
1484 reply.cache_flush = 1;
1485 }
1486
1487 /* Delaying response. (RFC6762 section 6)
1488 * Always delay the response, unicast or multicast, except when:
1489 * - Answering to a single question with a unique answer (not a probe).
1490 * - Answering to a probe query via unicast.
1491 * - Answering to a probe query via multicast if not multicasted within 250ms.
1492 *
1493 * unique answer? -> not if it includes service type or name ptr's
1494 */
1495 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1496 shared_answer |= (reply.serv_replies[i] &
1497 (REPLY_SERVICE_TYPE_PTR | REPLY_SERVICE_NAME_PTR));
1498 }
1499 if ( ((pkt->questions == 1) && (!shared_answer) && !reply.probe_query_recv)
1500 || (reply.probe_query_recv && reply.unicast_reply_requested)) {
1501 delay_response = 0;
1502 }
1503#if LWIP_IPV6
1504 if (IP_IS_V6_VAL(pkt->source_addr) && reply.probe_query_recv
1505 && !reply.unicast_reply_requested && !mdns->ipv6.multicast_probe_timeout) {
1506 delay_response = 0;
1507 }
1508#endif
1509#if LWIP_IPV4
1510 if (IP_IS_V4_VAL(pkt->source_addr) && reply.probe_query_recv
1511 && !reply.unicast_reply_requested && !mdns->ipv4.multicast_probe_timeout) {
1512 delay_response = 0;
1513 }
1514#endif
1515 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: response %s delayed\n", (delay_response ? "randomly" : "not")));
1516
1517 /* Unicast / multicast response:
1518 * Answering to (m)DNS querier via unicast response.
1519 * When:
1520 * a) Unicast reply requested && recently multicasted 1/4ttl (RFC6762 section 5.4)
1521 * b) Direct unicast query to port 5353 (RFC6762 section 5.5)
1522 * c) Reply to Legacy DNS querier (RFC6762 section 6.7)
1523 * d) A probe message is received requesting unicast (RFC6762 section 6)
1524 */
1525
1526#if LWIP_IPV6
1527 if ((IP_IS_V6_VAL(pkt->source_addr) && mdns->ipv6.multicast_timeout_25TTL)) {
1528 listen_to_QU_bit = 1;
1529 }
1530#endif
1531#if LWIP_IPV4
1532 if ((IP_IS_V4_VAL(pkt->source_addr) && mdns->ipv4.multicast_timeout_25TTL)) {
1533 listen_to_QU_bit = 1;
1534 }
1535#endif
1536 if ( (reply.unicast_reply_requested && listen_to_QU_bit)
1537 || pkt->recv_unicast
1538 || reply.legacy_query
1539 || (reply.probe_query_recv && reply.unicast_reply_requested)) {
1540 send_unicast = 1;
1541 }
1542 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: send response via %s\n", (send_unicast ? "unicast" : "multicast")));
1543
1544 /* Send out or put on waiting list */
1545 if (delay_response) {
1546 if (send_unicast) {
1547#if LWIP_IPV6
1548 /* Add answers to IPv6 waiting list if:
1549 * - it's a IPv6 incoming packet
1550 * - no message is in it yet
1551 */
1552 if (IP_IS_V6_VAL(pkt->source_addr) && !mdns->ipv6.unicast_msg_in_use) {
1553 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to unicast IPv6 waiting list\n"));
1554 SMEMCPY(&mdns->ipv6.delayed_msg_unicast.dest_addr, &pkt->source_addr, sizeof(ip_addr_t));
1555 mdns->ipv6.delayed_msg_unicast.dest_port = pkt->source_port;
1556
1557 mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_unicast, &reply);
1558
1559 mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_unicast_msg_delayed_ipv6,
1560 &mdns->ipv6.unicast_msg_in_use);
1561 }
1562#endif
1563#if LWIP_IPV4
1564 /* Add answers to IPv4 waiting list if:
1565 * - it's a IPv4 incoming packet
1566 * - no message is in it yet
1567 */
1568 if (IP_IS_V4_VAL(pkt->source_addr) && !mdns->ipv4.unicast_msg_in_use) {
1569 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to unicast IPv4 waiting list\n"));
1570 SMEMCPY(&mdns->ipv4.delayed_msg_unicast.dest_addr, &pkt->source_addr, sizeof(ip_addr_t));
1571 mdns->ipv4.delayed_msg_unicast.dest_port = pkt->source_port;
1572
1573 mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_unicast, &reply);
1574
1575 mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_unicast_msg_delayed_ipv4,
1576 &mdns->ipv4.unicast_msg_in_use);
1577 }
1578#endif
1579 }
1580 else {
1581#if LWIP_IPV6
1582 /* Add answers to IPv6 waiting list if:
1583 * - it's a IPv6 incoming packet
1584 * - the 1 second timeout is passed (RFC6762 section 6)
1585 * - and it's not a probe packet
1586 * Or if:
1587 * - it's a IPv6 incoming packet
1588 * - and it's a probe packet
1589 */
1590 if (IP_IS_V6_VAL(pkt->source_addr) && !mdns->ipv6.multicast_timeout
1591 && !reply.probe_query_recv) {
1592 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to multicast IPv6 waiting list\n"));
1593
1594 mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_multicast, &reply);
1595
1596 mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_multicast_msg_delayed_ipv6,
1597 &mdns->ipv6.multicast_msg_waiting);
1598 }
1599 else if (IP_IS_V6_VAL(pkt->source_addr) && reply.probe_query_recv) {
1600 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to probe multicast IPv6 waiting list\n"));
1601
1602 mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_multicast, &reply);
1603
1604 mdns->ipv6.multicast_msg_waiting = 1;
1605 }
1606#endif
1607#if LWIP_IPV4
1608 /* Add answers to IPv4 waiting list if:
1609 * - it's a IPv4 incoming packet
1610 * - the 1 second timeout is passed (RFC6762 section 6)
1611 * - and it's not a probe packet
1612 * Or if:
1613 * - it's a IPv4 incoming packet
1614 * - and it's a probe packet
1615 */
1616 if (IP_IS_V4_VAL(pkt->source_addr) && !mdns->ipv4.multicast_timeout
1617 && !reply.probe_query_recv) {
1618 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to multicast IPv4 waiting list\n"));
1619
1620 mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_multicast, &reply);
1621
1622 mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_multicast_msg_delayed_ipv4,
1623 &mdns->ipv4.multicast_msg_waiting);
1624 }
1625 else if (IP_IS_V4_VAL(pkt->source_addr) && reply.probe_query_recv) {
1626 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to probe multicast IPv4 waiting list\n"));
1627
1628 mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_multicast, &reply);
1629
1630 mdns->ipv4.multicast_msg_waiting = 1;
1631 }
1632#endif
1633 }
1634 }
1635 else {
1636 if (send_unicast) {
1637 /* Copy source IP/port to use when responding unicast */
1638 SMEMCPY(&reply.dest_addr, &pkt->source_addr, sizeof(ip_addr_t));
1639 reply.dest_port = pkt->source_port;
1640 /* send answer directly via unicast */
1641 res = mdns_send_outpacket(&reply, netif);
1642 if (res != ERR_OK) {
1643 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Unicast answer could not be send\n"));
1644 }
1645 else {
1646 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Unicast answer send successfully\n"));
1647 }
1648 return;
1649 }
1650 else {
1651 /* Set IP/port to use when responding multicast */
1652#if LWIP_IPV6
1653 if (IP_IS_V6_VAL(pkt->source_addr)) {
1654 if (mdns->ipv6.multicast_timeout && !reply.probe_query_recv) {
1655 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: we just multicasted, ignore question\n"));
1656 return;
1657 }
1658 SMEMCPY(&reply.dest_addr, &v6group, sizeof(ip_addr_t));
1659 }
1660#endif
1661#if LWIP_IPV4
1662 if (IP_IS_V4_VAL(pkt->source_addr)) {
1663 if (mdns->ipv4.multicast_timeout && !reply.probe_query_recv) {
1664 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: we just multicasted, ignore question\n"));
1665 return;
1666 }
1667 SMEMCPY(&reply.dest_addr, &v4group, sizeof(ip_addr_t));
1668 }
1669#endif
1670 reply.dest_port = LWIP_IANA_PORT_MDNS;
1671 /* send answer directly via multicast */
1672 res = mdns_send_outpacket(&reply, netif);
1673 if (res != ERR_OK) {
1674 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Multicast answer could not be send\n"));
1675 }
1676 else {
1677 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Multicast answer send successfully\n"));
1678#if LWIP_IPV6
1679 if (IP_IS_V6_VAL(pkt->source_addr)) {
1680 mdns_start_multicast_timeouts_ipv6(netif);
1681 }
1682#endif
1683#if LWIP_IPV4
1684 if (IP_IS_V4_VAL(pkt->source_addr)) {
1685 mdns_start_multicast_timeouts_ipv4(netif);
1686 }
1687#endif
1688 }
1689 return;
1690 }
1691 }
1692}
1693
1702static void
1703mdns_handle_tc_question(void *arg)
1704{
1705 struct mdns_packet *pkt = (struct mdns_packet *)arg;
1706 struct netif *from = netif_get_by_index(pkt->pbuf->if_idx);
1707 /* timer as elapsed, now handle this question */
1708 mdns_handle_question(pkt, from);
1709 /* remove from pending list */
1710 if (pending_tc_questions == pkt) {
1711 pending_tc_questions = pkt->next_tc_question;
1712 }
1713 else {
1714 struct mdns_packet *prev = pending_tc_questions;
1715 while (prev && prev->next_tc_question != pkt) {
1716 prev = prev->next_tc_question;
1717 }
1718 LWIP_ASSERT("pkt not found in pending_tc_questions list", prev != NULL);
1719 prev->next_tc_question = pkt->next_tc_question;
1720 }
1721 /* free linked answers and this question */
1722 while (pkt->next_answer) {
1723 struct mdns_packet *ans = pkt->next_answer;
1724 pkt->next_answer = ans->next_answer;
1725 pbuf_free(ans->pbuf);
1726 LWIP_MEMPOOL_FREE(MDNS_PKTS, ans);
1727 }
1728 pbuf_free(pkt->pbuf);
1729 LWIP_MEMPOOL_FREE(MDNS_PKTS, pkt);
1730}
1731
1738static void
1739mdns_conflict_save_time(struct netif *netif)
1740{
1741 struct mdns_host* mdns = NETIF_TO_HOST(netif);
1742 int i;
1743 u32_t diff;
1744 u8_t index2;
1745
1746 /* Increase the number of conflicts occurred */
1747 mdns->num_conflicts++;
1748 mdns->conflict_time[mdns->index] = sys_now();
1749 /* Print timestamp list */
1750 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: conflict timestamp list, insert index = %d\n", mdns->index));
1751 for(i = 0; i < MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT; i++) {
1752 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: time no. %d = %"U32_F"\n", i, mdns->conflict_time[i]));
1753 }
1754 /* Check if we had enough conflicts, minimum 15 */
1755 if (mdns->num_conflicts >= MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT) {
1756 /* Get the index to the oldest timestamp */
1757 index2 = (mdns->index + 1) % MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT;
1758 /* Compare the oldest vs newest time stamp */
1759 diff = mdns->conflict_time[mdns->index] - mdns->conflict_time[index2];
1760 /* If they are less then 10 seconds apart, initiate rate limit */
1761 if (diff < MDNS_PROBE_MAX_CONFLICTS_TIME_WINDOW) {
1762 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: probe rate limit enabled\n"));
1763 mdns->rate_limit_activated = 1;
1764 }
1765 }
1766 /* Increase index */
1767 mdns->index = (mdns->index + 1) % MDNS_PROBE_MAX_CONFLICTS_BEFORE_RATE_LIMIT;
1768}
1769
1778static void
1779mdns_probe_conflict(struct netif *netif, s8_t slot)
1780{
1781 /* Increase the number of conflicts occurred and check rate limiting */
1782 mdns_conflict_save_time(netif);
1783
1784 /* Disable currently running probe / announce timer */
1785 sys_untimeout(mdns_probe_and_announce, netif);
1786
1787 /* Inform the host on the conflict, if a callback is set */
1788 if (mdns_name_result_cb != NULL) {
1789 mdns_name_result_cb(netif, MDNS_PROBING_CONFLICT, slot);
1790 }
1791 /* TODO: rename and call restart if no mdns_name_result_cb was set? */
1792}
1793
1797#if LWIP_MDNS_SEARCH
1798static struct mdns_request *
1799mdns_lookup_request(struct mdns_rr_info *rr)
1800{
1801 int i;
1802 /* search originating request */
1803 for (i = 0; i < MDNS_MAX_REQUESTS; i++) {
1804 if ((mdns_requests[i].result_fn != NULL) &&
1805 (check_request(&mdns_requests[i], rr) != 0)) {
1806 return &mdns_requests[i];
1807 }
1808 }
1809 return NULL;
1810}
1811#endif
1812
1821static void
1822mdns_handle_response(struct mdns_packet *pkt, struct netif *netif)
1823{
1824 struct mdns_host* mdns = NETIF_TO_HOST(netif);
1825 u16_t total_answers_left;
1826#if LWIP_MDNS_SEARCH
1827 struct mdns_request *req = NULL;
1828 s8_t first = 1;
1829#endif
1830
1831 /* Ignore responses with a source port different from 5353
1832 * (LWIP_IANA_PORT_MDNS) -> RFC6762 section 6 */
1833 if (pkt->source_port != LWIP_IANA_PORT_MDNS) {
1834 return;
1835 }
1836
1837 /* Ignore all questions */
1838 while (pkt->questions_left) {
1839 struct mdns_question q;
1840 err_t res;
1841 res = mdns_read_question(pkt, &q);
1842 if (res != ERR_OK) {
1843 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping response packet\n"));
1844 return;
1845 }
1846#if LWIP_MDNS_SEARCH
1847 else {
1848 req = mdns_lookup_request(&q.info);
1849 }
1850#endif
1851 }
1852 /* We need to check all resource record sections: answers, authoritative and additional */
1853 total_answers_left = pkt->answers_left + pkt->authoritative_left + pkt->additional_left;
1854 while (total_answers_left) {
1855 struct mdns_answer ans;
1856 err_t res;
1857
1858 res = mdns_read_answer(pkt, &ans, &total_answers_left);
1859 if (res != ERR_OK) {
1860 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping response packet\n"));
1861 return;
1862 }
1863
1864 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Answer for domain "));
1865 mdns_domain_debug_print(&ans.info.domain);
1866 LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass));
1867
1868 if (ans.info.type == DNS_RRTYPE_ANY || ans.info.klass != DNS_RRCLASS_IN) {
1869 /* Skip answers for ANY type or if class != IN */
1870 continue;
1871 }
1872
1873#if LWIP_MDNS_SEARCH
1874 if (req && req->only_ptr) {
1875 /* Need to recheck that this answer match request that match previous answer */
1876 if (memcmp (req->service.name, ans.info.domain.name, req->service.length) != 0)
1877 req = NULL;
1878 }
1879 if (!req) {
1880 /* Try hard to search matching request */
1881 req = mdns_lookup_request(&ans.info);
1882 }
1883 if (req && req->result_fn) {
1884 u16_t offset;
1885 struct pbuf *p;
1886 int flags = (first ? MDNS_SEARCH_RESULT_FIRST : 0) |
1887 (!total_answers_left ? MDNS_SEARCH_RESULT_LAST : 0);
1888 if (req->only_ptr) {
1889 if (ans.info.type != DNS_RRTYPE_PTR)
1890 continue; /* Ignore non matching answer type */
1891 flags = MDNS_SEARCH_RESULT_FIRST | MDNS_SEARCH_RESULT_LAST;
1892 }
1893 p = pbuf_skip(pkt->pbuf, ans.rd_offset, &offset);
1894 if (p == NULL) {
1895 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Malformed response packet, aborting\n"));
1896 return;
1897 }
1898 if (ans.info.type == DNS_RRTYPE_PTR || ans.info.type == DNS_RRTYPE_SRV) {
1899 /* Those RR types have compressed domain name. Must uncompress here,
1900 since cannot be done without pbuf. */
1901 struct {
1902 u16_t values[3]; /* SRV: Prio, Weight, Port */
1903 struct mdns_domain dom; /* PTR & SRV: Domain (uncompressed) */
1904 } data;
1905 u16_t off = (ans.info.type == DNS_RRTYPE_SRV ? 6 : 0);
1906 u16_t len = mdns_readname(pkt->pbuf, ans.rd_offset + off, &data.dom);
1907 if (len == MDNS_READNAME_ERROR) {
1908 /* Ensure result_fn is called anyway, just copy failed domain as is */
1909 data.dom.length = ans.rd_length - off;
1910 memcpy(&data.dom, (const char *)p->payload + offset + off, data.dom.length);
1911 }
1912 /* Adjust len/off according RR type */
1913 if (ans.info.type == DNS_RRTYPE_SRV) {
1914 memcpy(&data, (const char *)p->payload + offset, 6);
1915 len = data.dom.length + 6;
1916 off = 0;
1917 } else {
1918 len = data.dom.length;
1919 off = 6;
1920 }
1921 req->result_fn(&ans, (const char *)&data + off, len, flags, req->arg);
1922 } else {
1923 /* Direct call result_fn with varpart pointing in pbuf payload */
1924 req->result_fn(&ans, (const char *)p->payload + offset, ans.rd_length, flags, req->arg);
1925 }
1926 first = 0;
1927 }
1928#endif
1929
1930 /* "Conflicting Multicast DNS responses received *before* the first probe
1931 * packet is sent MUST be silently ignored" so drop answer if we haven't
1932 * started probing yet. */
1933 if ((mdns->state == MDNS_STATE_PROBING) ||
1934 (mdns->state == MDNS_STATE_ANNOUNCE_WAIT)) {
1935 struct mdns_domain domain;
1936 u8_t i;
1937
1938 res = mdns_build_host_domain(&domain, mdns);
1939 if (res == ERR_OK && mdns_domain_eq(&ans.info.domain, &domain)) {
1940 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe response matches host domain!\n"));
1941 mdns_probe_conflict(netif, 0);
1942 break;
1943 }
1944
1945 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
1946 struct mdns_service* service = mdns->services[i];
1947 if (!service) {
1948 continue;
1949 }
1950 res = mdns_build_service_domain(&domain, service, 1);
1951 if ((res == ERR_OK) && mdns_domain_eq(&ans.info.domain, &domain)) {
1952 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe response matches service domain!\n"));
1953 mdns_probe_conflict(netif, i + 1);
1954 break;
1955 }
1956 }
1957 if (i < MDNS_MAX_SERVICES)
1958 break;
1959 }
1960 /* Perform conflict resolution (RFC6762 section 9):
1961 * We assume a conflict if the hostname or service name matches the answers
1962 * domain. Only if the rdata matches exactly we reset our assumption to no
1963 * conflict. As stated in the RFC:
1964 * What may be considered inconsistent is context sensitive, except that
1965 * resource records with identical rdata are never considered inconsistent,
1966 * even if they originate from different hosts.
1967 */
1968 else if ((mdns->state == MDNS_STATE_ANNOUNCING) ||
1969 (mdns->state == MDNS_STATE_COMPLETE)) {
1970 struct mdns_domain domain;
1971 u8_t i;
1972 u8_t conflict = 0;
1973
1974 /* Evaluate unique hostname records -> A and AAAA */
1975 res = mdns_build_host_domain(&domain, mdns);
1976 if (res == ERR_OK && mdns_domain_eq(&ans.info.domain, &domain)) {
1977 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response matches host domain, assuming conflict\n"));
1978 /* This means a conflict has taken place, except when the packet contains
1979 * exactly the same rdata. */
1980 conflict = 1;
1981 /* Evaluate rdata -> to see if it's a copy of our own data */
1982 if (ans.info.type == DNS_RRTYPE_A) {
1983#if LWIP_IPV4
1984 if (ans.rd_length == sizeof(ip4_addr_t) &&
1985 pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip4_addr(netif), ans.rd_length) == 0) {
1986 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own IPv4 address record -> no conflict\n"));
1987 conflict = 0;
1988 }
1989#endif
1990 }
1991 else if (ans.info.type == DNS_RRTYPE_AAAA) {
1992#if LWIP_IPV6
1993 if (ans.rd_length == sizeof(ip6_addr_p_t)) {
1994 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
1995 if (pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip6_addr(netif, i), ans.rd_length) == 0) {
1996 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own iPv6 address record, num = %d -> no conflict\n",i));
1997 conflict = 0;
1998 }
1999 }
2000 }
2001#endif
2002 }
2003 }
2004 /* Evaluate unique service name records -> SRV and TXT */
2005 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
2006 struct mdns_service* service = mdns->services[i];
2007 if (!service) {
2008 continue;
2009 }
2010 res = mdns_build_service_domain(&domain, service, 1);
2011 if ((res == ERR_OK) && mdns_domain_eq(&ans.info.domain, &domain)) {
2012 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response matches service domain, assuming conflict\n"));
2013 /* This means a conflict has taken place, except when the packet contains
2014 * exactly the same rdata. */
2015 conflict = 1;
2016 /* Evaluate rdata -> to see if it's a copy of our own data */
2017 if (ans.info.type == DNS_RRTYPE_SRV) {
2018 /* Read and compare to with our SRV record */
2019 u16_t field16, len, read_pos;
2020 struct mdns_domain srv_ans, my_ans;
2021 read_pos = ans.rd_offset;
2022 do {
2023 /* Check priority field */
2024 len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
2025 if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_PRIORITY) {
2026 break;
2027 }
2028 read_pos += len;
2029 /* Check weight field */
2030 len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
2031 if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_WEIGHT) {
2032 break;
2033 }
2034 read_pos += len;
2035 /* Check port field */
2036 len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
2037 if (len != sizeof(field16) || lwip_ntohs(field16) != service->port) {
2038 break;
2039 }
2040 read_pos += len;
2041 /* Check host field */
2042 len = mdns_readname(pkt->pbuf, read_pos, &srv_ans);
2043 mdns_build_host_domain(&my_ans, mdns);
2044 if (len == MDNS_READNAME_ERROR || !mdns_domain_eq(&srv_ans, &my_ans)) {
2045 break;
2046 }
2047 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own SRV record -> no conflict\n"));
2048 conflict = 0;
2049 } while (0);
2050 } else if (ans.info.type == DNS_RRTYPE_TXT) {
2051 mdns_prepare_txtdata(service);
2052 if (service->txtdata.length == ans.rd_length &&
2053 pbuf_memcmp(pkt->pbuf, ans.rd_offset, service->txtdata.name, ans.rd_length) == 0) {
2054 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own TXT record -> no conflict\n"));
2055 conflict = 0;
2056 }
2057 }
2058 }
2059 }
2060 if (conflict != 0) {
2061 /* Reset host to probing to reconfirm uniqueness */
2062 LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: Conflict resolution -> reset to probing state\n"));
2063 mdns_resp_restart(netif);
2064 break;
2065 }
2066 }
2067 }
2068 /* Clear all xxx_left variables because we parsed all answers */
2069 pkt->answers_left = 0;
2070 pkt->authoritative_left = 0;
2071 pkt->additional_left = 0;
2072}
2073
2078static void
2079mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
2080{
2081 struct dns_hdr hdr;
2082 struct mdns_packet packet;
2083 struct netif *recv_netif = ip_current_input_netif();
2084 u16_t offset = 0;
2085
2087 LWIP_UNUSED_ARG(pcb);
2088
2089 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Received IPv%d MDNS packet, len %d\n", IP_IS_V6(addr) ? 6 : 4, p->tot_len));
2090
2091 if (NETIF_TO_HOST(recv_netif) == NULL) {
2092 /* From netif not configured for MDNS */
2093 goto dealloc;
2094 }
2095
2097 /* Too small */
2098 goto dealloc;
2099 }
2101
2102 if (DNS_HDR_GET_OPCODE(&hdr)) {
2103 /* Ignore non-standard queries in multicast packets (RFC 6762, section 18.3) */
2104 goto dealloc;
2105 }
2106
2107 memset(&packet, 0, sizeof(packet));
2108 SMEMCPY(&packet.source_addr, addr, sizeof(packet.source_addr));
2109 packet.source_port = port;
2110 packet.pbuf = p;
2111 packet.parse_offset = offset;
2112 packet.tx_id = lwip_ntohs(hdr.id);
2113 packet.questions = packet.questions_left = lwip_ntohs(hdr.numquestions);
2114 packet.answers = packet.answers_left = lwip_ntohs(hdr.numanswers);
2115 packet.authoritative = packet.authoritative_left = lwip_ntohs(hdr.numauthrr);
2116 packet.additional = packet.additional_left = lwip_ntohs(hdr.numextrarr);
2117
2118 /* Source address check (RFC6762 section 11) -> for responses.
2119 * Source address check (RFC6762 section 5.5) -> for queries.
2120 * When the dest addr == multicast addr we know the packet originated on that
2121 * link. If not, we need to check the source address. We only accept queries
2122 * that originated on the link. Others are discarded.
2123 */
2124#if LWIP_IPV6
2126 /* instead of having one 'v6group' per netif, just compare zoneless here */
2127 if (!ip_addr_zoneless_eq(ip_current_dest_addr(), &v6group)) {
2128 packet.recv_unicast = 1;
2129
2130 if (ip6_addr_ismulticast_global(ip_2_ip6(ip_current_src_addr()))
2131 || ip6_addr_isglobal(ip_2_ip6(ip_current_src_addr()))) {
2132 goto dealloc;
2133 }
2134 }
2135 }
2136#endif
2137#if LWIP_IPV4
2139 if (!ip_addr_eq(ip_current_dest_addr(), &v4group)) {
2140 packet.recv_unicast = 1;
2141
2142 if (!ip4_addr_net_eq(ip_2_ip4(ip_current_src_addr()),
2143 netif_ip4_addr(recv_netif),
2144 netif_ip4_netmask(recv_netif))){
2145 goto dealloc;
2146 }
2147 }
2148 }
2149#endif
2150
2151 if (hdr.flags1 & DNS_FLAG1_RESPONSE) {
2152 mdns_handle_response(&packet, recv_netif);
2153 } else {
2154 if (packet.questions && hdr.flags1 & DNS_FLAG1_TRUNC) {
2155 /* this is a new truncated question */
2156 struct mdns_packet *pkt = (struct mdns_packet *)LWIP_MEMPOOL_ALLOC(MDNS_PKTS);
2157 if (!pkt)
2158 goto dealloc; /* don't reply truncated question if alloc error */
2159 SMEMCPY(pkt, &packet, sizeof(packet));
2160 /* insert this question in pending list */
2161 pkt->next_tc_question = pending_tc_questions;
2162 pending_tc_questions = pkt;
2163 /* question with truncated flags, need to wait 400-500ms before replying */
2164 sys_timeout(MDNS_RESPONSE_TC_DELAY_MS, mdns_handle_tc_question, pkt);
2165 /* return without dealloc pbuf */
2166 return;
2167 }
2168 else if (!packet.questions && packet.answers && pending_tc_questions) {
2169 /* this packet is a known-answer packet for a truncated question previously received */
2170 struct mdns_packet *q = pending_tc_questions;
2171 while (q) {
2172 if ((packet.source_port == q->source_port) &&
2173 ip_addr_eq(&packet.source_addr, &q->source_addr))
2174 break;
2175 q = q->next_tc_question;
2176 }
2177 if (q) {
2178 /* found question from the same source */
2179 struct mdns_packet *pkt = (struct mdns_packet *)LWIP_MEMPOOL_ALLOC(MDNS_PKTS);
2180 if (!pkt)
2181 goto dealloc; /* don't reply truncated question if alloc error */
2182 SMEMCPY(pkt, &packet, sizeof(packet));
2183 /* insert this known-ansert in question */
2184 pkt->next_answer = q->next_answer;
2185 q->next_answer = pkt;
2186 /* nothing more to do */
2187 return;
2188 }
2189 }
2190 /* if previous tests fail, handle this question normally */
2191 mdns_handle_question(&packet, recv_netif);
2192 }
2193
2194dealloc:
2195 pbuf_free(p);
2196}
2197
2198#if LWIP_NETIF_EXT_STATUS_CALLBACK && MDNS_RESP_USENETIF_EXTCALLBACK
2199static void
2200mdns_netif_ext_status_callback(struct netif *netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t *args)
2201{
2203
2204 /* MDNS enabled on netif? */
2205 if (NETIF_TO_HOST(netif) == NULL) {
2206 return;
2207 }
2208
2210 if (args->status_changed.state != 0) {
2211 mdns_resp_restart(netif);
2212 }
2213 /* TODO: send goodbye message */
2214 }
2216 if (args->link_changed.state != 0) {
2217 mdns_resp_restart(netif);
2218 }
2219 }
2223 mdns_resp_restart(netif);
2224 }
2225}
2226#endif /* LWIP_NETIF_EXT_STATUS_CALLBACK && MDNS_RESP_USENETIF_EXTCALLBACK */
2227
2228static void
2229mdns_define_probe_rrs_to_send(struct netif *netif, struct mdns_outmsg *outmsg)
2230{
2231 struct mdns_host *mdns = NETIF_TO_HOST(netif);
2232 int i;
2233
2234 memset(outmsg, 0, sizeof(struct mdns_outmsg));
2235
2236 /* Add unicast questions with rtype ANY for all our desired records */
2237 outmsg->host_questions = QUESTION_PROBE_HOST_ANY;
2238
2239 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
2240 struct mdns_service* service = mdns->services[i];
2241 if (!service) {
2242 continue;
2243 }
2244 outmsg->serv_questions[i] = QUESTION_PROBE_SERVICE_NAME_ANY;
2245 }
2246
2247 /* Add answers to the questions above into the authority section for tiebreaking */
2248#if LWIP_IPV4
2249 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
2250 outmsg->host_replies = REPLY_HOST_A;
2251 }
2252#endif
2253#if LWIP_IPV6
2254 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
2255 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
2256 outmsg->host_replies |= REPLY_HOST_AAAA;
2257 }
2258 }
2259#endif
2260
2261 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
2262 struct mdns_service *serv = mdns->services[i];
2263 if (serv) {
2264 outmsg->serv_replies[i] = REPLY_SERVICE_SRV;
2265 }
2266 }
2267}
2268
2269static err_t
2270mdns_send_probe(struct netif* netif, const ip_addr_t *destination)
2271{
2272 struct mdns_outmsg outmsg;
2273
2274 mdns_define_probe_rrs_to_send(netif, &outmsg);
2275
2276 outmsg.tx_id = 0;
2277 outmsg.dest_port = LWIP_IANA_PORT_MDNS;
2278 SMEMCPY(&outmsg.dest_addr, destination, sizeof(outmsg.dest_addr));
2279 return mdns_send_outpacket(&outmsg, netif);
2280}
2281
2285static void
2286mdns_probe_and_announce(void* arg)
2287{
2288 struct netif *netif = (struct netif *)arg;
2289 struct mdns_host* mdns = NETIF_TO_HOST(netif);
2290 u32_t announce_delay;
2291
2292
2293 switch (mdns->state) {
2294 case MDNS_STATE_OFF:
2295 case MDNS_STATE_PROBE_WAIT:
2296 case MDNS_STATE_PROBING:
2297#if LWIP_IPV4
2298 /*if ipv4 wait with probing until address is set*/
2299 if (!ip4_addr_isany_val(*netif_ip4_addr(netif)) &&
2300 mdns_send_probe(netif, &v4group) == ERR_OK)
2301#endif
2302 {
2303#if LWIP_IPV6
2304 if (mdns_send_probe(netif, &v6group) == ERR_OK)
2305#endif
2306 {
2307 mdns->state = MDNS_STATE_PROBING;
2308 mdns->sent_num++;
2309 }
2310 }
2311
2312 if (mdns->sent_num >= MDNS_PROBE_COUNT) {
2313 mdns->state = MDNS_STATE_ANNOUNCE_WAIT;
2314 mdns->sent_num = 0;
2315 }
2316
2317 if (mdns->sent_num && mdns->rate_limit_activated == 1) {
2318 /* delay second probe if rate limiting activated */
2319 sys_timeout(MDNS_PROBE_MAX_CONFLICTS_TIMEOUT, mdns_probe_and_announce, netif);
2320 }
2321 else {
2322 sys_timeout(MDNS_PROBE_DELAY_MS, mdns_probe_and_announce, netif);
2323 }
2324 break;
2325 case MDNS_STATE_ANNOUNCE_WAIT:
2326 case MDNS_STATE_ANNOUNCING:
2327 if (mdns->sent_num == 0) {
2328 /* probing was successful, announce all records */
2329 mdns->state = MDNS_STATE_ANNOUNCING;
2330 /* Reset rate limit max probe conflict timeout flag */
2331 mdns->rate_limit_activated = 0;
2332 /* Let the client know probing was successful */
2333 if (mdns_name_result_cb != NULL) {
2334 mdns_name_result_cb(netif, MDNS_PROBING_SUCCESSFUL, 0);
2335 }
2336 }
2337
2338 mdns_resp_announce(netif);
2339 mdns->sent_num++;
2340
2341 if (mdns->sent_num >= MDNS_ANNOUNCE_COUNT) {
2342 /* Announcing and probing complete */
2343 mdns->state = MDNS_STATE_COMPLETE;
2344 mdns->sent_num = 0;
2345 }
2346 else {
2347 announce_delay = MDNS_ANNOUNCE_DELAY_MS * (1 << (mdns->sent_num - 1));
2348 sys_timeout(announce_delay, mdns_probe_and_announce, netif);
2349 }
2350 break;
2351 case MDNS_STATE_COMPLETE:
2352 default:
2353 /* Do nothing */
2354 break;
2355 }
2356}
2357
2367err_t
2368mdns_resp_add_netif(struct netif *netif, const char *hostname)
2369{
2370 err_t res;
2371 struct mdns_host *mdns;
2372
2374 LWIP_ERROR("mdns_resp_add_netif: netif != NULL", (netif != NULL), return ERR_VAL);
2375 LWIP_ERROR("mdns_resp_add_netif: Hostname too long", (strlen(hostname) <= MDNS_LABEL_MAXLEN), return ERR_VAL);
2376
2377 LWIP_ASSERT("mdns_resp_add_netif: Double add", NETIF_TO_HOST(netif) == NULL);
2378 mdns = (struct mdns_host *) mem_calloc(1, sizeof(struct mdns_host));
2379 LWIP_ERROR("mdns_resp_add_netif: Alloc failed", (mdns != NULL), return ERR_MEM);
2380
2381 netif_set_client_data(netif, mdns_netif_client_id, mdns);
2382
2383 MEMCPY(&mdns->name, hostname, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(hostname)));
2384
2385 /* Init delayed message structs with address and port */
2386#if LWIP_IPV4
2387 mdns->ipv4.delayed_msg_multicast.dest_port = LWIP_IANA_PORT_MDNS;
2388 SMEMCPY(&mdns->ipv4.delayed_msg_multicast.dest_addr, &v4group,
2389 sizeof(ip_addr_t));
2390#endif
2391
2392#if LWIP_IPV6
2393 mdns->ipv6.delayed_msg_multicast.dest_port = LWIP_IANA_PORT_MDNS;
2394 SMEMCPY(&mdns->ipv6.delayed_msg_multicast.dest_addr, &v6group,
2395 sizeof(ip_addr_t));
2396#endif
2397
2398 /* Join multicast groups */
2399#if LWIP_IPV4
2400 res = igmp_joingroup_netif(netif, ip_2_ip4(&v4group));
2401 if (res != ERR_OK) {
2402 goto cleanup;
2403 }
2404#endif
2405#if LWIP_IPV6
2406 res = mld6_joingroup_netif(netif, ip_2_ip6(&v6group));
2407 if (res != ERR_OK) {
2408 goto cleanup;
2409 }
2410#endif
2411
2412 mdns_resp_restart(netif);
2413
2414 return ERR_OK;
2415
2416cleanup:
2417 mem_free(mdns);
2418 netif_set_client_data(netif, mdns_netif_client_id, NULL);
2419 return res;
2420}
2421
2429err_t
2430mdns_resp_remove_netif(struct netif *netif)
2431{
2432 int i;
2433 struct mdns_host *mdns;
2434
2436 LWIP_ASSERT("mdns_resp_remove_netif: Null pointer", netif);
2437 mdns = NETIF_TO_HOST(netif);
2438 LWIP_ERROR("mdns_resp_remove_netif: Not an active netif", (mdns != NULL), return ERR_VAL);
2439
2440 sys_untimeout(mdns_probe_and_announce, netif);
2441
2442 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
2443 struct mdns_service *service = mdns->services[i];
2444 if (service) {
2445 mem_free(service);
2446 }
2447 }
2448
2449 /* Leave multicast groups */
2450#if LWIP_IPV4
2451 igmp_leavegroup_netif(netif, ip_2_ip4(&v4group));
2452#endif
2453#if LWIP_IPV6
2454 mld6_leavegroup_netif(netif, ip_2_ip6(&v6group));
2455#endif
2456
2457 mem_free(mdns);
2458 netif_set_client_data(netif, mdns_netif_client_id, NULL);
2459 return ERR_OK;
2460}
2461
2471err_t
2472mdns_resp_rename_netif(struct netif *netif, const char *hostname)
2473{
2474 struct mdns_host *mdns;
2475 size_t len;
2476
2478 len = strlen(hostname);
2479 LWIP_ERROR("mdns_resp_rename_netif: netif != NULL", (netif != NULL), return ERR_VAL);
2480 LWIP_ERROR("mdns_resp_rename_netif: Hostname too long", (len <= MDNS_LABEL_MAXLEN), return ERR_VAL);
2481 mdns = NETIF_TO_HOST(netif);
2482 LWIP_ERROR("mdns_resp_rename_netif: Not an mdns netif", (mdns != NULL), return ERR_VAL);
2483
2484 MEMCPY(&mdns->name, hostname, LWIP_MIN(MDNS_LABEL_MAXLEN, len));
2485 mdns->name[len] = '\0'; /* null termination in case new name is shorter than previous */
2486
2487 mdns_resp_restart_delay(netif, MDNS_PROBE_DELAY_MS);
2488
2489 return ERR_OK;
2490}
2491
2498int
2499mdns_resp_netif_active(struct netif *netif)
2500{
2501 return NETIF_TO_HOST(netif) != NULL;
2502}
2503
2518s8_t
2519mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, service_get_txt_fn_t txt_fn, void *txt_data)
2520{
2521 u8_t slot;
2522 struct mdns_service *srv;
2523 struct mdns_host *mdns;
2524
2526 LWIP_ASSERT("mdns_resp_add_service: netif != NULL", netif);
2527 mdns = NETIF_TO_HOST(netif);
2528 LWIP_ERROR("mdns_resp_add_service: Not an mdns netif", (mdns != NULL), return ERR_VAL);
2529
2530 LWIP_ERROR("mdns_resp_add_service: Name too long", (strlen(name) <= MDNS_LABEL_MAXLEN), return ERR_VAL);
2531 LWIP_ERROR("mdns_resp_add_service: Service too long", (strlen(service) <= MDNS_LABEL_MAXLEN), return ERR_VAL);
2532 LWIP_ERROR("mdns_resp_add_service: Bad proto (need TCP or UDP)", (proto == DNSSD_PROTO_TCP || proto == DNSSD_PROTO_UDP), return ERR_VAL);
2533
2534 for (slot = 0; slot < MDNS_MAX_SERVICES; slot++) {
2535 if (mdns->services[slot] == NULL) {
2536 break;
2537 }
2538 }
2539 LWIP_ERROR("mdns_resp_add_service: Service list full (increase MDNS_MAX_SERVICES)", (slot < MDNS_MAX_SERVICES), return ERR_MEM);
2540
2541 srv = (struct mdns_service *)mem_calloc(1, sizeof(struct mdns_service));
2542 LWIP_ERROR("mdns_resp_add_service: Alloc failed", (srv != NULL), return ERR_MEM);
2543
2544 MEMCPY(&srv->name, name, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(name)));
2545 MEMCPY(&srv->service, service, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(service)));
2546 srv->txt_fn = txt_fn;
2547 srv->txt_userdata = txt_data;
2548 srv->proto = (u16_t)proto;
2549 srv->port = port;
2550
2551 mdns->services[slot] = srv;
2552
2553 mdns_resp_restart(netif);
2554
2555 return slot;
2556}
2557
2565err_t
2566mdns_resp_del_service(struct netif *netif, u8_t slot)
2567{
2568 struct mdns_host *mdns;
2569 struct mdns_service *srv;
2570 LWIP_ASSERT("mdns_resp_del_service: netif != NULL", netif);
2571 mdns = NETIF_TO_HOST(netif);
2572 LWIP_ERROR("mdns_resp_del_service: Not an mdns netif", (mdns != NULL), return ERR_VAL);
2573 LWIP_ERROR("mdns_resp_del_service: Invalid Service ID", slot < MDNS_MAX_SERVICES, return ERR_VAL);
2574 LWIP_ERROR("mdns_resp_del_service: Invalid Service ID", (mdns->services[slot] != NULL), return ERR_VAL);
2575
2576 srv = mdns->services[slot];
2577 mdns->services[slot] = NULL;
2578 mem_free(srv);
2579 return ERR_OK;
2580}
2581
2590err_t
2591mdns_resp_rename_service(struct netif *netif, u8_t slot, const char *name)
2592{
2593 struct mdns_service *srv;
2594 struct mdns_host *mdns;
2595 size_t len;
2596
2598 len = strlen(name);
2599 LWIP_ASSERT("mdns_resp_rename_service: netif != NULL", netif);
2600 mdns = NETIF_TO_HOST(netif);
2601 LWIP_ERROR("mdns_resp_rename_service: Not an mdns netif", (mdns != NULL), return ERR_VAL);
2602 LWIP_ERROR("mdns_resp_rename_service: Name too long", (len <= MDNS_LABEL_MAXLEN), return ERR_VAL);
2603 LWIP_ERROR("mdns_resp_rename_service: Invalid Service ID", slot < MDNS_MAX_SERVICES, return ERR_VAL);
2604 LWIP_ERROR("mdns_resp_rename_service: Invalid Service ID", (mdns->services[slot] != NULL), return ERR_VAL);
2605
2606 srv = mdns->services[slot];
2607
2608 MEMCPY(&srv->name, name, LWIP_MIN(MDNS_LABEL_MAXLEN, len));
2609 srv->name[len] = '\0'; /* null termination in case new name is shorter than previous */
2610
2611 mdns_resp_restart_delay(netif, MDNS_PROBE_DELAY_MS);
2612
2613 return ERR_OK;
2614}
2615
2625err_t
2626mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_t txt_len)
2627{
2629 LWIP_ASSERT("mdns_resp_add_service_txtitem: service != NULL", service);
2630
2631 /* Use a mdns_domain struct to store txt chunks since it is the same encoding */
2632 return mdns_domain_add_label(&service->txtdata, txt, txt_len);
2633}
2634
2635#if LWIP_MDNS_SEARCH
2641void
2642mdns_search_stop(u8_t request_id)
2643{
2644 struct mdns_request *req;
2645 LWIP_ASSERT("mdns_search_stop: bad request_id", request_id < MDNS_MAX_REQUESTS);
2646 req = &mdns_requests[request_id];
2647 if (req && req->result_fn) {
2648 req->result_fn = NULL;
2649 }
2650}
2651
2666err_t
2667mdns_search_service(const char *name, const char *service, enum mdns_sd_proto proto,
2668 struct netif *netif, search_result_fn_t result_fn, void *arg,
2669 u8_t *request_id)
2670{
2671 u8_t slot;
2672 struct mdns_request *req;
2673 if (name) {
2674 LWIP_ERROR("mdns_search_service: Name too long", (strlen(name) <= MDNS_LABEL_MAXLEN), return ERR_VAL);
2675 }
2676 LWIP_ERROR("mdns_search_service: Service too long", (strlen(service) < MDNS_DOMAIN_MAXLEN), return ERR_VAL);
2677 LWIP_ERROR("mdns_search_service: Bad reqid pointer", request_id, return ERR_VAL);
2678 LWIP_ERROR("mdns_search_service: Bad proto (need TCP or UDP)", (proto == DNSSD_PROTO_TCP || proto == DNSSD_PROTO_UDP), return ERR_VAL);
2679 for (slot = 0; slot < MDNS_MAX_REQUESTS; slot++) {
2680 if (mdns_requests[slot].result_fn == NULL) {
2681 break;
2682 }
2683 }
2684 if (slot >= MDNS_MAX_REQUESTS) {
2685 /* Don't assert if no more space in mdns_request table. Just return an error. */
2686 return ERR_MEM;
2687 }
2688
2689 req = &mdns_requests[slot];
2690 memset(req, 0, sizeof(struct mdns_request));
2691 req->result_fn = result_fn;
2692 req->arg = arg;
2693 req->proto = (u16_t)proto;
2694 req->qtype = DNS_RRTYPE_PTR;
2695 if (proto == DNSSD_PROTO_UDP && strcmp(service, "_services._dns-sd") == 0) {
2696 req->only_ptr = 1; /* don't check other answers */
2697 }
2698 mdns_domain_add_string(&req->service, service);
2699 if (name) {
2700 MEMCPY(&req->name, name, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(name)));
2701 }
2702 /* save request id (slot) in pointer provided by caller */
2703 *request_id = slot;
2704 /* now prepare a MDNS request and send it (on specified interface) */
2705#if LWIP_IPV6
2706 mdns_send_request(req, netif, &v6group);
2707#endif
2708#if LWIP_IPV4
2709 mdns_send_request(req, netif, &v4group);
2710#endif
2711 return ERR_OK;
2712}
2713#endif
2714
2720void
2721mdns_resp_announce(struct netif *netif)
2722{
2723 struct mdns_host* mdns;
2725 LWIP_ERROR("mdns_resp_announce: netif != NULL", (netif != NULL), return);
2726
2727 mdns = NETIF_TO_HOST(netif);
2728 if (mdns == NULL) {
2729 return;
2730 }
2731
2732 /* Do not announce if the mdns responder is off, waiting to probe, probing or
2733 * waiting to announce. */
2734 if (mdns->state >= MDNS_STATE_ANNOUNCING) {
2735 /* Announce on IPv6 and IPv4 */
2736#if LWIP_IPV6
2737 mdns_announce(netif, &v6group);
2738 mdns_start_multicast_timeouts_ipv6(netif);
2739#endif
2740#if LWIP_IPV4
2741 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
2742 mdns_announce(netif, &v4group);
2743 mdns_start_multicast_timeouts_ipv4(netif);
2744 }
2745#endif
2746 } /* else: ip address changed while probing was ongoing? @todo reset counter to restart? */
2747}
2748
2751void
2752mdns_resp_register_name_result_cb(mdns_name_result_cb_t cb)
2753{
2754 mdns_name_result_cb = cb;
2755}
2756
2764void
2765mdns_resp_restart_delay(struct netif *netif, uint32_t delay)
2766{
2767 struct mdns_host* mdns;
2769 LWIP_ERROR("mdns_resp_restart: netif != NULL", (netif != NULL), return);
2770
2771 mdns = NETIF_TO_HOST(netif);
2772 if (mdns == NULL) {
2773 return;
2774 }
2775 /* Make sure timer is not running */
2776 sys_untimeout(mdns_probe_and_announce, netif);
2777
2778 mdns->sent_num = 0;
2779 mdns->state = MDNS_STATE_PROBE_WAIT;
2780
2781 /* RFC6762 section 8.1: If fifteen conflicts occur within any ten-second period,
2782 * then the host MUST wait at least five seconds before each successive
2783 * additional probe attempt.
2784 */
2785 if (mdns->rate_limit_activated == 1) {
2786 sys_timeout(MDNS_PROBE_MAX_CONFLICTS_TIMEOUT, mdns_probe_and_announce, netif);
2787 }
2788 else {
2789 /* Adjust probe delay according sent probe count. */
2790 sys_timeout(delay, mdns_probe_and_announce, netif);
2791 }
2792}
2793
2800void
2801mdns_resp_restart(struct netif *netif)
2802{
2803 mdns_resp_restart_delay(netif, MDNS_INITIAL_PROBE_DELAY_MS);
2804}
2805
2810void
2811mdns_resp_init(void)
2812{
2813 err_t res;
2814
2815 /* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
2816#if LWIP_MDNS_SEARCH
2817 memset(mdns_requests, 0, sizeof(mdns_requests));
2818#endif
2819 LWIP_MEMPOOL_INIT(MDNS_PKTS);
2820 mdns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
2821 LWIP_ASSERT("Failed to allocate pcb", mdns_pcb != NULL);
2822#if LWIP_MULTICAST_TX_OPTIONS
2823 udp_set_multicast_ttl(mdns_pcb, MDNS_IP_TTL);
2824#else
2825 mdns_pcb->ttl = MDNS_IP_TTL;
2826#endif
2827 res = udp_bind(mdns_pcb, IP_ANY_TYPE, LWIP_IANA_PORT_MDNS);
2828 LWIP_UNUSED_ARG(res); /* in case of LWIP_NOASSERT */
2829 LWIP_ASSERT("Failed to bind pcb", res == ERR_OK);
2830 udp_recv(mdns_pcb, mdns_recv, NULL);
2831
2832 mdns_netif_client_id = netif_alloc_client_data_id();
2833
2834#if MDNS_RESP_USENETIF_EXTCALLBACK
2835 /* register for netif events when started on first netif */
2836 netif_add_ext_callback(&netif_callback, mdns_netif_ext_status_callback);
2837#endif
2838}
2839
2846void *mdns_get_service_txt_userdata(struct netif *netif, s8_t slot)
2847{
2848 struct mdns_host *mdns = NETIF_TO_HOST(netif);
2849 struct mdns_service *s;
2850 LWIP_ASSERT("mdns_get_service_txt_userdata: index out of range", slot < MDNS_MAX_SERVICES);
2851 s = mdns->services[slot];
2852 return s ? s->txt_userdata : NULL;
2853}
2854
2855#endif /* LWIP_MDNS_RESPONDER */
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * hostname
Definition: ftp.c:88
#define lwip_ntohl(x)
Definition: def.h:89
#define LWIP_MIN(x, y)
Definition: def.h:66
#define lwip_ntohs(x)
Definition: def.h:87
#define mem_free(ptr, bsize)
Definition: types.h:124
#define NULL
Definition: types.h:112
UINT32 uint32_t
Definition: types.h:75
static WCHAR reason[MAX_STRING_RESOURCE_LEN]
Definition: object.c:1904
static void cleanup(void)
Definition: main.c:1335
USHORT port
Definition: uri.c:228
#define U32_F
Definition: cc.h:22
void * mem_calloc(mem_size_t count, mem_size_t size)
Definition: mem.c:999
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:158
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:130
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
#define ip_current_src_addr()
Definition: ip.h:223
#define ip_current_dest_addr()
Definition: ip.h:225
#define ip_current_input_netif()
Definition: ip.h:150
void dealloc(int i, int no_throw)
Definition: ehthrow.cxx:33
#define ERR_MEM
Definition: fontsub.h:52
GLdouble s
Definition: gl.h:2039
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLuint res
Definition: glext.h:9613
GLenum src
Definition: glext.h:6340
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
GLboolean GLenum GLenum GLvoid * values
Definition: glext.h:5666
GLbitfield flags
Definition: glext.h:7161
const GLint * first
Definition: glext.h:5794
GLenum const GLvoid * addr
Definition: glext.h:9621
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
uint32_t u32_t
Definition: arch.h:129
uint8_t u8_t
Definition: arch.h:125
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:373
uint16_t u16_t
Definition: arch.h:127
int8_t s8_t
Definition: arch.h:126
@ LWIP_IANA_PORT_MDNS
Definition: iana.h:88
s8_t err_t
Definition: err.h:96
@ ERR_OK
Definition: err.h:55
@ ERR_VAL
Definition: err.h:67
#define IP_ANY_TYPE
Definition: ip_addr.h:461
@ IPADDR_TYPE_ANY
Definition: ip_addr.h:60
#define LWIP_IPV6_NUM_ADDRESSES
Definition: opt.h:2487
#define LWIP_ASSERT_CORE_LOCKED()
Definition: opt.h:227
#define SMEMCPY(dst, src, len)
Definition: opt.h:145
#define MDNS_MAX_REQUESTS
Definition: mdns_opts.h:107
#define MDNS_DEBUG
Definition: mdns_opts.h:114
#define MDNS_PROBE_DELAY_MS
Definition: mdns_opts.h:68
#define MDNS_MAX_SERVICES
Definition: mdns_opts.h:60
#define MDNS_MAX_STORED_PKTS
Definition: mdns_opts.h:78
#define LWIP_MEMPOOL_DECLARE(name, num, size, desc)
Definition: memp.h:95
#define LWIP_MEMPOOL_ALLOC(name)
Definition: memp.h:122
#define LWIP_MEMPOOL_INIT(name)
Definition: memp.h:117
#define LWIP_MEMPOOL_FREE(name, x)
Definition: memp.h:127
struct netif * netif_get_by_index(u8_t idx)
Definition: netif.c:1730
u16_t netif_nsc_reason_t
Definition: netif.h:586
u16_t pbuf_memcmp(const struct pbuf *p, u16_t offset, const void *s2, u16_t n)
Definition: pbuf.c:1465
u8_t pbuf_get_at(const struct pbuf *p, u16_t offset)
Definition: pbuf.c:1402
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:727
struct pbuf * pbuf_skip(struct pbuf *in, u16_t in_offset, u16_t *out_offset)
Definition: pbuf.c:1209
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:1058
u32_t sys_now(void)
Definition: sys_arch.c:23
#define ip_2_ip6(ipaddr)
Definition: ip_addr.h:356
#define IP_IS_V6_VAL(ipaddr)
Definition: ip_addr.h:348
#define ip_addr_eq(addr1, addr2)
Definition: ip_addr.h:374
ip6_addr_t ip_addr_t
Definition: ip_addr.h:344
#define ip_addr_zoneless_eq(addr1, addr2)
Definition: ip_addr.h:376
#define IP_IS_V6(ipaddr)
Definition: ip_addr.h:350
#define IP_IS_V4_VAL(ipaddr)
Definition: ip_addr.h:347
char hdr[14]
Definition: iptest.cpp:33
#define MEMCPY(DST, SRC, BYTES)
Definition: macros.h:231
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static HMODULE MODULEINFO DWORD cb
Definition: module.c:33
static char * dest
Definition: rtl.c:135
#define min(a, b)
Definition: monoChain.cc:55
#define LWIP_NSC_IPV6_ADDR_STATE_CHANGED
Definition: netif.h:611
#define LWIP_NSC_IPV4_GATEWAY_CHANGED
Definition: netif.h:603
#define LWIP_NSC_IPV4_SETTINGS_CHANGED
Definition: netif.h:607
#define LWIP_NSC_LINK_CHANGED
Definition: netif.h:595
#define NETIF_DECLARE_EXT_CALLBACK(name)
Definition: netif.h:683
#define LWIP_NSC_STATUS_CHANGED
Definition: netif.h:599
#define netif_add_ext_callback(callback, fn)
Definition: netif.h:684
#define LWIP_NSC_IPV6_SET
Definition: netif.h:609
#define LWIP_NSC_IPV4_NETMASK_CHANGED
Definition: netif.h:605
#define LWIP_NSC_IPV4_ADDRESS_CHANGED
Definition: netif.h:601
#define DNS_RRCLASS_IN
Definition: dns.h:76
#define SIZEOF_DNS_HDR
Definition: dns.h:116
#define DNS_RRCLASS_ANY
Definition: dns.h:80
#define DNS_FLAG1_TRUNC
Definition: dns.h:89
#define DNS_RRTYPE_SRV
Definition: dns.h:72
#define DNS_RRTYPE_TXT
Definition: dns.h:70
#define DNS_RRTYPE_A
Definition: dns.h:55
#define DNS_MQUERY_IPV4_GROUP_INIT
Definition: dns.h:128
#define DNS_HDR_GET_OPCODE(hdr)
Definition: dns.h:96
#define DNS_FLAG1_RESPONSE
Definition: dns.h:84
#define DNS_RRTYPE_PTR
Definition: dns.h:66
#define DNS_FLAG1_AUTHORATIVE
Definition: dns.h:88
#define DNS_RRTYPE_AAAA
Definition: dns.h:71
#define DNS_MQUERY_IPV6_GROUP_INIT
Definition: dns.h:133
#define DNS_RRTYPE_ANY
Definition: dns.h:73
typedefPACK_STRUCT_END struct ip6_addr_packed ip6_addr_p_t
Definition: ip6.h:62
#define memset(x, y, z)
Definition: compat.h:39
CardRegion * from
Definition: spigame.cpp:19
Definition: vfat.h:185
Definition: match.c:390
Definition: dns.h:103
Definition: cookie.c:42
Definition: match.c:28
Definition: name.c:39
Definition: netif.h:269
Definition: dhcpd.h:135
Definition: pbuf.h:186
Definition: tftpd.h:86
struct _slot slot
Definition: vfat.h:196
void * arg
Definition: msvc.h:10
#define snprintf
Definition: wintirpc.h:48