|
|
@@ -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);
|
|
|
}
|
|
|
|
|
|
/**
|