1 /** 2 * @file 3 * MDNS responder implementation 4 * 5 * @defgroup mdns MDNS 6 * @ingroup apps 7 * 8 * RFC 6762 - Multicast DNS<br> 9 * RFC 6763 - DNS-Based Service Discovery 10 * 11 * You need to increase MEMP_NUM_SYS_TIMEOUT by one if you use MDNS! 12 * 13 * @verbinclude mdns.txt 14 * 15 * Things left to implement: 16 * ------------------------- 17 * 18 * - Sending goodbye messages (zero ttl) - shutdown, DHCP lease about to expire, DHCP turned off... 19 * - Sending negative responses NSEC 20 * - Fragmenting replies if required 21 * - Individual known answer detection for all local IPv6 addresses 22 * - Dynamic size of outgoing packet 23 */ 24 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" 60 #include "lwip/apps/mdns_domain.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 */ 93 static 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 */ 99 static 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 105 static struct mdns_request mdns_requests[MDNS_MAX_REQUESTS]; 106 #endif 107 108 static u8_t mdns_netif_client_id; 109 static struct udp_pcb *mdns_pcb; 110 #if MDNS_RESP_USENETIF_EXTCALLBACK 111 NETIF_DECLARE_EXT_CALLBACK(netif_callback) 112 #endif 113 static 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 117 /** Delayed response defines */ 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 128 /** Probing & announcing defines */ 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 151 /** Information about received packet */ 152 struct mdns_packet { 153 /** Sender IP/port */ 154 ip_addr_t source_addr; 155 u16_t source_port; 156 /** If packet was received unicast */ 157 u16_t recv_unicast; 158 /** Packet data */ 159 struct pbuf *pbuf; 160 /** Current parsing offset in packet */ 161 u16_t parse_offset; 162 /** Identifier. Used in legacy queries */ 163 u16_t tx_id; 164 /** Number of questions in packet, 165 * read from packet header */ 166 u16_t questions; 167 /** Number of unparsed questions */ 168 u16_t questions_left; 169 /** Number of answers in packet */ 170 u16_t answers; 171 /** Number of unparsed answers */ 172 u16_t answers_left; 173 /** Number of authoritative answers in packet */ 174 u16_t authoritative; 175 /** Number of unparsed authoritative answers */ 176 u16_t authoritative_left; 177 /** Number of additional answers in packet */ 178 u16_t additional; 179 /** Number of unparsed additional answers */ 180 u16_t additional_left; 181 /** Chained list of known answer received after a truncated question */ 182 struct mdns_packet *next_answer; 183 /** Chained list of truncated question that are waiting */ 184 struct mdns_packet *next_tc_question; 185 }; 186 187 /* list of received questions with TC flags set, waiting for known answers */ 188 static struct mdns_packet *pending_tc_questions; 189 190 /* pool of received packets */ 191 LWIP_MEMPOOL_DECLARE(MDNS_PKTS, MDNS_MAX_STORED_PKTS, sizeof (struct mdns_packet), "Stored mDNS packets") 192 193 struct mdns_question { 194 struct mdns_rr_info info; 195 /** unicast reply requested */ 196 u16_t unicast; 197 }; 198 199 struct mdns_answer_list { 200 u16_t offset[MDNS_PROBE_TIEBREAK_MAX_ANSWERS]; 201 u16_t size; 202 }; 203 204 static err_t mdns_parse_pkt_questions(struct netif *netif, 205 struct mdns_packet *pkt, 206 struct mdns_outmsg *reply); 207 static void mdns_define_probe_rrs_to_send(struct netif *netif, 208 struct mdns_outmsg *outmsg); 209 static void mdns_probe_and_announce(void* arg); 210 static void mdns_conflict_save_time(struct netif *netif); 211 212 /** 213 * Construction to make mdns struct accessible from mdns_out.c 214 * TODO: 215 * can we add the mdns struct to the netif like we do for dhcp, autoip,...? 216 * Then this is not needed any more. 217 * 218 * @param netif The network interface 219 * @return mdns struct 220 */ 221 struct mdns_host* 222 netif_mdns_data(struct netif *netif) { 223 return NETIF_TO_HOST(netif); 224 } 225 226 /** 227 * Construction to access the mdns udp pcb. 228 * 229 * @return udp_pcb struct of mdns 230 */ 231 struct udp_pcb* 232 get_mdns_pcb(void) 233 { 234 return mdns_pcb; 235 } 236 237 /** 238 * Check which replies we should send for a host/netif based on question 239 * @param netif The network interface that received the question 240 * @param rr Domain/type/class from a question 241 * @param reverse_v6_reply Bitmask of which IPv6 addresses to send reverse PTRs for 242 * if reply bit has REPLY_HOST_PTR_V6 set 243 * @return Bitmask of which replies to send 244 */ 245 static int 246 check_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 306 /** 307 * Check which replies we should send for a service based on question 308 * @param service A registered MDNS service 309 * @param rr Domain/type/class from a question 310 * @return Bitmask of which replies to send 311 */ 312 static int 313 check_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 353 /** 354 * Check if question belong to a specified request 355 * @param request A ongoing MDNS request 356 * @param rr Domain/type/class from an answer 357 * @return Bitmask of which matching replies 358 */ 359 static int 360 check_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 391 /** 392 * Helper function for mdns_read_question/mdns_read_answer 393 * Reads a domain, type and class from the packet 394 * @param pkt The MDNS packet to read from. The parse_offset field will be 395 * incremented to point to the next unparsed byte. 396 * @param info The struct to fill with domain, type and class 397 * @return ERR_OK on success, an err_t otherwise 398 */ 399 static err_t 400 mdns_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 425 /** 426 * Read a question from the packet. 427 * All questions have to be read before the answers. 428 * @param pkt The MDNS packet to read from. The questions_left field will be decremented 429 * and the parse_offset will be updated. 430 * @param question The struct to fill with question data 431 * @return ERR_OK on success, an err_t otherwise 432 */ 433 static err_t 434 mdns_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 460 /** 461 * Read an answer from the packet 462 * The variable length reply is not copied, its pbuf offset and length is stored instead. 463 * @param pkt The MDNS packet to read. The num_left field will be decremented and 464 * the parse_offset will be updated. 465 * @param answer The struct to fill with answer data 466 * @param num_left number of answers left -> answers, authoritative or additional 467 * @return ERR_OK on success, an err_t otherwise 468 */ 469 static err_t 470 mdns_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 520 /** 521 * Send unsolicited answer containing all our known data 522 * @param netif The network interface to send on 523 * @param destination The target address to send to (usually multicast address) 524 */ 525 static void 526 mdns_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 562 /** 563 * Perform lexicographical comparison to define the lexicographical order of the 564 * records. 565 * 566 * @param pkt_a first packet (needed for rr data) 567 * @param pkt_b second packet (needed for rr data) 568 * @param ans_a first rr 569 * @param ans_b second rr 570 * @param result pointer to save result in -> MDNS_LEXICOGRAPHICAL_EQUAL, 571 * MDNS_LEXICOGRAPHICAL_LATER or MDNS_LEXICOGRAPHICAL_EARLIER. 572 * @return err_t ERR_OK if result is good, ERR_VAL if domain decompression failed. 573 */ 574 static err_t 575 mdns_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 710 /** 711 * Clear authoritative answer list 712 * 713 * @param a_list answer list to clear 714 */ 715 static void 716 mdns_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 725 /** 726 * Pushes the offset of the answer on a lexicographically later sorted list. 727 * We use a simple insertion sort because most of the time we are only sorting 728 * two items. The answers are sorted from the smallest to the largest. 729 * 730 * @param a_list Answer list to which to add the answer 731 * @param pkt Packet where answer originated 732 * @param new_offset Offset of the new answer in the packet 733 * @param new_answer The new answer 734 * @return err_t ERR_MEM if list is full 735 */ 736 static err_t 737 mdns_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 786 /** 787 * Check if the given answer answers the give question 788 * 789 * @param q query to find answer for 790 * @param a answer to given query 791 * @return 1 it a answers q, 0 if not 792 */ 793 static u8_t 794 mdns_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 805 /** 806 * Converts the output packet to the input packet format for probe tiebreaking 807 * 808 * @param inpkt destination packet for conversion 809 * @param outpkt source packet for conversion 810 */ 811 static void 812 mdns_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 823 /** 824 * Debug print to print the answer part that is lexicographically compared 825 * 826 * @param pkt Packet where answer originated 827 * @param a The answer to print 828 */ 829 static void 830 mdns_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); 846 LWIP_UNUSED_ARG(a); 847 #endif 848 } 849 850 /** 851 * Perform probe tiebreaking according to RFC6762 section 8.2 852 * 853 * @param netif network interface of incoming packet 854 * @param pkt incoming packet 855 */ 856 static void 857 mdns_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; 868 u8_t match, result; 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 1060 cleanup: 1061 if (myprobe_inpkt.pbuf != NULL) { 1062 pbuf_free(myprobe_inpkt.pbuf); 1063 } 1064 } 1065 1066 /** 1067 * Check the incoming packet and parse all questions 1068 * 1069 * @param netif network interface of incoming packet 1070 * @param pkt incoming packet 1071 * @param reply outgoing message 1072 * @return err_t 1073 */ 1074 static err_t 1075 mdns_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 1115 /** 1116 * Check the incoming packet and parse all (known) answers 1117 * 1118 * @param netif network interface of incoming packet 1119 * @param pkt incoming packet 1120 * @param reply outgoing message 1121 * @return err_t 1122 */ 1123 static err_t 1124 mdns_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 1287 /** 1288 * Check the incoming packet and parse all authoritative answers to see if the 1289 * query is a probe query. 1290 * 1291 * @param netif network interface of incoming packet 1292 * @param pkt incoming packet 1293 * @param reply outgoing message 1294 * @return err_t 1295 */ 1296 static err_t 1297 mdns_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 1350 /** 1351 * Add / copy message to delaying message buffer. 1352 * 1353 * @param dest destination msg struct 1354 * @param src source msg struct 1355 */ 1356 static void 1357 mdns_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 1375 /** 1376 * Handle question MDNS packet 1377 * - Perform probe tiebreaking when in probing state 1378 * - Parse all questions and set bits what answers to send 1379 * - Clear pending answers if known answers are supplied 1380 * - Define which type of answer is requested 1381 * - Send out packet or put it on hold until after random time 1382 * 1383 * @param pkt incoming packet (in stack) 1384 * @param netif network interface of incoming packet 1385 */ 1386 static void 1387 mdns_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) { 1448 LWIP_DEBUGF(MDNS_DEBUG, 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 1464 reply.flags = DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE; 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 1694 /** 1695 * Handle truncated question MDNS packet 1696 * - Called by timer 1697 * - Call mdns_handle_question 1698 * - Do cleanup 1699 * 1700 * @param arg incoming packet (in pool) 1701 */ 1702 static void 1703 mdns_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 1732 /** 1733 * Save time when a probe conflict occurs: 1734 * - Check if we exceeded the maximum of 15 conflicts in 10seconds. 1735 * 1736 * @param netif network interface on which the conflict occurred. 1737 */ 1738 static void 1739 mdns_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 1770 /** 1771 * Handle a probe conflict: 1772 * - Check if we exceeded the maximum of 15 conflicts in 10seconds. 1773 * - Let the user know there is a conflict. 1774 * 1775 * @param netif network interface on which the conflict occurred. 1776 * @param slot service index +1 on which the conflict occurred (0 indicate hostname conflict). 1777 */ 1778 static void 1779 mdns_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 1794 /** 1795 * Loockup matching request for response MDNS packet 1796 */ 1797 #if LWIP_MDNS_SEARCH 1798 static struct mdns_request * 1799 mdns_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 1813 /** 1814 * Handle response MDNS packet: 1815 * - Handle responses on probe query 1816 * - Perform conflict resolution on every packet (RFC6762 section 9) 1817 * 1818 * @param pkt incoming packet 1819 * @param netif network interface on which packet was received 1820 */ 1821 static void 1822 mdns_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 2074 /** 2075 * Receive input function for MDNS packets. 2076 * Handles both IPv4 and IPv6 UDP pcbs. 2077 */ 2078 static void 2079 mdns_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 2086 LWIP_UNUSED_ARG(arg); 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 2096 if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, offset) < SIZEOF_DNS_HDR) { 2097 /* Too small */ 2098 goto dealloc; 2099 } 2100 offset += SIZEOF_DNS_HDR; 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 2125 if (IP_IS_V6(ip_current_dest_addr())) { 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 2138 if (!IP_IS_V6(ip_current_dest_addr())) { 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 2194 dealloc: 2195 pbuf_free(p); 2196 } 2197 2198 #if LWIP_NETIF_EXT_STATUS_CALLBACK && MDNS_RESP_USENETIF_EXTCALLBACK 2199 static void 2200 mdns_netif_ext_status_callback(struct netif *netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t *args) 2201 { 2202 LWIP_UNUSED_ARG(args); 2203 2204 /* MDNS enabled on netif? */ 2205 if (NETIF_TO_HOST(netif) == NULL) { 2206 return; 2207 } 2208 2209 if (reason & LWIP_NSC_STATUS_CHANGED) { 2210 if (args->status_changed.state != 0) { 2211 mdns_resp_restart(netif); 2212 } 2213 /* TODO: send goodbye message */ 2214 } 2215 if (reason & LWIP_NSC_LINK_CHANGED) { 2216 if (args->link_changed.state != 0) { 2217 mdns_resp_restart(netif); 2218 } 2219 } 2220 if (reason & (LWIP_NSC_IPV4_ADDRESS_CHANGED | LWIP_NSC_IPV4_GATEWAY_CHANGED | 2221 LWIP_NSC_IPV4_NETMASK_CHANGED | LWIP_NSC_IPV4_SETTINGS_CHANGED | 2222 LWIP_NSC_IPV6_SET | LWIP_NSC_IPV6_ADDR_STATE_CHANGED)) { 2223 mdns_resp_restart(netif); 2224 } 2225 } 2226 #endif /* LWIP_NETIF_EXT_STATUS_CALLBACK && MDNS_RESP_USENETIF_EXTCALLBACK */ 2227 2228 static void 2229 mdns_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 2269 static err_t 2270 mdns_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 2282 /** 2283 * Timer callback for probing and announcing on the network. 2284 */ 2285 static void 2286 mdns_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 2358 /** 2359 * @ingroup mdns 2360 * Activate MDNS responder for a network interface. 2361 * @param netif The network interface to activate. 2362 * @param hostname Name to use. Queries for <hostname>.local will be answered 2363 * with the IP addresses of the netif. The hostname will be copied, the 2364 * given pointer can be on the stack. 2365 * @return ERR_OK if netif was added, an err_t otherwise 2366 */ 2367 err_t 2368 mdns_resp_add_netif(struct netif *netif, const char *hostname) 2369 { 2370 err_t res; 2371 struct mdns_host *mdns; 2372 2373 LWIP_ASSERT_CORE_LOCKED(); 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 2416 cleanup: 2417 mem_free(mdns); 2418 netif_set_client_data(netif, mdns_netif_client_id, NULL); 2419 return res; 2420 } 2421 2422 /** 2423 * @ingroup mdns 2424 * Stop responding to MDNS queries on this interface, leave multicast groups, 2425 * and free the helper structure and any of its services. 2426 * @param netif The network interface to remove. 2427 * @return ERR_OK if netif was removed, an err_t otherwise 2428 */ 2429 err_t 2430 mdns_resp_remove_netif(struct netif *netif) 2431 { 2432 int i; 2433 struct mdns_host *mdns; 2434 2435 LWIP_ASSERT_CORE_LOCKED(); 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 2462 /** 2463 * @ingroup mdns 2464 * Update MDNS hostname for a network interface. 2465 * @param netif The network interface to activate. 2466 * @param hostname Name to use. Queries for <hostname>.local will be answered 2467 * with the IP addresses of the netif. The hostname will be copied, the 2468 * given pointer can be on the stack. 2469 * @return ERR_OK if name could be set on netif, an err_t otherwise 2470 */ 2471 err_t 2472 mdns_resp_rename_netif(struct netif *netif, const char *hostname) 2473 { 2474 struct mdns_host *mdns; 2475 size_t len; 2476 2477 LWIP_ASSERT_CORE_LOCKED(); 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 2492 /** 2493 * @ingroup mdns 2494 * Checks if an MDNS responder is active for a given network interface. 2495 * @param netif The network interface to test. 2496 * @return nonzero if responder active, zero otherwise. 2497 */ 2498 int 2499 mdns_resp_netif_active(struct netif *netif) 2500 { 2501 return NETIF_TO_HOST(netif) != NULL; 2502 } 2503 2504 /** 2505 * @ingroup mdns 2506 * Add a service to the selected network interface. 2507 * @param netif The network interface to publish this service on 2508 * @param name The name of the service 2509 * @param service The service type, like "_http" 2510 * @param proto The service protocol, DNSSD_PROTO_TCP for TCP ("_tcp") and DNSSD_PROTO_UDP 2511 * for others ("_udp") 2512 * @param port The port the service listens to 2513 * @param txt_fn Callback to get TXT data. Will be called each time a TXT reply is created to 2514 * allow dynamic replies. 2515 * @param txt_data Userdata pointer for txt_fn 2516 * @return service_id if the service was added to the netif, an err_t otherwise 2517 */ 2518 s8_t 2519 mdns_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 2525 LWIP_ASSERT_CORE_LOCKED(); 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 2558 /** 2559 * @ingroup mdns 2560 * Delete a service on the selected network interface. 2561 * @param netif The network interface on which service should be removed 2562 * @param slot The service slot number returned by mdns_resp_add_service 2563 * @return ERR_OK if the service was removed from the netif, an err_t otherwise 2564 */ 2565 err_t 2566 mdns_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 2582 /** 2583 * @ingroup mdns 2584 * Update name for an MDNS service. 2585 * @param netif The network interface to activate. 2586 * @param slot The service slot number returned by mdns_resp_add_service 2587 * @param name The new name for the service 2588 * @return ERR_OK if name could be set on service, an err_t otherwise 2589 */ 2590 err_t 2591 mdns_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 2597 LWIP_ASSERT_CORE_LOCKED(); 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 2616 /** 2617 * @ingroup mdns 2618 * Call this function from inside the service_get_txt_fn_t callback to add text data. 2619 * Buffer for TXT data is 256 bytes, and each field is prefixed with a length byte. 2620 * @param service The service provided to the get_txt callback 2621 * @param txt String to add to the TXT field. 2622 * @param txt_len Length of string 2623 * @return ERR_OK if the string was added to the reply, an err_t otherwise 2624 */ 2625 err_t 2626 mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_t txt_len) 2627 { 2628 LWIP_ASSERT_CORE_LOCKED(); 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 2636 /** 2637 * @ingroup mdns 2638 * Stop a search request. 2639 * @param request_id The search request to stop 2640 */ 2641 void 2642 mdns_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 2652 /** 2653 * @ingroup mdns 2654 * Search a specific service on the network. 2655 * @param name The name of the service 2656 * @param service The service type, like "_http" 2657 * @param proto The service protocol, DNSSD_PROTO_TCP for TCP ("_tcp") and DNSSD_PROTO_UDP 2658 * for others ("_udp") 2659 * @param netif The network interface where to send search request 2660 * @param result_fn Callback to send answer received. Will be called for each answer of a 2661 * response frame matching request sent. 2662 * @param arg Userdata pointer for result_fn 2663 * @param request_id Returned request identifier to allow stop it. 2664 * @return ERR_OK if the search request was created and sent, an err_t otherwise 2665 */ 2666 err_t 2667 mdns_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 2715 /** 2716 * @ingroup mdns 2717 * Send unsolicited answer containing all our known data 2718 * @param netif The network interface to send on 2719 */ 2720 void 2721 mdns_resp_announce(struct netif *netif) 2722 { 2723 struct mdns_host* mdns; 2724 LWIP_ASSERT_CORE_LOCKED(); 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 2749 /** Register a callback function that is called if probing is completed successfully 2750 * or with a conflict. */ 2751 void 2752 mdns_resp_register_name_result_cb(mdns_name_result_cb_t cb) 2753 { 2754 mdns_name_result_cb = cb; 2755 } 2756 2757 /** 2758 * @ingroup mdns 2759 * Restart mdns responder after a specified delay. Call this when cable is connected 2760 * after being disconnected or administrative interface is set up after being down 2761 * @param netif The network interface to send on 2762 * @param delay The delay to use before sending probe 2763 */ 2764 void 2765 mdns_resp_restart_delay(struct netif *netif, uint32_t delay) 2766 { 2767 struct mdns_host* mdns; 2768 LWIP_ASSERT_CORE_LOCKED(); 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 2794 /** 2795 * @ingroup mdns 2796 * Restart mdns responder. Call this when cable is connected after being disconnected or 2797 * administrative interface is set up after being down 2798 * @param netif The network interface to send on 2799 */ 2800 void 2801 mdns_resp_restart(struct netif *netif) 2802 { 2803 mdns_resp_restart_delay(netif, MDNS_INITIAL_PROBE_DELAY_MS); 2804 } 2805 2806 /** 2807 * @ingroup mdns 2808 * Initiate MDNS responder. Will open UDP sockets on port 5353 2809 */ 2810 void 2811 mdns_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 2840 /** 2841 * @ingroup mdns 2842 * Return TXT userdata of a specific service on a network interface. 2843 * @param netif Network interface. 2844 * @param slot Service index. 2845 */ 2846 void *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 */ 2856