diff --git a/src/apps/mdns/mdns.c b/src/apps/mdns/mdns.c index 1602ea6b..83e64f98 100644 --- a/src/apps/mdns/mdns.c +++ b/src/apps/mdns/mdns.c @@ -901,10 +901,11 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif) reply.cache_flush = 1; } - /* Delaying response. + /* Delaying response. (RFC6762 section 6) * Always delay the response, unicast or multicast, except when: - * - Answering to a single question with a unique answer (RFC6762 section 6) - * - Answering to a probe query via unicast (RFC6762 section 6) + * - Answering to a single question with a unique answer (not a probe). + * - Answering to a probe query via unicast. + * - Answering to a probe query via multicast if not multicasted within 250ms. * * unique answer? -> not if it includes service type or name ptr's */ @@ -912,9 +913,22 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif) shared_answer |= (reply.serv_replies[i] & (REPLY_SERVICE_TYPE_PTR | REPLY_SERVICE_NAME_PTR)); } - if (((pkt->questions == 1) && (!shared_answer)) || reply.probe_query_recv) { + if ( ((pkt->questions == 1) && (!shared_answer) && !reply.probe_query_recv) + || (reply.probe_query_recv && reply.unicast_reply_requested)) { delay_response = 0; } +#if LWIP_IPV6 + if (IP_IS_V6_VAL(pkt->source_addr) && reply.probe_query_recv + && !reply.unicast_reply_requested && !mdns->ipv6.multicast_probe_timeout) { + delay_response = 0; + } +#endif +#if LWIP_IPV4 + if (IP_IS_V4_VAL(pkt->source_addr) && reply.probe_query_recv + && !reply.unicast_reply_requested && !mdns->ipv4.multicast_probe_timeout) { + delay_response = 0; + } +#endif LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: response %s delayed\r\n", (delay_response ? "randomly" : "not"))); /* Unicast / multicast response: @@ -923,7 +937,7 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif) * a) Unicast reply requested && recently multicasted 1/4ttl (RFC6762 section 5.4) * b) Direct unicast query to port 5353 (RFC6762 section 5.5) * c) Reply to Legacy DNS querier (RFC6762 section 6.7) - * d) A probe message is received (RFC6762 section 6) + * d) A probe message is received requesting unicast (RFC6762 section 6) */ #if LWIP_IPV6 @@ -939,7 +953,7 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif) if ( (reply.unicast_reply_requested && listen_to_QU_bit) || pkt->recv_unicast || reply.legacy_query - || reply.probe_query_recv ) { + || (reply.probe_query_recv && reply.unicast_reply_requested)) { send_unicast = 1; } LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: send response via %s\r\n", (send_unicast ? "unicast" : "multicast"))); @@ -984,9 +998,14 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif) #if LWIP_IPV6 /* Add answers to IPv6 waiting list if: * - it's a IPv6 incoming packet - * - and the 1 second timeout is passed (RFC6762 section 6) + * - the 1 second timeout is passed (RFC6762 section 6) + * - and it's not a probe packet + * Or if: + * - it's a IPv6 incoming packet + * - and it's a probe packet */ - if (IP_IS_V6_VAL(pkt->source_addr) && !mdns->ipv6.multicast_timeout) { + if (IP_IS_V6_VAL(pkt->source_addr) && !mdns->ipv6.multicast_timeout + && !reply.probe_query_recv) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to multicast IPv6 waiting list\r\n")); mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_multicast, &reply); @@ -994,13 +1013,25 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif) mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_multicast_msg_delayed_ipv6, &mdns->ipv6.multicast_msg_waiting); } + else if (IP_IS_V6_VAL(pkt->source_addr) && reply.probe_query_recv) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to probe multicast IPv6 waiting list\r\n")); + + mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_multicast, &reply); + + mdns->ipv6.multicast_msg_waiting = 1; + } #endif #if LWIP_IPV4 /* Add answers to IPv4 waiting list if: * - it's a IPv4 incoming packet - * - and the 1 second timeout is passed (RFC6762 section 6) + * - the 1 second timeout is passed (RFC6762 section 6) + * - and it's not a probe packet + * Or if: + * - it's a IPv4 incoming packet + * - and it's a probe packet */ - if (IP_IS_V4_VAL(pkt->source_addr) && !mdns->ipv4.multicast_timeout) { + if (IP_IS_V4_VAL(pkt->source_addr) && !mdns->ipv4.multicast_timeout + && !reply.probe_query_recv) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to multicast IPv4 waiting list\r\n")); mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_multicast, &reply); @@ -1008,6 +1039,13 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif) mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_multicast_msg_delayed_ipv4, &mdns->ipv4.multicast_msg_waiting); } + else if (IP_IS_V4_VAL(pkt->source_addr) && reply.probe_query_recv) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to probe multicast IPv4 waiting list\r\n")); + + mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_multicast, &reply); + + mdns->ipv4.multicast_msg_waiting = 1; + } #endif } } @@ -1030,7 +1068,7 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif) /* Set IP/port to use when responding multicast */ #if LWIP_IPV6 if (IP_IS_V6_VAL(pkt->source_addr)) { - if (mdns->ipv6.multicast_timeout) { + if (mdns->ipv6.multicast_timeout && !reply.probe_query_recv) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: we just multicasted, ignore question\r\n")); return; } @@ -1039,7 +1077,7 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif) #endif #if LWIP_IPV4 if (IP_IS_V4_VAL(pkt->source_addr)) { - if (mdns->ipv4.multicast_timeout) { + if (mdns->ipv4.multicast_timeout && !reply.probe_query_recv) { LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: we just multicasted, ignore question\r\n")); return; } @@ -1056,22 +1094,12 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif) LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Multicast answer send successfully\r\n")); #if LWIP_IPV6 if (IP_IS_V6_VAL(pkt->source_addr)) { - mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv6, - &mdns->ipv6.multicast_timeout); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv6\n")); - mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv6, - &mdns->ipv6.multicast_timeout_25TTL); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv6\n")); + mdns_start_multicast_timeouts_ipv6(netif); } #endif #if LWIP_IPV4 if (IP_IS_V4_VAL(pkt->source_addr)) { - mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv4, - &mdns->ipv4.multicast_timeout); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv4\n")); - mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv4, - &mdns->ipv4.multicast_timeout_25TTL); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv4\n")); + mdns_start_multicast_timeouts_ipv4(netif); } #endif } @@ -1689,22 +1717,12 @@ mdns_resp_announce(struct netif *netif) /* Announce on IPv6 and IPv4 */ #if LWIP_IPV6 mdns_announce(netif, &v6group); - mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv6, - &mdns->ipv6.multicast_timeout); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv6\n")); - mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv6, - &mdns->ipv6.multicast_timeout_25TTL); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv6\n")); + mdns_start_multicast_timeouts_ipv6(netif); #endif #if LWIP_IPV4 if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { mdns_announce(netif, &v4group); - mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv4, - &mdns->ipv4.multicast_timeout); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv4\n")); - mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv4, - &mdns->ipv4.multicast_timeout_25TTL); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv4\n")); + mdns_start_multicast_timeouts_ipv4(netif); } #endif } /* else: ip address changed while probing was ongoing? @todo reset counter to restart? */ diff --git a/src/apps/mdns/mdns_out.c b/src/apps/mdns/mdns_out.c index ac4d37ac..d13b3f91 100644 --- a/src/apps/mdns/mdns_out.c +++ b/src/apps/mdns/mdns_out.c @@ -775,6 +775,37 @@ mdns_multicast_timeout_reset_ipv4(void *arg) mdns->ipv4.multicast_timeout = 0; } +/** + * Called by timeouts when timer is passed, allows direct multicast IPv4 probe + * response traffic again and sends out probe response if one was pending + * + * @param arg pointer to netif of timeout. + */ +void +mdns_multicast_probe_timeout_reset_ipv4(void *arg) +{ + struct netif *netif = (struct netif*)arg; + struct mdns_host *mdns = netif_mdns_data(netif); + err_t res; + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout finished - IPv4\n")); + + mdns->ipv4.multicast_probe_timeout = 0; + + if (mdns->ipv4.multicast_msg_waiting) { + res = mdns_send_outpacket(&mdns->ipv4.delayed_msg_multicast, netif); + if(res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send failed - IPv4\n")); + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send successful - IPv4\n")); + mdns_clear_outmsg(&mdns->ipv4.delayed_msg_multicast); + mdns->ipv4.multicast_msg_waiting = 0; + mdns_start_multicast_timeouts_ipv4(netif); + } + } +} + /** * Called by timeouts when timer is passed, allows to send an answer on a QU * question via multicast. @@ -812,12 +843,7 @@ mdns_send_multicast_msg_delayed_ipv4(void *arg) LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed multicast send successful - IPv4\n")); mdns_clear_outmsg(&mdns->ipv4.delayed_msg_multicast); mdns->ipv4.multicast_msg_waiting = 0; - mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv4, - &mdns->ipv4.multicast_timeout); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv4\n")); - mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv4, - &mdns->ipv4.multicast_timeout_25TTL); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv4\n")); + mdns_start_multicast_timeouts_ipv4(netif); } } @@ -844,6 +870,29 @@ mdns_send_unicast_msg_delayed_ipv4(void *arg) } } +/** Start all multicast timeouts for IPv4 + * Timeouts started: + * - do not multicast within one second + * - do not multicast a probe response within 250ms + * - send a multicast answer on a QU question if not send recently. + * + * @param netif network interface to start timeouts on + */ +void +mdns_start_multicast_timeouts_ipv4(struct netif *netif) +{ + struct mdns_host *mdns = netif_mdns_data(netif); + + mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv4, + &mdns->ipv4.multicast_timeout); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv4\n")); + mdns_set_timeout(netif, MDNS_MULTICAST_PROBE_TIMEOUT, mdns_multicast_probe_timeout_reset_ipv4, + &mdns->ipv4.multicast_probe_timeout); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout started - IPv4\n")); + mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv4, + &mdns->ipv4.multicast_timeout_25TTL); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv4\n")); +} #endif #if LWIP_IPV6 @@ -863,6 +912,37 @@ mdns_multicast_timeout_reset_ipv6(void *arg) mdns->ipv6.multicast_timeout = 0; } +/** + * Called by timeouts when timer is passed, allows direct multicast IPv6 probe + * response traffic again and sends out probe response if one was pending + * + * @param arg pointer to netif of timeout. + */ +void +mdns_multicast_probe_timeout_reset_ipv6(void *arg) +{ + struct netif *netif = (struct netif*)arg; + struct mdns_host *mdns = netif_mdns_data(netif); + err_t res; + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout finished - IPv6\n")); + + mdns->ipv6.multicast_probe_timeout = 0; + + if (mdns->ipv6.multicast_msg_waiting) { + res = mdns_send_outpacket(&mdns->ipv6.delayed_msg_multicast, netif); + if(res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send failed - IPv6\n")); + } + else { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send successful - IPv6\n")); + mdns_clear_outmsg(&mdns->ipv6.delayed_msg_multicast); + mdns->ipv6.multicast_msg_waiting = 0; + mdns_start_multicast_timeouts_ipv6(netif); + } + } +} + /** * Called by timeouts when timer is passed, allows to send an answer on a QU * question via multicast. @@ -900,12 +980,7 @@ mdns_send_multicast_msg_delayed_ipv6(void *arg) LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed multicast send successful - IPv6\n")); mdns_clear_outmsg(&mdns->ipv6.delayed_msg_multicast); mdns->ipv6.multicast_msg_waiting = 0; - mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv6, - &mdns->ipv6.multicast_timeout); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv6\n")); - mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv6, - &mdns->ipv6.multicast_timeout_25TTL); - LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv6\n")); + mdns_start_multicast_timeouts_ipv6(netif); } } @@ -932,6 +1007,29 @@ mdns_send_unicast_msg_delayed_ipv6(void *arg) } } +/** Start all multicast timeouts for IPv6 + * Timeouts started: + * - do not multicast within one second + * - do not multicast a probe response within 250ms + * - send a multicast answer on a QU question if not send recently. + * + * @param netif network interface to start timeouts on + */ +void +mdns_start_multicast_timeouts_ipv6(struct netif *netif) +{ + struct mdns_host *mdns = netif_mdns_data(netif); + + mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv6, + &mdns->ipv6.multicast_timeout); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv6\n")); + mdns_set_timeout(netif, MDNS_MULTICAST_PROBE_TIMEOUT, mdns_multicast_probe_timeout_reset_ipv6, + &mdns->ipv6.multicast_probe_timeout); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout started - IPv6\n")); + mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv6, + &mdns->ipv6.multicast_timeout_25TTL); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv6\n")); +} #endif /** diff --git a/src/include/lwip/apps/mdns_out.h b/src/include/lwip/apps/mdns_out.h index f36eeeda..83afab24 100644 --- a/src/include/lwip/apps/mdns_out.h +++ b/src/include/lwip/apps/mdns_out.h @@ -83,6 +83,14 @@ extern "C" { */ #define MDNS_MULTICAST_TIMEOUT 1000 +/* RFC6762 section 6: + * In this special case only, when responding via multicast to a probe, a + * Multicast DNS responder is only required to delay its transmission as + * necessary to ensure an interval of at least 250 ms since the last time the + * record was multicast on that interface. + */ +#define MDNS_MULTICAST_PROBE_TIMEOUT 250 + /* RFC6762 section 5.4: * When receiving a question with the unicast-response bit set, a responder * SHOULD usually respond with a unicast packet directed back to the querier. @@ -100,15 +108,19 @@ void mdns_set_timeout(struct netif *netif, u32_t msecs, sys_timeout_handler handler, u8_t *busy_flag); #if LWIP_IPV4 void mdns_multicast_timeout_reset_ipv4(void *arg); +void mdns_multicast_probe_timeout_reset_ipv4(void *arg); void mdns_multicast_timeout_25ttl_reset_ipv4(void *arg); void mdns_send_multicast_msg_delayed_ipv4(void *arg); void mdns_send_unicast_msg_delayed_ipv4(void *arg); +void mdns_start_multicast_timeouts_ipv4(struct netif *netif); #endif #if LWIP_IPV6 void mdns_multicast_timeout_reset_ipv6(void *arg); +void mdns_multicast_probe_timeout_reset_ipv6(void *arg); void mdns_multicast_timeout_25ttl_reset_ipv6(void *arg); void mdns_send_multicast_msg_delayed_ipv6(void *arg); void mdns_send_unicast_msg_delayed_ipv6(void *arg); +void mdns_start_multicast_timeouts_ipv6(struct netif *netif); #endif void mdns_prepare_txtdata(struct mdns_service *service); diff --git a/src/include/lwip/apps/mdns_priv.h b/src/include/lwip/apps/mdns_priv.h index 903f4cbe..df3a0973 100644 --- a/src/include/lwip/apps/mdns_priv.h +++ b/src/include/lwip/apps/mdns_priv.h @@ -145,10 +145,12 @@ struct mdns_outmsg { /** Delayed msg info */ struct mdns_delayed_msg { - /** Timer state multicast */ + /** Signals if a multicast msg needs to be send out */ u8_t multicast_msg_waiting; - /** Multicast timeout on */ + /** Multicast timeout for all multicast traffic except probe answers */ u8_t multicast_timeout; + /** Multicast timeout only for probe answers */ + u8_t multicast_probe_timeout; /** Output msg used for delayed multicast responses */ struct mdns_outmsg delayed_msg_multicast; /** Prefer multicast over unicast timeout -> 25% of TTL = we take 30s as