mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-12-25 18:14:53 +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 negative responses NSEC
|
||||
* - Fragmenting replies if required
|
||||
* - Handling multi-packet known answers (TC bit)
|
||||
* - Individual known answer detection for all local IPv6 addresses
|
||||
* - Dynamic size of outgoing packet
|
||||
*/
|
||||
@ -64,6 +63,7 @@
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/prot/dns.h"
|
||||
#include "lwip/prot/iana.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 (LWIP_RAND() %(MDNS_RESPONSE_DELAY_MAX - \
|
||||
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 */
|
||||
#define MDNS_PROBE_DELAY_MS 250
|
||||
@ -174,8 +179,18 @@ struct mdns_packet {
|
||||
u16_t additional;
|
||||
/** Number of unparsed additional answers */
|
||||
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_rr_info info;
|
||||
/** 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
|
||||
* - 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
|
||||
*/
|
||||
static void
|
||||
@ -1410,6 +1425,17 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
|
||||
if (res != ERR_OK) {
|
||||
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 */
|
||||
/* If it's a probe query, we need to directly answer via unicast. */
|
||||
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:
|
||||
* - 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) {
|
||||
mdns_handle_response(&packet, recv_netif);
|
||||
} 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);
|
||||
}
|
||||
|
||||
@ -2675,10 +2776,10 @@ mdns_resp_init(void)
|
||||
err_t res;
|
||||
|
||||
/* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
|
||||
|
||||
#if LWIP_MDNS_SEARCH
|
||||
memset(mdns_requests, 0, sizeof(mdns_requests));
|
||||
#endif
|
||||
LWIP_MEMPOOL_INIT(MDNS_PKTS);
|
||||
mdns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
LWIP_ASSERT("Failed to allocate pcb", mdns_pcb != NULL);
|
||||
#if LWIP_MULTICAST_TX_OPTIONS
|
||||
|
@ -60,6 +60,16 @@
|
||||
#define MDNS_MAX_SERVICES 1
|
||||
#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
|
||||
* PBUF_RAM and freed after packet was sent.
|
||||
* According to RFC 6762, there is no reason to retain the 512 bytes restriction
|
||||
|
Loading…
Reference in New Issue
Block a user