|
|
|
|
@ -13,7 +13,7 @@
|
|
|
|
|
* Things left to implement: |
|
|
|
|
* ------------------------- |
|
|
|
|
* |
|
|
|
|
* - Probing/conflict resolution |
|
|
|
|
* - Tiebreaking for simultaneous probing |
|
|
|
|
* - Sending goodbye messages (zero ttl) - shutdown, DHCP lease about to expire, DHCP turned off... |
|
|
|
|
* - Checking that source address of unicast requests are on the same network |
|
|
|
|
* - Limiting multicast responses to 1 per second per resource record |
|
|
|
|
@ -63,6 +63,7 @@
|
|
|
|
|
#include "lwip/mem.h" |
|
|
|
|
#include "lwip/prot/dns.h" |
|
|
|
|
#include "lwip/prot/iana.h" |
|
|
|
|
#include "lwip/timeouts.h" |
|
|
|
|
|
|
|
|
|
#include <string.h> |
|
|
|
|
|
|
|
|
|
@ -102,6 +103,7 @@ static const ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT;
|
|
|
|
|
static u8_t mdns_netif_client_id; |
|
|
|
|
static struct udp_pcb *mdns_pcb; |
|
|
|
|
NETIF_DECLARE_EXT_CALLBACK(netif_callback) |
|
|
|
|
static mdns_name_result_cb_t mdns_name_result_cb = NULL; |
|
|
|
|
|
|
|
|
|
#define NETIF_TO_HOST(netif) (struct mdns_host*)(netif_get_client_data(netif, mdns_netif_client_id)) |
|
|
|
|
|
|
|
|
|
@ -135,6 +137,12 @@ NETIF_DECLARE_EXT_CALLBACK(netif_callback)
|
|
|
|
|
/* Lookup for text info on service instance */ |
|
|
|
|
#define REPLY_SERVICE_TXT 0x80 |
|
|
|
|
|
|
|
|
|
typedef enum { |
|
|
|
|
MDNS_PROBING_NOT_STARTED, |
|
|
|
|
MDNS_PROBING_ONGOING, |
|
|
|
|
MDNS_PROBING_COMPLETE, |
|
|
|
|
} mdns_probing_state; |
|
|
|
|
|
|
|
|
|
static const char *dnssd_protos[] = { |
|
|
|
|
"_udp", /* DNSSD_PROTO_UDP */ |
|
|
|
|
"_tcp", /* DNSSD_PROTO_TCP */ |
|
|
|
|
@ -168,6 +176,10 @@ struct mdns_host {
|
|
|
|
|
struct mdns_service *services[MDNS_MAX_SERVICES]; |
|
|
|
|
/** TTL in seconds of A/AAAA/PTR replies */ |
|
|
|
|
u32_t dns_ttl; |
|
|
|
|
/** Number of probes sent for the current name */ |
|
|
|
|
u8_t probes_sent; |
|
|
|
|
/** State in probing sequence */ |
|
|
|
|
mdns_probing_state probing_state; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/** Information about received packet */ |
|
|
|
|
@ -191,7 +203,7 @@ struct mdns_packet {
|
|
|
|
|
/** Number of unparsed questions */ |
|
|
|
|
u16_t questions_left; |
|
|
|
|
/** Number of answers in packet,
|
|
|
|
|
* (sum of normal, authorative and additional answers) |
|
|
|
|
* (sum of normal, authoritative and additional answers) |
|
|
|
|
* read from packet header */ |
|
|
|
|
u16_t answers; |
|
|
|
|
/** Number of unparsed answers */ |
|
|
|
|
@ -215,6 +227,8 @@ struct mdns_outpacket {
|
|
|
|
|
u16_t questions; |
|
|
|
|
/** Number of normal answers written */ |
|
|
|
|
u16_t answers; |
|
|
|
|
/** Number of authoritative answers written */ |
|
|
|
|
u16_t authoritative; |
|
|
|
|
/** Number of additional answers written */ |
|
|
|
|
u16_t additional; |
|
|
|
|
/** Offsets for written domain names in packet.
|
|
|
|
|
@ -261,6 +275,9 @@ struct mdns_answer {
|
|
|
|
|
u16_t rd_offset; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static err_t mdns_send_outpacket(struct mdns_outpacket *outpkt, u8_t flags); |
|
|
|
|
static void mdns_probe(void* arg); |
|
|
|
|
|
|
|
|
|
static err_t |
|
|
|
|
mdns_domain_add_label_base(struct mdns_domain *domain, u8_t len) |
|
|
|
|
{ |
|
|
|
|
@ -1279,13 +1296,14 @@ mdns_init_outpacket(struct mdns_outpacket *out, struct mdns_packet *in)
|
|
|
|
|
* Add additional answers based on the selected answers |
|
|
|
|
* Send the packet |
|
|
|
|
*/ |
|
|
|
|
static void |
|
|
|
|
mdns_send_outpacket(struct mdns_outpacket *outpkt) |
|
|
|
|
static err_t |
|
|
|
|
mdns_send_outpacket(struct mdns_outpacket *outpkt, u8_t flags) |
|
|
|
|
{ |
|
|
|
|
struct mdns_service *service; |
|
|
|
|
err_t res; |
|
|
|
|
err_t res = ERR_ARG; |
|
|
|
|
int i; |
|
|
|
|
struct mdns_host *mdns = NETIF_TO_HOST(outpkt->netif); |
|
|
|
|
u16_t answers = 0; |
|
|
|
|
|
|
|
|
|
/* Write answers to host questions */ |
|
|
|
|
#if LWIP_IPV4 |
|
|
|
|
@ -1294,14 +1312,14 @@ mdns_send_outpacket(struct mdns_outpacket *outpkt)
|
|
|
|
|
if (res != ERR_OK) { |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
outpkt->answers++; |
|
|
|
|
answers++; |
|
|
|
|
} |
|
|
|
|
if (outpkt->host_replies & REPLY_HOST_PTR_V4) { |
|
|
|
|
res = mdns_add_hostv4_ptr_answer(outpkt, outpkt->cache_flush, outpkt->netif); |
|
|
|
|
if (res != ERR_OK) { |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
outpkt->answers++; |
|
|
|
|
answers++; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
#if LWIP_IPV6 |
|
|
|
|
@ -1313,7 +1331,7 @@ mdns_send_outpacket(struct mdns_outpacket *outpkt)
|
|
|
|
|
if (res != ERR_OK) { |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
outpkt->answers++; |
|
|
|
|
answers++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -1326,7 +1344,7 @@ mdns_send_outpacket(struct mdns_outpacket *outpkt)
|
|
|
|
|
if (res != ERR_OK) { |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
outpkt->answers++; |
|
|
|
|
answers++; |
|
|
|
|
} |
|
|
|
|
addrindex++; |
|
|
|
|
rev_addrs >>= 1; |
|
|
|
|
@ -1346,7 +1364,7 @@ mdns_send_outpacket(struct mdns_outpacket *outpkt)
|
|
|
|
|
if (res != ERR_OK) { |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
outpkt->answers++; |
|
|
|
|
answers++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (outpkt->serv_replies[i] & REPLY_SERVICE_NAME_PTR) { |
|
|
|
|
@ -1354,7 +1372,7 @@ mdns_send_outpacket(struct mdns_outpacket *outpkt)
|
|
|
|
|
if (res != ERR_OK) { |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
outpkt->answers++; |
|
|
|
|
answers++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (outpkt->serv_replies[i] & REPLY_SERVICE_SRV) { |
|
|
|
|
@ -1362,7 +1380,7 @@ mdns_send_outpacket(struct mdns_outpacket *outpkt)
|
|
|
|
|
if (res != ERR_OK) { |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
outpkt->answers++; |
|
|
|
|
answers++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (outpkt->serv_replies[i] & REPLY_SERVICE_TXT) { |
|
|
|
|
@ -1370,10 +1388,17 @@ mdns_send_outpacket(struct mdns_outpacket *outpkt)
|
|
|
|
|
if (res != ERR_OK) { |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
outpkt->answers++; |
|
|
|
|
answers++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* if this is a response, the data above is anwers, else this is a probe and the answers above goes into auth section */ |
|
|
|
|
if ( flags & DNS_FLAG1_RESPONSE ) { |
|
|
|
|
outpkt->answers += answers; |
|
|
|
|
} else { |
|
|
|
|
outpkt->authoritative += answers; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* All answers written, add additional RRs */ |
|
|
|
|
for (i = 0; i < MDNS_MAX_SERVICES; ++i) { |
|
|
|
|
service = mdns->services[i]; |
|
|
|
|
@ -1439,13 +1464,12 @@ mdns_send_outpacket(struct mdns_outpacket *outpkt)
|
|
|
|
|
|
|
|
|
|
/* Write header */ |
|
|
|
|
memset(&hdr, 0, sizeof(hdr)); |
|
|
|
|
hdr.flags1 = DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE; |
|
|
|
|
hdr.flags1 = flags; |
|
|
|
|
hdr.numquestions = lwip_htons(outpkt->questions); |
|
|
|
|
hdr.numanswers = lwip_htons(outpkt->answers); |
|
|
|
|
hdr.numauthrr = lwip_htons(outpkt->authoritative); |
|
|
|
|
hdr.numextrarr = lwip_htons(outpkt->additional); |
|
|
|
|
if (outpkt->legacy_query) { |
|
|
|
|
hdr.numquestions = lwip_htons(1); |
|
|
|
|
hdr.id = lwip_htons(outpkt->tx_id); |
|
|
|
|
} |
|
|
|
|
hdr.id = lwip_htons(outpkt->tx_id); |
|
|
|
|
pbuf_take(outpkt->pbuf, &hdr, sizeof(hdr)); |
|
|
|
|
|
|
|
|
|
/* Shrink packet */ |
|
|
|
|
@ -1463,9 +1487,9 @@ mdns_send_outpacket(struct mdns_outpacket *outpkt)
|
|
|
|
|
/* Send created packet */ |
|
|
|
|
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Sending packet, len=%d, unicast=%d\n", outpkt->write_offset, outpkt->unicast_reply)); |
|
|
|
|
if (outpkt->unicast_reply) { |
|
|
|
|
udp_sendto_if(mdns_pcb, outpkt->pbuf, &outpkt->dest_addr, outpkt->dest_port, outpkt->netif); |
|
|
|
|
res = udp_sendto_if(mdns_pcb, outpkt->pbuf, &outpkt->dest_addr, outpkt->dest_port, outpkt->netif); |
|
|
|
|
} else { |
|
|
|
|
udp_sendto_if(mdns_pcb, outpkt->pbuf, mcast_destaddr, LWIP_IANA_PORT_MDNS, outpkt->netif); |
|
|
|
|
res = udp_sendto_if(mdns_pcb, outpkt->pbuf, mcast_destaddr, LWIP_IANA_PORT_MDNS, outpkt->netif); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -1474,8 +1498,10 @@ cleanup:
|
|
|
|
|
pbuf_free(outpkt->pbuf); |
|
|
|
|
outpkt->pbuf = NULL; |
|
|
|
|
} |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Send unsolicited answer containing all our known data |
|
|
|
|
* @param netif The network interface to send on |
|
|
|
|
@ -1515,7 +1541,7 @@ mdns_announce(struct netif *netif, const ip_addr_t *destination)
|
|
|
|
|
|
|
|
|
|
announce.dest_port = LWIP_IANA_PORT_MDNS; |
|
|
|
|
SMEMCPY(&announce.dest_addr, destination, sizeof(announce.dest_addr)); |
|
|
|
|
mdns_send_outpacket(&announce); |
|
|
|
|
mdns_send_outpacket(&announce, DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -1534,6 +1560,12 @@ mdns_handle_question(struct mdns_packet *pkt)
|
|
|
|
|
err_t res; |
|
|
|
|
struct mdns_host *mdns = NETIF_TO_HOST(pkt->netif); |
|
|
|
|
|
|
|
|
|
if (mdns->probing_state != MDNS_PROBING_COMPLETE) { |
|
|
|
|
/* Don't answer questions until we've verified our domains via probing */ |
|
|
|
|
/* todo we should check incoming questions during probing for tiebreaking */ |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
mdns_init_outpacket(&reply, pkt); |
|
|
|
|
|
|
|
|
|
while (pkt->questions_left) { |
|
|
|
|
@ -1569,6 +1601,7 @@ mdns_handle_question(struct mdns_packet *pkt)
|
|
|
|
|
if (replies && reply.legacy_query) { |
|
|
|
|
/* Add question to reply packet (legacy packet only has 1 question) */ |
|
|
|
|
res = mdns_add_question(&reply, &q.info.domain, q.info.type, q.info.klass, 0); |
|
|
|
|
reply.questions = 1; |
|
|
|
|
if (res != ERR_OK) { |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
@ -1724,7 +1757,7 @@ mdns_handle_question(struct mdns_packet *pkt)
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
mdns_send_outpacket(&reply); |
|
|
|
|
mdns_send_outpacket(&reply, DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE); |
|
|
|
|
|
|
|
|
|
cleanup: |
|
|
|
|
if (reply.pbuf) { |
|
|
|
|
@ -1741,6 +1774,8 @@ cleanup:
|
|
|
|
|
static void |
|
|
|
|
mdns_handle_response(struct mdns_packet *pkt) |
|
|
|
|
{ |
|
|
|
|
struct mdns_host* mdns = NETIF_TO_HOST(pkt->netif); |
|
|
|
|
|
|
|
|
|
/* Ignore all questions */ |
|
|
|
|
while (pkt->questions_left) { |
|
|
|
|
struct mdns_question q; |
|
|
|
|
@ -1766,6 +1801,39 @@ mdns_handle_response(struct mdns_packet *pkt)
|
|
|
|
|
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Answer for domain ")); |
|
|
|
|
mdns_domain_debug_print(&ans.info.domain); |
|
|
|
|
LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass)); |
|
|
|
|
|
|
|
|
|
/*"Apparently conflicting Multicast DNS responses received *before* the first probe packet is sent MUST
|
|
|
|
|
be silently ignored" so drop answer if we haven't started probing yet*/ |
|
|
|
|
if (mdns->probing_state == MDNS_PROBING_ONGOING && mdns->probes_sent > 0) { |
|
|
|
|
struct mdns_domain domain; |
|
|
|
|
u8_t i; |
|
|
|
|
u8_t conflict = 0; |
|
|
|
|
|
|
|
|
|
res = mdns_build_host_domain(&domain, mdns); |
|
|
|
|
if (res == ERR_OK && mdns_domain_eq(&ans.info.domain, &domain)) { |
|
|
|
|
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe response matches host domain!")); |
|
|
|
|
conflict = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (i = 0; i < MDNS_MAX_SERVICES; ++i) { |
|
|
|
|
struct mdns_service* service = mdns->services[i]; |
|
|
|
|
if (!service) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
res = mdns_build_service_domain(&domain, service, 1); |
|
|
|
|
if (res == ERR_OK && mdns_domain_eq(&ans.info.domain, &domain)) { |
|
|
|
|
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Probe response matches service domain!")); |
|
|
|
|
conflict = 1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (conflict != 0) { |
|
|
|
|
sys_untimeout(mdns_probe, pkt->netif); |
|
|
|
|
if (mdns_name_result_cb != NULL) { |
|
|
|
|
mdns_name_result_cb(pkt->netif, 0); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -1851,13 +1919,13 @@ mdns_netif_ext_status_callback(struct netif *netif, netif_nsc_reason_t reason, c
|
|
|
|
|
|
|
|
|
|
if (reason & LWIP_NSC_STATUS_CHANGED) { |
|
|
|
|
if (args->status_changed.state != 0) { |
|
|
|
|
mdns_resp_announce(netif); |
|
|
|
|
mdns_resp_restart(netif); |
|
|
|
|
} |
|
|
|
|
/* TODO: send goodbye message */ |
|
|
|
|
} |
|
|
|
|
if (reason & LWIP_NSC_LINK_CHANGED) { |
|
|
|
|
if (args->link_changed.state != 0) { |
|
|
|
|
mdns_resp_announce(netif); |
|
|
|
|
mdns_resp_restart(netif); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (reason & (LWIP_NSC_IPV4_ADDRESS_CHANGED | LWIP_NSC_IPV4_GATEWAY_CHANGED | |
|
|
|
|
@ -1868,10 +1936,111 @@ mdns_netif_ext_status_callback(struct netif *netif, netif_nsc_reason_t reason, c
|
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static err_t |
|
|
|
|
mdns_send_probe(struct netif* netif, const ip_addr_t *destination) |
|
|
|
|
{ |
|
|
|
|
struct mdns_host* mdns; |
|
|
|
|
struct mdns_outpacket pkt; |
|
|
|
|
struct mdns_domain domain; |
|
|
|
|
u8_t i; |
|
|
|
|
err_t res; |
|
|
|
|
|
|
|
|
|
mdns = NETIF_TO_HOST(netif); |
|
|
|
|
|
|
|
|
|
memset(&pkt, 0, sizeof(pkt)); |
|
|
|
|
pkt.netif = netif; |
|
|
|
|
|
|
|
|
|
/* Add unicast questions with rtype ANY for all our desired records */ |
|
|
|
|
mdns_build_host_domain(&domain, mdns); |
|
|
|
|
res = mdns_add_question(&pkt, &domain, DNS_RRTYPE_ANY, DNS_RRCLASS_IN, 1); |
|
|
|
|
if (res != ERR_OK) { |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
pkt.questions++; |
|
|
|
|
for (i = 0; i < MDNS_MAX_SERVICES; ++i) { |
|
|
|
|
struct mdns_service* service = mdns->services[i]; |
|
|
|
|
if (!service) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
mdns_build_service_domain(&domain, service, 1); |
|
|
|
|
res = mdns_add_question(&pkt, &domain, DNS_RRTYPE_ANY, DNS_RRCLASS_IN, 1); |
|
|
|
|
if (res != ERR_OK) { |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
pkt.questions++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Add answers to the questions above into the authority section for tiebreaking */ |
|
|
|
|
#if LWIP_IPV4 |
|
|
|
|
if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { |
|
|
|
|
pkt.host_replies = REPLY_HOST_A; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
#if LWIP_IPV6 |
|
|
|
|
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { |
|
|
|
|
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) { |
|
|
|
|
pkt.host_replies |= REPLY_HOST_AAAA; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
for (i = 0; i < MDNS_MAX_SERVICES; i++) { |
|
|
|
|
struct mdns_service *serv = mdns->services[i]; |
|
|
|
|
if (serv) { |
|
|
|
|
pkt.serv_replies[i] = REPLY_SERVICE_SRV | REPLY_SERVICE_TXT; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pkt.tx_id = 0; |
|
|
|
|
pkt.dest_port = LWIP_IANA_PORT_MDNS; |
|
|
|
|
SMEMCPY(&pkt.dest_addr, destination, sizeof(pkt.dest_addr)); |
|
|
|
|
res = mdns_send_outpacket(&pkt, 0); |
|
|
|
|
|
|
|
|
|
cleanup: |
|
|
|
|
if (pkt.pbuf) { |
|
|
|
|
pbuf_free(pkt.pbuf); |
|
|
|
|
pkt.pbuf = NULL; |
|
|
|
|
} |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Timer callback for probing network. |
|
|
|
|
*/ |
|
|
|
|
static void |
|
|
|
|
mdns_probe(void* arg) |
|
|
|
|
{ |
|
|
|
|
struct netif *netif = (struct netif *)arg; |
|
|
|
|
struct mdns_host* mdns = NETIF_TO_HOST(netif); |
|
|
|
|
|
|
|
|
|
if(mdns->probes_sent >= 3) { |
|
|
|
|
/* probing successful, announce the new name */ |
|
|
|
|
mdns->probing_state = MDNS_PROBING_COMPLETE; |
|
|
|
|
mdns_resp_announce(netif); |
|
|
|
|
if (mdns_name_result_cb != NULL) { |
|
|
|
|
mdns_name_result_cb(netif, 1); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
#if LWIP_IPV4 |
|
|
|
|
/*if ipv4 wait with probing until address is set*/ |
|
|
|
|
if (!ip4_addr_isany_val(*netif_ip4_addr(netif)) && |
|
|
|
|
mdns_send_probe(netif, IP4_ADDR_ANY) == ERR_OK) |
|
|
|
|
#endif |
|
|
|
|
{ |
|
|
|
|
#if LWIP_IPV6 |
|
|
|
|
if (mdns_send_probe(netif, IP6_ADDR_ANY) == ERR_OK) |
|
|
|
|
#endif |
|
|
|
|
{ |
|
|
|
|
mdns->probes_sent++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
sys_timeout(250, mdns_probe, netif); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @ingroup mdns |
|
|
|
|
* Activate MDNS responder for a network interface and send announce packets. |
|
|
|
|
* Don't forget to call mdns_resp_announce() after you added all netifs and services. |
|
|
|
|
* Activate MDNS responder for a network interface. |
|
|
|
|
* @param netif The network interface to activate. |
|
|
|
|
* @param hostname Name to use. Queries for <hostname>.local will be answered |
|
|
|
|
* with the IP addresses of the netif. The hostname will be copied, the |
|
|
|
|
@ -1897,6 +2066,8 @@ mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl)
|
|
|
|
|
|
|
|
|
|
MEMCPY(&mdns->name, hostname, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(hostname))); |
|
|
|
|
mdns->dns_ttl = dns_ttl; |
|
|
|
|
mdns->probes_sent = 0; |
|
|
|
|
mdns->probing_state = MDNS_PROBING_NOT_STARTED; |
|
|
|
|
|
|
|
|
|
/* Join multicast groups */ |
|
|
|
|
#if LWIP_IPV4 |
|
|
|
|
@ -1912,6 +2083,8 @@ mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl)
|
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
mdns_resp_restart(netif); |
|
|
|
|
|
|
|
|
|
return ERR_OK; |
|
|
|
|
|
|
|
|
|
cleanup: |
|
|
|
|
@ -1938,6 +2111,10 @@ mdns_resp_remove_netif(struct netif *netif)
|
|
|
|
|
mdns = NETIF_TO_HOST(netif); |
|
|
|
|
LWIP_ERROR("mdns_resp_remove_netif: Not an active netif", (mdns != NULL), return ERR_VAL); |
|
|
|
|
|
|
|
|
|
if (mdns->probing_state == MDNS_PROBING_ONGOING) { |
|
|
|
|
sys_untimeout(mdns_probe, netif); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (i = 0; i < MDNS_MAX_SERVICES; i++) { |
|
|
|
|
struct mdns_service *service = mdns->services[i]; |
|
|
|
|
if (service) { |
|
|
|
|
@ -1958,10 +2135,39 @@ mdns_resp_remove_netif(struct netif *netif)
|
|
|
|
|
return ERR_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @ingroup mdns |
|
|
|
|
* Update MDNS hostname for a network interface. |
|
|
|
|
* @param netif The network interface to activate. |
|
|
|
|
* @param hostname Name to use. Queries for <hostname>.local will be answered |
|
|
|
|
* with the IP addresses of the netif. The hostname will be copied, the |
|
|
|
|
* given pointer can be on the stack. |
|
|
|
|
* @return ERR_OK if name could be set on netif, an err_t otherwise |
|
|
|
|
*/ |
|
|
|
|
err_t |
|
|
|
|
mdns_resp_rename_netif(struct netif *netif, const char *hostname) |
|
|
|
|
{ |
|
|
|
|
struct mdns_host *mdns; |
|
|
|
|
u8_t len; |
|
|
|
|
|
|
|
|
|
LWIP_ASSERT_CORE_LOCKED(); |
|
|
|
|
len = strlen(hostname); |
|
|
|
|
LWIP_ERROR("mdns_resp_rename_netif: netif != NULL", (netif != NULL), return ERR_VAL); |
|
|
|
|
LWIP_ERROR("mdns_resp_rename_netif: Hostname too long", (len <= MDNS_LABEL_MAXLEN), return ERR_VAL); |
|
|
|
|
mdns = NETIF_TO_HOST(netif); |
|
|
|
|
LWIP_ERROR("mdns_resp_rename_netif: Not an mdns netif", (mdns != NULL), return ERR_VAL); |
|
|
|
|
|
|
|
|
|
MEMCPY(&mdns->name, hostname, len); |
|
|
|
|
mdns->name[len] = '\0'; /* null termination in case new name is shorter than previous */ |
|
|
|
|
|
|
|
|
|
mdns_resp_restart(netif); |
|
|
|
|
|
|
|
|
|
return ERR_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @ingroup mdns |
|
|
|
|
* Add a service to the selected network interface. |
|
|
|
|
* Don't forget to call mdns_resp_announce() after you added all services. |
|
|
|
|
* @param netif The network interface to publish this service on |
|
|
|
|
* @param name The name of the service |
|
|
|
|
* @param service The service type, like "_http" |
|
|
|
|
@ -2012,6 +2218,8 @@ mdns_resp_add_service(struct netif *netif, const char *name, const char *service
|
|
|
|
|
|
|
|
|
|
mdns->services[slot] = srv; |
|
|
|
|
|
|
|
|
|
mdns_resp_restart(netif); |
|
|
|
|
|
|
|
|
|
return slot; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -2039,6 +2247,40 @@ mdns_resp_del_service(struct netif *netif, s8_t slot)
|
|
|
|
|
return ERR_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @ingroup mdns |
|
|
|
|
* Update name for an MDNS service. |
|
|
|
|
* @param netif The network interface to activate. |
|
|
|
|
* @param slot The service slot number returned by mdns_resp_add_service |
|
|
|
|
* @param name The new name for the service |
|
|
|
|
* @return ERR_OK if name could be set on service, an err_t otherwise |
|
|
|
|
*/ |
|
|
|
|
err_t |
|
|
|
|
mdns_resp_rename_service(struct netif *netif, s8_t slot, const char *name) |
|
|
|
|
{ |
|
|
|
|
struct mdns_service *srv; |
|
|
|
|
struct mdns_host *mdns; |
|
|
|
|
u8_t len; |
|
|
|
|
|
|
|
|
|
LWIP_ASSERT_CORE_LOCKED(); |
|
|
|
|
len = strlen(name); |
|
|
|
|
LWIP_ASSERT("mdns_resp_rename_service: netif != NULL", netif); |
|
|
|
|
mdns = NETIF_TO_HOST(netif); |
|
|
|
|
LWIP_ERROR("mdns_resp_rename_service: Not an mdns netif", (mdns != NULL), return ERR_VAL); |
|
|
|
|
LWIP_ERROR("mdns_resp_rename_service: Name too long", (len <= MDNS_LABEL_MAXLEN), return ERR_VAL); |
|
|
|
|
LWIP_ERROR("mdns_resp_rename_service: Invalid Service ID", (slot >= 0) && (slot < MDNS_MAX_SERVICES), return ERR_VAL); |
|
|
|
|
LWIP_ERROR("mdns_resp_rename_service: Invalid Service ID", (mdns->services[slot] != NULL), return ERR_VAL); |
|
|
|
|
|
|
|
|
|
srv = mdns->services[slot]; |
|
|
|
|
|
|
|
|
|
MEMCPY(&srv->name, name, len); |
|
|
|
|
srv->name[len] = '\0'; /* null termination in case new name is shorter than previous */ |
|
|
|
|
|
|
|
|
|
mdns_resp_restart(netif); |
|
|
|
|
|
|
|
|
|
return ERR_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @ingroup mdns |
|
|
|
|
* Call this function from inside the service_get_txt_fn_t callback to add text data. |
|
|
|
|
@ -2066,22 +2308,61 @@ mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_
|
|
|
|
|
void |
|
|
|
|
mdns_resp_announce(struct netif *netif) |
|
|
|
|
{ |
|
|
|
|
struct mdns_host* mdns; |
|
|
|
|
LWIP_ASSERT_CORE_LOCKED(); |
|
|
|
|
LWIP_ERROR("mdns_resp_announce: netif != NULL", (netif != NULL), return); |
|
|
|
|
|
|
|
|
|
if (NETIF_TO_HOST(netif) == NULL) { |
|
|
|
|
mdns = NETIF_TO_HOST(netif); |
|
|
|
|
if (mdns == NULL) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Announce on IPv6 and IPv4 */ |
|
|
|
|
if (mdns->probing_state == MDNS_PROBING_COMPLETE) |
|
|
|
|
{ |
|
|
|
|
/* Announce on IPv6 and IPv4 */ |
|
|
|
|
#if LWIP_IPV6 |
|
|
|
|
mdns_announce(netif, IP6_ADDR_ANY); |
|
|
|
|
mdns_announce(netif, IP6_ADDR_ANY); |
|
|
|
|
#endif |
|
|
|
|
#if LWIP_IPV4 |
|
|
|
|
if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { |
|
|
|
|
mdns_announce(netif, IP4_ADDR_ANY); |
|
|
|
|
} |
|
|
|
|
if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { |
|
|
|
|
mdns_announce(netif, IP4_ADDR_ANY); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
} /* else: ip address changed while probing was ongoing? todo reset counter to restart? */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
mdns_resp_register_name_result_cb(mdns_name_result_cb_t cb) |
|
|
|
|
{ |
|
|
|
|
mdns_name_result_cb = cb; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @ingroup mdns |
|
|
|
|
* Restart mdns responder. Call this when cable is connected after being disconnected or |
|
|
|
|
* administrative interface is set up after being down |
|
|
|
|
* @param netif The network interface to send on |
|
|
|
|
*/ |
|
|
|
|
void |
|
|
|
|
mdns_resp_restart(struct netif *netif) |
|
|
|
|
{ |
|
|
|
|
struct mdns_host* mdns; |
|
|
|
|
LWIP_ASSERT_CORE_LOCKED(); |
|
|
|
|
LWIP_ERROR("mdns_resp_restart: netif != NULL", (netif != NULL), return); |
|
|
|
|
|
|
|
|
|
mdns = NETIF_TO_HOST(netif); |
|
|
|
|
if (mdns == NULL) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mdns->probing_state == MDNS_PROBING_ONGOING) { |
|
|
|
|
sys_untimeout(mdns_probe, netif); |
|
|
|
|
} |
|
|
|
|
/*todo first probe timeout SHOULD be random 0-250 ms*/ |
|
|
|
|
/*todo if we've failed 15 times within a 10 second period we MUST wait 5 seconds (or wait 5 seconds every time except first)*/ |
|
|
|
|
mdns->probes_sent = 0; |
|
|
|
|
mdns->probing_state = MDNS_PROBING_ONGOING; |
|
|
|
|
sys_timeout(250, mdns_probe, netif); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|