mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-08-24 07:05:56 +00:00
mdns: support for multi-packet known answer (questions with TC bit)
This allow Apple Bonjour Conformance Test to not fail with the following tests: - DISTRIBUTED DUPLICATE SUPPRESSION - MULTIPLE QUESTIONS - DISTRIBUTED DUPLICATE SUPPRESSION Signed-off-by: Simon Goldschmidt <goldsimon@gmx.de>
This commit is contained in:
parent
e85e473838
commit
9301225895
|
@ -18,7 +18,6 @@
|
||||||
* - Sending goodbye messages (zero ttl) - shutdown, DHCP lease about to expire, DHCP turned off...
|
* - Sending goodbye messages (zero ttl) - shutdown, DHCP lease about to expire, DHCP turned off...
|
||||||
* - Sending negative responses NSEC
|
* - Sending negative responses NSEC
|
||||||
* - Fragmenting replies if required
|
* - Fragmenting replies if required
|
||||||
* - Handling multi-packet known answers (TC bit)
|
|
||||||
* - Individual known answer detection for all local IPv6 addresses
|
* - Individual known answer detection for all local IPv6 addresses
|
||||||
* - Dynamic size of outgoing packet
|
* - Dynamic size of outgoing packet
|
||||||
*/
|
*/
|
||||||
|
@ -64,6 +63,7 @@
|
||||||
#include "lwip/udp.h"
|
#include "lwip/udp.h"
|
||||||
#include "lwip/ip_addr.h"
|
#include "lwip/ip_addr.h"
|
||||||
#include "lwip/mem.h"
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/memp.h"
|
||||||
#include "lwip/prot/dns.h"
|
#include "lwip/prot/dns.h"
|
||||||
#include "lwip/prot/iana.h"
|
#include "lwip/prot/iana.h"
|
||||||
#include "lwip/timeouts.h"
|
#include "lwip/timeouts.h"
|
||||||
|
@ -119,6 +119,11 @@ static mdns_name_result_cb_t mdns_name_result_cb;
|
||||||
#define MDNS_RESPONSE_DELAY_MIN 20
|
#define MDNS_RESPONSE_DELAY_MIN 20
|
||||||
#define MDNS_RESPONSE_DELAY (LWIP_RAND() %(MDNS_RESPONSE_DELAY_MAX - \
|
#define MDNS_RESPONSE_DELAY (LWIP_RAND() %(MDNS_RESPONSE_DELAY_MAX - \
|
||||||
MDNS_RESPONSE_DELAY_MIN) + MDNS_RESPONSE_DELAY_MIN)
|
MDNS_RESPONSE_DELAY_MIN) + MDNS_RESPONSE_DELAY_MIN)
|
||||||
|
/* Delayed response for truncated question defines */
|
||||||
|
#define MDNS_RESPONSE_TC_DELAY_MAX 500
|
||||||
|
#define MDNS_RESPONSE_TC_DELAY_MIN 400
|
||||||
|
#define MDNS_RESPONSE_TC_DELAY_MS (LWIP_RAND() % (MDNS_RESPONSE_TC_DELAY_MAX - \
|
||||||
|
MDNS_RESPONSE_TC_DELAY_MIN) + MDNS_RESPONSE_TC_DELAY_MIN)
|
||||||
|
|
||||||
/** Probing & announcing defines */
|
/** Probing & announcing defines */
|
||||||
#define MDNS_PROBE_DELAY_MS 250
|
#define MDNS_PROBE_DELAY_MS 250
|
||||||
|
@ -174,8 +179,18 @@ struct mdns_packet {
|
||||||
u16_t additional;
|
u16_t additional;
|
||||||
/** Number of unparsed additional answers */
|
/** Number of unparsed additional answers */
|
||||||
u16_t additional_left;
|
u16_t additional_left;
|
||||||
|
/** Chained list of known answer received after a truncated question */
|
||||||
|
struct mdns_packet *next_answer;
|
||||||
|
/** Chained list of truncated question that are waiting */
|
||||||
|
struct mdns_packet *next_tc_question;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* list of received questions with TC flags set, waiting for known answers */
|
||||||
|
static struct mdns_packet *pending_tc_questions;
|
||||||
|
|
||||||
|
/* pool of received packets */
|
||||||
|
LWIP_MEMPOOL_DECLARE(MDNS_PKTS, MDNS_MAX_STORED_PKTS, sizeof (struct mdns_packet), "Stored mDNS packets")
|
||||||
|
|
||||||
struct mdns_question {
|
struct mdns_question {
|
||||||
struct mdns_rr_info info;
|
struct mdns_rr_info info;
|
||||||
/** unicast reply requested */
|
/** unicast reply requested */
|
||||||
|
@ -1364,7 +1379,7 @@ mdns_add_msg_to_delayed(struct mdns_outmsg *dest, struct mdns_outmsg *src)
|
||||||
* - Define which type of answer is requested
|
* - Define which type of answer is requested
|
||||||
* - Send out packet or put it on hold until after random time
|
* - Send out packet or put it on hold until after random time
|
||||||
*
|
*
|
||||||
* @param pkt incoming packet
|
* @param pkt incoming packet (in stack)
|
||||||
* @param netif network interface of incoming packet
|
* @param netif network interface of incoming packet
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
|
@ -1410,6 +1425,17 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
|
||||||
if (res != ERR_OK) {
|
if (res != ERR_OK) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (pkt->next_answer) {
|
||||||
|
/* Also parse known-answers from additional packets */
|
||||||
|
struct mdns_packet *pkta = pkt->next_answer;
|
||||||
|
while (pkta) {
|
||||||
|
res = mdns_parse_pkt_known_answers(netif, pkta, &reply);
|
||||||
|
if (res != ERR_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pkta = pkta->next_answer;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Parse authoritative answers -> probing */
|
/* Parse authoritative answers -> probing */
|
||||||
/* If it's a probe query, we need to directly answer via unicast. */
|
/* If it's a probe query, we need to directly answer via unicast. */
|
||||||
res = mdns_parse_pkt_authoritative_answers(netif, pkt, &reply);
|
res = mdns_parse_pkt_authoritative_answers(netif, pkt, &reply);
|
||||||
|
@ -1664,6 +1690,44 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle truncated question MDNS packet
|
||||||
|
* - Called by timer
|
||||||
|
* - Call mdns_handle_question
|
||||||
|
* - Do cleanup
|
||||||
|
*
|
||||||
|
* @param pkt incoming packet (in pool)
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
mdns_handle_tc_question(void *arg)
|
||||||
|
{
|
||||||
|
struct mdns_packet *pkt = (struct mdns_packet *)arg;
|
||||||
|
struct netif *from = netif_get_by_index(pkt->pbuf->if_idx);
|
||||||
|
/* timer as elapsed, now handle this question */
|
||||||
|
mdns_handle_question(pkt, from);
|
||||||
|
/* remove from pending list */
|
||||||
|
if (pending_tc_questions == pkt) {
|
||||||
|
pending_tc_questions = pkt->next_tc_question;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
struct mdns_packet *prev = pending_tc_questions;
|
||||||
|
while (prev && prev->next_tc_question != pkt) {
|
||||||
|
prev = prev->next_tc_question;
|
||||||
|
}
|
||||||
|
LWIP_ASSERT("pkt not found in pending_tc_questions list", prev != NULL);
|
||||||
|
prev->next_tc_question = pkt->next_tc_question;
|
||||||
|
}
|
||||||
|
/* free linked answers and this question */
|
||||||
|
while (pkt->next_answer) {
|
||||||
|
struct mdns_packet *ans = pkt->next_answer;
|
||||||
|
pkt->next_answer = ans->next_answer;
|
||||||
|
pbuf_free(ans->pbuf);
|
||||||
|
LWIP_MEMPOOL_FREE(MDNS_PKTS, ans);
|
||||||
|
}
|
||||||
|
pbuf_free(pkt->pbuf);
|
||||||
|
LWIP_MEMPOOL_FREE(MDNS_PKTS, pkt);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a probe conflict:
|
* Handle a probe conflict:
|
||||||
* - Check if we exceeded the maximum of 15 conflicts in 10seconds.
|
* - Check if we exceeded the maximum of 15 conflicts in 10seconds.
|
||||||
|
@ -2067,6 +2131,43 @@ mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
|
||||||
if (hdr.flags1 & DNS_FLAG1_RESPONSE) {
|
if (hdr.flags1 & DNS_FLAG1_RESPONSE) {
|
||||||
mdns_handle_response(&packet, recv_netif);
|
mdns_handle_response(&packet, recv_netif);
|
||||||
} else {
|
} else {
|
||||||
|
if (packet.questions && hdr.flags1 & DNS_FLAG1_TRUNC) {
|
||||||
|
/* this is a new truncated question */
|
||||||
|
struct mdns_packet *pkt = (struct mdns_packet *)LWIP_MEMPOOL_ALLOC(MDNS_PKTS);
|
||||||
|
if (!pkt)
|
||||||
|
goto dealloc; /* don't reply truncated question if alloc error */
|
||||||
|
SMEMCPY(pkt, &packet, sizeof(packet));
|
||||||
|
/* insert this question in pending list */
|
||||||
|
pkt->next_tc_question = pending_tc_questions;
|
||||||
|
pending_tc_questions = pkt;
|
||||||
|
/* question with truncated flags, need to wait 400-500ms before replying */
|
||||||
|
sys_timeout(MDNS_RESPONSE_TC_DELAY_MS, mdns_handle_tc_question, pkt);
|
||||||
|
/* return without dealloc pbuf */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!packet.questions && packet.answers && pending_tc_questions) {
|
||||||
|
/* this packet is a known-answer packet for a truncated question previously received */
|
||||||
|
struct mdns_packet *q = pending_tc_questions;
|
||||||
|
while (q) {
|
||||||
|
if ((packet.source_port == q->source_port) &&
|
||||||
|
ip_addr_cmp(&packet.source_addr, &q->source_addr))
|
||||||
|
break;
|
||||||
|
q = q->next_tc_question;
|
||||||
|
}
|
||||||
|
if (q) {
|
||||||
|
/* found question from the same source */
|
||||||
|
struct mdns_packet *pkt = (struct mdns_packet *)LWIP_MEMPOOL_ALLOC(MDNS_PKTS);
|
||||||
|
if (!pkt)
|
||||||
|
goto dealloc; /* don't reply truncated question if alloc error */
|
||||||
|
SMEMCPY(pkt, &packet, sizeof(packet));
|
||||||
|
/* insert this known-ansert in question */
|
||||||
|
pkt->next_answer = q->next_answer;
|
||||||
|
q->next_answer = pkt;
|
||||||
|
/* nothing more to do */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* if previous tests fail, handle this question normally */
|
||||||
mdns_handle_question(&packet, recv_netif);
|
mdns_handle_question(&packet, recv_netif);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2675,10 +2776,10 @@ mdns_resp_init(void)
|
||||||
err_t res;
|
err_t res;
|
||||||
|
|
||||||
/* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
|
/* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
|
||||||
|
|
||||||
#if LWIP_MDNS_SEARCH
|
#if LWIP_MDNS_SEARCH
|
||||||
memset(mdns_requests, 0, sizeof(mdns_requests));
|
memset(mdns_requests, 0, sizeof(mdns_requests));
|
||||||
#endif
|
#endif
|
||||||
|
LWIP_MEMPOOL_INIT(MDNS_PKTS);
|
||||||
mdns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
mdns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
||||||
LWIP_ASSERT("Failed to allocate pcb", mdns_pcb != NULL);
|
LWIP_ASSERT("Failed to allocate pcb", mdns_pcb != NULL);
|
||||||
#if LWIP_MULTICAST_TX_OPTIONS
|
#if LWIP_MULTICAST_TX_OPTIONS
|
||||||
|
|
|
@ -60,6 +60,16 @@
|
||||||
#define MDNS_MAX_SERVICES 1
|
#define MDNS_MAX_SERVICES 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** The maximum number of received packets stored in chained list of known
|
||||||
|
* answers for pending truncated questions. This value define the size of
|
||||||
|
* the MDNS_PKTS mempool.
|
||||||
|
* Up to MDNS_MAX_STORED_PKTS pbuf can be stored in addition to TC questions
|
||||||
|
* that are pending.
|
||||||
|
*/
|
||||||
|
#ifndef MDNS_MAX_STORED_PKTS
|
||||||
|
#define MDNS_MAX_STORED_PKTS 4
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Payload size allocated for each outgoing UDP packet. Will be allocated with
|
/** Payload size allocated for each outgoing UDP packet. Will be allocated with
|
||||||
* PBUF_RAM and freed after packet was sent.
|
* PBUF_RAM and freed after packet was sent.
|
||||||
* According to RFC 6762, there is no reason to retain the 512 bytes restriction
|
* According to RFC 6762, there is no reason to retain the 512 bytes restriction
|
||||||
|
|
Loading…
Reference in New Issue
Block a user