1 /**
2 * @file
3 * MDNS responder implementation - output related functionalities
4 */
5
6 /*
7 * Copyright (c) 2015 Verisure Innovation AB
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30 * OF SUCH DAMAGE.
31 *
32 * This file is part of the lwIP TCP/IP stack.
33 *
34 * Author: Erik Ekman <[email protected]>
35 * Author: Jasper Verschueren <[email protected]>
36 *
37 */
38
39 #include "lwip/apps/mdns_out.h"
40 #include "lwip/apps/mdns_priv.h"
41 #include "lwip/apps/mdns_domain.h"
42 #include "lwip/prot/dns.h"
43 #include "lwip/prot/iana.h"
44 #include "lwip/udp.h"
45
46 #include <string.h>
47
48 #if LWIP_IPV6
49 #include "lwip/prot/ip6.h"
50 #endif
51
52
53 #if LWIP_MDNS_RESPONDER
54
55 /* Payload size allocated for each outgoing UDP packet */
56 #define OUTPACKET_SIZE 500
57
58 /* Function prototypes */
59 static void mdns_clear_outmsg(struct mdns_outmsg *outmsg);
60
61 /**
62 * Call user supplied function to setup TXT data
63 * @param service The service to build TXT record for
64 */
65 void
mdns_prepare_txtdata(struct mdns_service * service)66 mdns_prepare_txtdata(struct mdns_service *service)
67 {
68 memset(&service->txtdata, 0, sizeof(struct mdns_domain));
69 if (service->txt_fn) {
70 service->txt_fn(service, service->txt_userdata);
71 }
72 }
73
74 /**
75 * Write a question to an outpacket
76 * A question contains domain, type and class. Since an answer also starts with these fields this function is also
77 * called from mdns_add_answer().
78 * @param outpkt The outpacket to write to
79 * @param domain The domain name the answer is for
80 * @param type The DNS type of the answer (like 'AAAA', 'SRV')
81 * @param klass The DNS type of the answer (like 'IN')
82 * @param unicast If highest bit in class should be set, to instruct the responder to
83 * reply with a unicast packet
84 * @return ERR_OK on success, an err_t otherwise
85 */
86 static err_t
mdns_add_question(struct mdns_outpacket * outpkt,struct mdns_domain * domain,u16_t type,u16_t klass,u16_t unicast)87 mdns_add_question(struct mdns_outpacket *outpkt, struct mdns_domain *domain,
88 u16_t type, u16_t klass, u16_t unicast)
89 {
90 u16_t question_len;
91 u16_t field16;
92 err_t res;
93
94 if (!outpkt->pbuf) {
95 /* If no pbuf is active, allocate one */
96 outpkt->pbuf = pbuf_alloc(PBUF_TRANSPORT, OUTPACKET_SIZE, PBUF_RAM);
97 if (!outpkt->pbuf) {
98 return ERR_MEM;
99 }
100 outpkt->write_offset = SIZEOF_DNS_HDR;
101 }
102
103 /* Worst case calculation. Domain string might be compressed */
104 question_len = domain->length + sizeof(type) + sizeof(klass);
105 if (outpkt->write_offset + question_len > outpkt->pbuf->tot_len) {
106 /* No space */
107 return ERR_MEM;
108 }
109
110 /* Write name */
111 res = mdns_write_domain(outpkt, domain);
112 if (res != ERR_OK) {
113 return res;
114 }
115
116 /* Write type */
117 field16 = lwip_htons(type);
118 res = pbuf_take_at(outpkt->pbuf, &field16, sizeof(field16), outpkt->write_offset);
119 if (res != ERR_OK) {
120 return res;
121 }
122 outpkt->write_offset += sizeof(field16);
123
124 /* Write class */
125 if (unicast) {
126 klass |= 0x8000;
127 }
128 field16 = lwip_htons(klass);
129 res = pbuf_take_at(outpkt->pbuf, &field16, sizeof(field16), outpkt->write_offset);
130 if (res != ERR_OK) {
131 return res;
132 }
133 outpkt->write_offset += sizeof(field16);
134
135 return ERR_OK;
136 }
137
138 /**
139 * Write answer to reply packet.
140 * buf or answer_domain can be null. The rd_length written will be buf_length +
141 * size of (compressed) domain. Most uses will need either buf or answer_domain,
142 * special case is SRV that starts with 3 u16 and then a domain name.
143 * @param reply The outpacket to write to
144 * @param domain The domain name the answer is for
145 * @param type The DNS type of the answer (like 'AAAA', 'SRV')
146 * @param klass The DNS type of the answer (like 'IN')
147 * @param cache_flush If highest bit in class should be set, to instruct receiver that
148 * this reply replaces any earlier answer for this domain/type/class
149 * @param ttl Validity time in seconds to send out for IP address data in DNS replies
150 * @param buf Pointer to buffer of answer data
151 * @param buf_length Length of variable data
152 * @param answer_domain A domain to write after any buffer data as answer
153 * @return ERR_OK on success, an err_t otherwise
154 */
155 static err_t
mdns_add_answer(struct mdns_outpacket * reply,struct mdns_domain * domain,u16_t type,u16_t klass,u16_t cache_flush,u32_t ttl,const u8_t * buf,size_t buf_length,struct mdns_domain * answer_domain)156 mdns_add_answer(struct mdns_outpacket *reply, struct mdns_domain *domain,
157 u16_t type, u16_t klass, u16_t cache_flush, u32_t ttl,
158 const u8_t *buf, size_t buf_length, struct mdns_domain *answer_domain)
159 {
160 u16_t answer_len;
161 u16_t field16;
162 u16_t rdlen_offset;
163 u16_t answer_offset;
164 u32_t field32;
165 err_t res;
166
167 if (!reply->pbuf) {
168 /* If no pbuf is active, allocate one */
169 reply->pbuf = pbuf_alloc(PBUF_TRANSPORT, OUTPACKET_SIZE, PBUF_RAM);
170 if (!reply->pbuf) {
171 return ERR_MEM;
172 }
173 reply->write_offset = SIZEOF_DNS_HDR;
174 }
175
176 /* Worst case calculation. Domain strings might be compressed */
177 answer_len = domain->length + sizeof(type) + sizeof(klass) + sizeof(ttl) + sizeof(field16)/*rd_length*/;
178 if (buf) {
179 answer_len += (u16_t)buf_length;
180 }
181 if (answer_domain) {
182 answer_len += answer_domain->length;
183 }
184 if (reply->write_offset + answer_len > reply->pbuf->tot_len) {
185 /* No space */
186 return ERR_MEM;
187 }
188
189 /* Answer starts with same data as question, then more fields */
190 mdns_add_question(reply, domain, type, klass, cache_flush);
191
192 /* Write TTL */
193 field32 = lwip_htonl(ttl);
194 res = pbuf_take_at(reply->pbuf, &field32, sizeof(field32), reply->write_offset);
195 if (res != ERR_OK) {
196 return res;
197 }
198 reply->write_offset += sizeof(field32);
199
200 /* Store offsets and skip forward to the data */
201 rdlen_offset = reply->write_offset;
202 reply->write_offset += sizeof(field16);
203 answer_offset = reply->write_offset;
204
205 if (buf) {
206 /* Write static data */
207 res = pbuf_take_at(reply->pbuf, buf, (u16_t)buf_length, reply->write_offset);
208 if (res != ERR_OK) {
209 return res;
210 }
211 reply->write_offset += (u16_t)buf_length;
212 }
213
214 if (answer_domain) {
215 /* Write name answer (compressed if possible) */
216 res = mdns_write_domain(reply, answer_domain);
217 if (res != ERR_OK) {
218 return res;
219 }
220 }
221
222 /* Write rd_length after when we know the answer size */
223 field16 = lwip_htons(reply->write_offset - answer_offset);
224 res = pbuf_take_at(reply->pbuf, &field16, sizeof(field16), rdlen_offset);
225
226 return res;
227 }
228
229 /** Write an ANY host question to outpacket */
230 static err_t
mdns_add_any_host_question(struct mdns_outpacket * outpkt,struct mdns_host * mdns,u16_t request_unicast_reply)231 mdns_add_any_host_question(struct mdns_outpacket *outpkt,
232 struct mdns_host *mdns,
233 u16_t request_unicast_reply)
234 {
235 struct mdns_domain host;
236 mdns_build_host_domain(&host, mdns);
237 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Adding host question for ANY type\n"));
238 return mdns_add_question(outpkt, &host, DNS_RRTYPE_ANY, DNS_RRCLASS_IN,
239 request_unicast_reply);
240 }
241
242 /** Write an ANY service instance question to outpacket */
243 static err_t
mdns_add_any_service_question(struct mdns_outpacket * outpkt,struct mdns_service * service,u16_t request_unicast_reply)244 mdns_add_any_service_question(struct mdns_outpacket *outpkt,
245 struct mdns_service *service,
246 u16_t request_unicast_reply)
247 {
248 struct mdns_domain domain;
249 mdns_build_service_domain(&domain, service, 1);
250 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Adding service instance question for ANY type\n"));
251 return mdns_add_question(outpkt, &domain, DNS_RRTYPE_ANY, DNS_RRCLASS_IN,
252 request_unicast_reply);
253 }
254
255 #if LWIP_IPV4
256 /** Write an IPv4 address (A) RR to outpacket */
257 static err_t
mdns_add_a_answer(struct mdns_outpacket * reply,struct mdns_outmsg * msg,struct netif * netif)258 mdns_add_a_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg,
259 struct netif *netif)
260 {
261 err_t res;
262 u32_t ttl = MDNS_TTL_120;
263 struct mdns_domain host;
264 mdns_build_host_domain(&host, netif_mdns_data(netif));
265 /* When answering to a legacy querier, we need to repeat the question and
266 * limit the ttl to the short legacy ttl */
267 if(msg->legacy_query) {
268 /* Repeating the question only needs to be done for the question asked
269 * (max one question), not for the additional records. */
270 if(reply->questions < 1) {
271 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n"));
272 res = mdns_add_question(reply, &host, DNS_RRTYPE_A, DNS_RRCLASS_IN, 0);
273 if (res != ERR_OK) {
274 return res;
275 }
276 reply->questions = 1;
277 }
278 /* ttl of legacy answer may not be greater then 10 seconds */
279 ttl = MDNS_TTL_10;
280 }
281 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with A record\n"));
282 return mdns_add_answer(reply, &host, DNS_RRTYPE_A, DNS_RRCLASS_IN, msg->cache_flush,
283 ttl, (const u8_t *) netif_ip4_addr(netif),
284 sizeof(ip4_addr_t), NULL);
285 }
286
287 /** Write a 4.3.2.1.in-addr.arpa -> hostname.local PTR RR to outpacket */
288 static err_t
mdns_add_hostv4_ptr_answer(struct mdns_outpacket * reply,struct mdns_outmsg * msg,struct netif * netif)289 mdns_add_hostv4_ptr_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg,
290 struct netif *netif)
291 {
292 err_t res;
293 u32_t ttl = MDNS_TTL_120;
294 struct mdns_domain host, revhost;
295 mdns_build_host_domain(&host, netif_mdns_data(netif));
296 mdns_build_reverse_v4_domain(&revhost, netif_ip4_addr(netif));
297 /* When answering to a legacy querier, we need to repeat the question and
298 * limit the ttl to the short legacy ttl */
299 if(msg->legacy_query) {
300 /* Repeating the question only needs to be done for the question asked
301 * (max one question), not for the additional records. */
302 if(reply->questions < 1) {
303 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n"));
304 res = mdns_add_question(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0);
305 if (res != ERR_OK) {
306 return res;
307 }
308 reply->questions = 1;
309 }
310 /* ttl of legacy answer may not be greater then 10 seconds */
311 ttl = MDNS_TTL_10;
312 }
313 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with v4 PTR record\n"));
314 return mdns_add_answer(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN,
315 msg->cache_flush, ttl, NULL, 0, &host);
316 }
317 #endif
318
319 #if LWIP_IPV6
320 /** Write an IPv6 address (AAAA) RR to outpacket */
321 static err_t
mdns_add_aaaa_answer(struct mdns_outpacket * reply,struct mdns_outmsg * msg,struct netif * netif,int addrindex)322 mdns_add_aaaa_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg,
323 struct netif *netif, int addrindex)
324 {
325 err_t res;
326 u32_t ttl = MDNS_TTL_120;
327 struct mdns_domain host;
328 mdns_build_host_domain(&host, netif_mdns_data(netif));
329 /* When answering to a legacy querier, we need to repeat the question and
330 * limit the ttl to the short legacy ttl */
331 if(msg->legacy_query) {
332 /* Repeating the question only needs to be done for the question asked
333 * (max one question), not for the additional records. */
334 if(reply->questions < 1) {
335 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n"));
336 res = mdns_add_question(reply, &host, DNS_RRTYPE_AAAA, DNS_RRCLASS_IN, 0);
337 if (res != ERR_OK) {
338 return res;
339 }
340 reply->questions = 1;
341 }
342 /* ttl of legacy answer may not be greater then 10 seconds */
343 ttl = MDNS_TTL_10;
344 }
345 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with AAAA record\n"));
346 return mdns_add_answer(reply, &host, DNS_RRTYPE_AAAA, DNS_RRCLASS_IN, msg->cache_flush,
347 ttl, (const u8_t *) netif_ip6_addr(netif, addrindex),
348 sizeof(ip6_addr_p_t), NULL);
349 }
350
351 /** Write a x.y.z.ip6.arpa -> hostname.local PTR RR to outpacket */
352 static err_t
mdns_add_hostv6_ptr_answer(struct mdns_outpacket * reply,struct mdns_outmsg * msg,struct netif * netif,int addrindex)353 mdns_add_hostv6_ptr_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg,
354 struct netif *netif, int addrindex)
355 {
356 err_t res;
357 u32_t ttl = MDNS_TTL_120;
358 struct mdns_domain host, revhost;
359 mdns_build_host_domain(&host, netif_mdns_data(netif));
360 mdns_build_reverse_v6_domain(&revhost, netif_ip6_addr(netif, addrindex));
361 /* When answering to a legacy querier, we need to repeat the question and
362 * limit the ttl to the short legacy ttl */
363 if(msg->legacy_query) {
364 /* Repeating the question only needs to be done for the question asked
365 * (max one question), not for the additional records. */
366 if(reply->questions < 1) {
367 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n"));
368 res = mdns_add_question(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0);
369 if (res != ERR_OK) {
370 return res;
371 }
372 reply->questions = 1;
373 }
374 /* ttl of legacy answer may not be greater then 10 seconds */
375 ttl = MDNS_TTL_10;
376 }
377 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with v6 PTR record\n"));
378 return mdns_add_answer(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN,
379 msg->cache_flush, ttl, NULL, 0, &host);
380 }
381 #endif
382
383 /** Write an all-services -> servicetype PTR RR to outpacket */
384 static err_t
mdns_add_servicetype_ptr_answer(struct mdns_outpacket * reply,struct mdns_outmsg * msg,struct mdns_service * service)385 mdns_add_servicetype_ptr_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg,
386 struct mdns_service *service)
387 {
388 err_t res;
389 u32_t ttl = MDNS_TTL_4500;
390 struct mdns_domain service_type, service_dnssd;
391 mdns_build_service_domain(&service_type, service, 0);
392 mdns_build_dnssd_domain(&service_dnssd);
393 /* When answering to a legacy querier, we need to repeat the question and
394 * limit the ttl to the short legacy ttl */
395 if(msg->legacy_query) {
396 /* Repeating the question only needs to be done for the question asked
397 * (max one question), not for the additional records. */
398 if(reply->questions < 1) {
399 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n"));
400 res = mdns_add_question(reply, &service_dnssd, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0);
401 if (res != ERR_OK) {
402 return res;
403 }
404 reply->questions = 1;
405 }
406 /* ttl of legacy answer may not be greater then 10 seconds */
407 ttl = MDNS_TTL_10;
408 }
409 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with service type PTR record\n"));
410 return mdns_add_answer(reply, &service_dnssd, DNS_RRTYPE_PTR, DNS_RRCLASS_IN,
411 0, ttl, NULL, 0, &service_type);
412 }
413
414 /** Write a servicetype -> servicename PTR RR to outpacket */
415 static err_t
mdns_add_servicename_ptr_answer(struct mdns_outpacket * reply,struct mdns_outmsg * msg,struct mdns_service * service)416 mdns_add_servicename_ptr_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg,
417 struct mdns_service *service)
418 {
419 err_t res;
420 u32_t ttl = MDNS_TTL_120;
421 struct mdns_domain service_type, service_instance;
422 mdns_build_service_domain(&service_type, service, 0);
423 mdns_build_service_domain(&service_instance, service, 1);
424 /* When answering to a legacy querier, we need to repeat the question and
425 * limit the ttl to the short legacy ttl */
426 if(msg->legacy_query) {
427 /* Repeating the question only needs to be done for the question asked
428 * (max one question), not for the additional records. */
429 if(reply->questions < 1) {
430 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n"));
431 res = mdns_add_question(reply, &service_type, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0);
432 if (res != ERR_OK) {
433 return res;
434 }
435 reply->questions = 1;
436 }
437 /* ttl of legacy answer may not be greater then 10 seconds */
438 ttl = MDNS_TTL_10;
439 }
440 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with service name PTR record\n"));
441 return mdns_add_answer(reply, &service_type, DNS_RRTYPE_PTR, DNS_RRCLASS_IN,
442 0, ttl, NULL, 0, &service_instance);
443 }
444
445 /** Write a SRV RR to outpacket */
446 static err_t
mdns_add_srv_answer(struct mdns_outpacket * reply,struct mdns_outmsg * msg,struct mdns_host * mdns,struct mdns_service * service)447 mdns_add_srv_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg,
448 struct mdns_host *mdns, struct mdns_service *service)
449 {
450 err_t res;
451 u32_t ttl = MDNS_TTL_120;
452 struct mdns_domain service_instance, srvhost;
453 u16_t srvdata[3];
454 mdns_build_service_domain(&service_instance, service, 1);
455 mdns_build_host_domain(&srvhost, mdns);
456 if (msg->legacy_query) {
457 /* RFC 6762 section 18.14:
458 * In legacy unicast responses generated to answer legacy queries,
459 * name compression MUST NOT be performed on SRV records.
460 */
461 srvhost.skip_compression = 1;
462 /* When answering to a legacy querier, we need to repeat the question and
463 * limit the ttl to the short legacy ttl.
464 * Repeating the question only needs to be done for the question asked
465 * (max one question), not for the additional records. */
466 if(reply->questions < 1) {
467 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n"));
468 res = mdns_add_question(reply, &service_instance, DNS_RRTYPE_SRV, DNS_RRCLASS_IN, 0);
469 if (res != ERR_OK) {
470 return res;
471 }
472 reply->questions = 1;
473 }
474 /* ttl of legacy answer may not be greater then 10 seconds */
475 ttl = MDNS_TTL_10;
476 }
477 srvdata[0] = lwip_htons(SRV_PRIORITY);
478 srvdata[1] = lwip_htons(SRV_WEIGHT);
479 srvdata[2] = lwip_htons(service->port);
480 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with SRV record\n"));
481 return mdns_add_answer(reply, &service_instance, DNS_RRTYPE_SRV, DNS_RRCLASS_IN,
482 msg->cache_flush, ttl,
483 (const u8_t *) &srvdata, sizeof(srvdata), &srvhost);
484 }
485
486 /** Write a TXT RR to outpacket */
487 static err_t
mdns_add_txt_answer(struct mdns_outpacket * reply,struct mdns_outmsg * msg,struct mdns_service * service)488 mdns_add_txt_answer(struct mdns_outpacket *reply, struct mdns_outmsg *msg,
489 struct mdns_service *service)
490 {
491 err_t res;
492 u32_t ttl = MDNS_TTL_120;
493 struct mdns_domain service_instance;
494 mdns_build_service_domain(&service_instance, service, 1);
495 mdns_prepare_txtdata(service);
496 /* When answering to a legacy querier, we need to repeat the question and
497 * limit the ttl to the short legacy ttl */
498 if(msg->legacy_query) {
499 /* Repeating the question only needs to be done for the question asked
500 * (max one question), not for the additional records. */
501 if(reply->questions < 1) {
502 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Add question for legacy query\n"));
503 res = mdns_add_question(reply, &service_instance, DNS_RRTYPE_TXT, DNS_RRCLASS_IN, 0);
504 if (res != ERR_OK) {
505 return res;
506 }
507 reply->questions = 1;
508 }
509 /* ttl of legacy answer may not be greater then 10 seconds */
510 ttl = MDNS_TTL_10;
511 }
512 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with TXT record\n"));
513 return mdns_add_answer(reply, &service_instance, DNS_RRTYPE_TXT, DNS_RRCLASS_IN,
514 msg->cache_flush, ttl, (u8_t *) &service->txtdata.name,
515 service->txtdata.length, NULL);
516 }
517
518
519 static err_t
mdns_add_probe_questions_to_outpacket(struct mdns_outpacket * outpkt,struct mdns_outmsg * msg,struct netif * netif)520 mdns_add_probe_questions_to_outpacket(struct mdns_outpacket *outpkt, struct mdns_outmsg *msg,
521 struct netif *netif)
522 {
523 err_t res;
524 int i;
525 struct mdns_host *mdns = netif_mdns_data(netif);
526
527 /* Write host questions (probing or legacy query) */
528 if(msg->host_questions & QUESTION_PROBE_HOST_ANY) {
529 res = mdns_add_any_host_question(outpkt, mdns, 1);
530 if (res != ERR_OK) {
531 return res;
532 }
533 outpkt->questions++;
534 }
535 /* Write service questions (probing or legacy query) */
536 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
537 struct mdns_service* service = mdns->services[i];
538 if (!service) {
539 continue;
540 }
541 if(msg->serv_questions[i] & QUESTION_PROBE_SERVICE_NAME_ANY) {
542 res = mdns_add_any_service_question(outpkt, service, 1);
543 if (res != ERR_OK) {
544 return res;
545 }
546 outpkt->questions++;
547 }
548 }
549 return ERR_OK;
550 }
551
552 #if LWIP_MDNS_SEARCH
553 static err_t
mdns_add_query_question_to_outpacket(struct mdns_outpacket * outpkt,struct mdns_outmsg * msg)554 mdns_add_query_question_to_outpacket(struct mdns_outpacket *outpkt, struct mdns_outmsg *msg)
555 {
556 err_t res;
557 /* Write legacy query question */
558 if(msg->query) {
559 struct mdns_request *req = msg->query;
560 struct mdns_domain dom;
561 /* Build question domain */
562 mdns_build_request_domain(&dom, req, req->name[0]);
563 /* Add query question to output packet */
564 res = mdns_add_question(outpkt, &dom, req->qtype, DNS_RRCLASS_IN, 0);
565 if (res != ERR_OK) {
566 return res;
567 }
568 outpkt->questions++;
569 }
570 return ERR_OK;
571 }
572 #endif
573
574 /**
575 * Create packet with chosen answers as a reply
576 *
577 * Add all selected answers / questions
578 * Add additional answers based on the selected answers
579 */
580 err_t
mdns_create_outpacket(struct netif * netif,struct mdns_outmsg * msg,struct mdns_outpacket * outpkt)581 mdns_create_outpacket(struct netif *netif, struct mdns_outmsg *msg,
582 struct mdns_outpacket *outpkt)
583 {
584 struct mdns_host *mdns = netif_mdns_data(netif);
585 struct mdns_service *service;
586 err_t res;
587 int i;
588 u16_t answers = 0;
589
590 #if LWIP_MDNS_SEARCH
591 res = mdns_add_query_question_to_outpacket(outpkt, msg);
592 if (res != ERR_OK) {
593 return res;
594 }
595 #endif
596
597 res = mdns_add_probe_questions_to_outpacket(outpkt, msg, netif);
598 if (res != ERR_OK) {
599 return res;
600 }
601
602 /* Write answers to host questions */
603 #if LWIP_IPV4
604 if (msg->host_replies & REPLY_HOST_A) {
605 res = mdns_add_a_answer(outpkt, msg, netif);
606 if (res != ERR_OK) {
607 return res;
608 }
609 answers++;
610 }
611 if (msg->host_replies & REPLY_HOST_PTR_V4) {
612 res = mdns_add_hostv4_ptr_answer(outpkt, msg, netif);
613 if (res != ERR_OK) {
614 return res;
615 }
616 answers++;
617 }
618 #endif
619 #if LWIP_IPV6
620 if (msg->host_replies & REPLY_HOST_AAAA) {
621 int addrindex;
622 for (addrindex = 0; addrindex < LWIP_IPV6_NUM_ADDRESSES; addrindex++) {
623 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addrindex))) {
624 res = mdns_add_aaaa_answer(outpkt, msg, netif, addrindex);
625 if (res != ERR_OK) {
626 return res;
627 }
628 answers++;
629 }
630 }
631 }
632 if (msg->host_replies & REPLY_HOST_PTR_V6) {
633 u8_t rev_addrs = msg->host_reverse_v6_replies;
634 int addrindex = 0;
635 while (rev_addrs) {
636 if (rev_addrs & 1) {
637 res = mdns_add_hostv6_ptr_answer(outpkt, msg, netif, addrindex);
638 if (res != ERR_OK) {
639 return res;
640 }
641 answers++;
642 }
643 addrindex++;
644 rev_addrs >>= 1;
645 }
646 }
647 #endif
648
649 /* Write answers to service questions */
650 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
651 service = mdns->services[i];
652 if (!service) {
653 continue;
654 }
655
656 if (msg->serv_replies[i] & REPLY_SERVICE_TYPE_PTR) {
657 res = mdns_add_servicetype_ptr_answer(outpkt, msg, service);
658 if (res != ERR_OK) {
659 return res;
660 }
661 answers++;
662 }
663
664 if (msg->serv_replies[i] & REPLY_SERVICE_NAME_PTR) {
665 res = mdns_add_servicename_ptr_answer(outpkt, msg, service);
666 if (res != ERR_OK) {
667 return res;
668 }
669 answers++;
670 }
671
672 if (msg->serv_replies[i] & REPLY_SERVICE_SRV) {
673 res = mdns_add_srv_answer(outpkt, msg, mdns, service);
674 if (res != ERR_OK) {
675 return res;
676 }
677 answers++;
678 }
679
680 if (msg->serv_replies[i] & REPLY_SERVICE_TXT) {
681 res = mdns_add_txt_answer(outpkt, msg, service);
682 if (res != ERR_OK) {
683 return res;
684 }
685 answers++;
686 }
687 }
688
689 /* if this is a response, the data above is anwers, else this is a probe and
690 * the answers above goes into auth section */
691 if (msg->flags & DNS_FLAG1_RESPONSE) {
692 outpkt->answers += answers;
693 } else {
694 outpkt->authoritative += answers;
695 }
696
697 /* All answers written, add additional RRs */
698 for (i = 0; i < MDNS_MAX_SERVICES; i++) {
699 service = mdns->services[i];
700 if (!service) {
701 continue;
702 }
703
704 if (msg->serv_replies[i] & REPLY_SERVICE_NAME_PTR) {
705 /* Our service instance requested, include SRV & TXT
706 * if they are already not requested. */
707 if (!(msg->serv_replies[i] & REPLY_SERVICE_SRV)) {
708 res = mdns_add_srv_answer(outpkt, msg, mdns, service);
709 if (res != ERR_OK) {
710 return res;
711 }
712 outpkt->additional++;
713 }
714
715 if (!(msg->serv_replies[i] & REPLY_SERVICE_TXT)) {
716 res = mdns_add_txt_answer(outpkt, msg, service);
717 if (res != ERR_OK) {
718 return res;
719 }
720 outpkt->additional++;
721 }
722 }
723
724 /* If service instance, SRV, record or an IP address is requested,
725 * supply all addresses for the host
726 */
727 if ((msg->serv_replies[i] & (REPLY_SERVICE_NAME_PTR | REPLY_SERVICE_SRV)) ||
728 (msg->host_replies & (REPLY_HOST_A | REPLY_HOST_AAAA))) {
729 #if LWIP_IPV6
730 if (!(msg->host_replies & REPLY_HOST_AAAA)) {
731 int addrindex;
732 for (addrindex = 0; addrindex < LWIP_IPV6_NUM_ADDRESSES; addrindex++) {
733 if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addrindex))) {
734 res = mdns_add_aaaa_answer(outpkt, msg, netif, addrindex);
735 if (res != ERR_OK) {
736 return res;
737 }
738 outpkt->additional++;
739 }
740 }
741 }
742 #endif
743 #if LWIP_IPV4
744 if (!(msg->host_replies & REPLY_HOST_A) &&
745 !ip4_addr_isany_val(*netif_ip4_addr(netif))) {
746 res = mdns_add_a_answer(outpkt, msg, netif);
747 if (res != ERR_OK) {
748 return res;
749 }
750 outpkt->additional++;
751 }
752 #endif
753 }
754 }
755
756 return res;
757 }
758
759 /**
760 * Send chosen answers as a reply
761 *
762 * Create the packet
763 * Send the packet
764 */
765 err_t
mdns_send_outpacket(struct mdns_outmsg * msg,struct netif * netif)766 mdns_send_outpacket(struct mdns_outmsg *msg, struct netif *netif)
767 {
768 struct mdns_outpacket outpkt;
769 err_t res;
770
771 memset(&outpkt, 0, sizeof(outpkt));
772
773 res = mdns_create_outpacket(netif, msg, &outpkt);
774 if (res != ERR_OK) {
775 goto cleanup;
776 }
777
778 if (outpkt.pbuf) {
779 struct dns_hdr hdr;
780
781 /* Write header */
782 memset(&hdr, 0, sizeof(hdr));
783 hdr.flags1 = msg->flags;
784 hdr.numquestions = lwip_htons(outpkt.questions);
785 hdr.numanswers = lwip_htons(outpkt.answers);
786 hdr.numauthrr = lwip_htons(outpkt.authoritative);
787 hdr.numextrarr = lwip_htons(outpkt.additional);
788 hdr.id = lwip_htons(msg->tx_id);
789 pbuf_take(outpkt.pbuf, &hdr, sizeof(hdr));
790
791 /* Shrink packet */
792 pbuf_realloc(outpkt.pbuf, outpkt.write_offset);
793
794 /* Send created packet */
795 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Sending packet, len=%d\n",
796 outpkt.write_offset));
797
798 res = udp_sendto_if(get_mdns_pcb(), outpkt.pbuf, &msg->dest_addr, msg->dest_port, netif);
799 }
800
801 cleanup:
802 if (outpkt.pbuf) {
803 pbuf_free(outpkt.pbuf);
804 outpkt.pbuf = NULL;
805 }
806 return res;
807 }
808
809 #if LWIP_IPV4
810 /**
811 * Called by timeouts when timer is passed, allows multicast IPv4 traffic again.
812 *
813 * @param arg pointer to netif of timeout.
814 */
815 void
mdns_multicast_timeout_reset_ipv4(void * arg)816 mdns_multicast_timeout_reset_ipv4(void *arg)
817 {
818 struct netif *netif = (struct netif*)arg;
819 struct mdns_host *mdns = netif_mdns_data(netif);
820
821 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout finished - IPv4\n"));
822
823 mdns->ipv4.multicast_timeout = 0;
824 }
825
826 /**
827 * Called by timeouts when timer is passed, allows direct multicast IPv4 probe
828 * response traffic again and sends out probe response if one was pending
829 *
830 * @param arg pointer to netif of timeout.
831 */
832 void
mdns_multicast_probe_timeout_reset_ipv4(void * arg)833 mdns_multicast_probe_timeout_reset_ipv4(void *arg)
834 {
835 struct netif *netif = (struct netif*)arg;
836 struct mdns_host *mdns = netif_mdns_data(netif);
837 err_t res;
838
839 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout finished - IPv4\n"));
840
841 mdns->ipv4.multicast_probe_timeout = 0;
842
843 if (mdns->ipv4.multicast_msg_waiting) {
844 res = mdns_send_outpacket(&mdns->ipv4.delayed_msg_multicast, netif);
845 if(res != ERR_OK) {
846 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send failed - IPv4\n"));
847 }
848 else {
849 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send successful - IPv4\n"));
850 mdns_clear_outmsg(&mdns->ipv4.delayed_msg_multicast);
851 mdns->ipv4.multicast_msg_waiting = 0;
852 mdns_start_multicast_timeouts_ipv4(netif);
853 }
854 }
855 }
856
857 /**
858 * Called by timeouts when timer is passed, allows to send an answer on a QU
859 * question via multicast.
860 *
861 * @param arg pointer to netif of timeout.
862 */
863 void
mdns_multicast_timeout_25ttl_reset_ipv4(void * arg)864 mdns_multicast_timeout_25ttl_reset_ipv4(void *arg)
865 {
866 struct netif *netif = (struct netif*)arg;
867 struct mdns_host *mdns = netif_mdns_data(netif);
868
869 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl finished - IPv4\n"));
870
871 mdns->ipv4.multicast_timeout_25TTL = 0;
872 }
873
874 /**
875 * Called by timeouts when timer is passed, sends out delayed multicast IPv4 response.
876 *
877 * @param arg pointer to netif of timeout.
878 */
879 void
mdns_send_multicast_msg_delayed_ipv4(void * arg)880 mdns_send_multicast_msg_delayed_ipv4(void *arg)
881 {
882 struct netif *netif = (struct netif*)arg;
883 struct mdns_host *mdns = netif_mdns_data(netif);
884 err_t res;
885
886 res = mdns_send_outpacket(&mdns->ipv4.delayed_msg_multicast, netif);
887 if(res != ERR_OK) {
888 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed multicast send failed - IPv4\n"));
889 }
890 else {
891 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed multicast send successful - IPv4\n"));
892 mdns_clear_outmsg(&mdns->ipv4.delayed_msg_multicast);
893 mdns->ipv4.multicast_msg_waiting = 0;
894 mdns_start_multicast_timeouts_ipv4(netif);
895 }
896 }
897
898 /**
899 * Called by timeouts when timer is passed, sends out delayed unicast IPv4 response.
900 *
901 * @param arg pointer to netif of timeout.
902 */
903 void
mdns_send_unicast_msg_delayed_ipv4(void * arg)904 mdns_send_unicast_msg_delayed_ipv4(void *arg)
905 {
906 struct netif *netif = (struct netif*)arg;
907 struct mdns_host *mdns = netif_mdns_data(netif);
908 err_t res;
909
910 res = mdns_send_outpacket(&mdns->ipv4.delayed_msg_unicast, netif);
911 if(res != ERR_OK) {
912 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed unicast send failed - IPv4\n"));
913 }
914 else {
915 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed unicast send successful - IPv4\n"));
916 mdns_clear_outmsg(&mdns->ipv4.delayed_msg_unicast);
917 mdns->ipv4.unicast_msg_in_use = 0;
918 }
919 }
920
921 /** Start all multicast timeouts for IPv4
922 * Timeouts started:
923 * - do not multicast within one second
924 * - do not multicast a probe response within 250ms
925 * - send a multicast answer on a QU question if not send recently.
926 *
927 * @param netif network interface to start timeouts on
928 */
929 void
mdns_start_multicast_timeouts_ipv4(struct netif * netif)930 mdns_start_multicast_timeouts_ipv4(struct netif *netif)
931 {
932 struct mdns_host *mdns = netif_mdns_data(netif);
933
934 mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv4,
935 &mdns->ipv4.multicast_timeout);
936 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv4\n"));
937 mdns_set_timeout(netif, MDNS_MULTICAST_PROBE_TIMEOUT, mdns_multicast_probe_timeout_reset_ipv4,
938 &mdns->ipv4.multicast_probe_timeout);
939 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout started - IPv4\n"));
940 mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv4,
941 &mdns->ipv4.multicast_timeout_25TTL);
942 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv4\n"));
943 }
944 #endif
945
946 #if LWIP_IPV6
947 /**
948 * Called by timeouts when timer is passed, allows multicast IPv6 traffic again.
949 *
950 * @param arg pointer to netif of timeout.
951 */
952 void
mdns_multicast_timeout_reset_ipv6(void * arg)953 mdns_multicast_timeout_reset_ipv6(void *arg)
954 {
955 struct netif *netif = (struct netif*)arg;
956 struct mdns_host *mdns = netif_mdns_data(netif);
957
958 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout finished - IPv6\n"));
959
960 mdns->ipv6.multicast_timeout = 0;
961 }
962
963 /**
964 * Called by timeouts when timer is passed, allows direct multicast IPv6 probe
965 * response traffic again and sends out probe response if one was pending
966 *
967 * @param arg pointer to netif of timeout.
968 */
969 void
mdns_multicast_probe_timeout_reset_ipv6(void * arg)970 mdns_multicast_probe_timeout_reset_ipv6(void *arg)
971 {
972 struct netif *netif = (struct netif*)arg;
973 struct mdns_host *mdns = netif_mdns_data(netif);
974 err_t res;
975
976 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout finished - IPv6\n"));
977
978 mdns->ipv6.multicast_probe_timeout = 0;
979
980 if (mdns->ipv6.multicast_msg_waiting) {
981 res = mdns_send_outpacket(&mdns->ipv6.delayed_msg_multicast, netif);
982 if(res != ERR_OK) {
983 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send failed - IPv6\n"));
984 }
985 else {
986 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send successful - IPv6\n"));
987 mdns_clear_outmsg(&mdns->ipv6.delayed_msg_multicast);
988 mdns->ipv6.multicast_msg_waiting = 0;
989 mdns_start_multicast_timeouts_ipv6(netif);
990 }
991 }
992 }
993
994 /**
995 * Called by timeouts when timer is passed, allows to send an answer on a QU
996 * question via multicast.
997 *
998 * @param arg pointer to netif of timeout.
999 */
1000 void
mdns_multicast_timeout_25ttl_reset_ipv6(void * arg)1001 mdns_multicast_timeout_25ttl_reset_ipv6(void *arg)
1002 {
1003 struct netif *netif = (struct netif*)arg;
1004 struct mdns_host *mdns = netif_mdns_data(netif);
1005
1006 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl finished - IPv6\n"));
1007
1008 mdns->ipv6.multicast_timeout_25TTL = 0;
1009 }
1010
1011 /**
1012 * Called by timeouts when timer is passed, sends out delayed multicast IPv6 response.
1013 *
1014 * @param arg pointer to netif of timeout.
1015 */
1016 void
mdns_send_multicast_msg_delayed_ipv6(void * arg)1017 mdns_send_multicast_msg_delayed_ipv6(void *arg)
1018 {
1019 struct netif *netif = (struct netif*)arg;
1020 struct mdns_host *mdns = netif_mdns_data(netif);
1021 err_t res;
1022
1023 res = mdns_send_outpacket(&mdns->ipv6.delayed_msg_multicast, netif);
1024 if(res != ERR_OK) {
1025 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed multicast send failed - IPv6\n"));
1026 }
1027 else {
1028 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed multicast send successful - IPv6\n"));
1029 mdns_clear_outmsg(&mdns->ipv6.delayed_msg_multicast);
1030 mdns->ipv6.multicast_msg_waiting = 0;
1031 mdns_start_multicast_timeouts_ipv6(netif);
1032 }
1033 }
1034
1035 /**
1036 * Called by timeouts when timer is passed, sends out delayed unicast IPv6 response.
1037 *
1038 * @param arg pointer to netif of timeout.
1039 */
1040 void
mdns_send_unicast_msg_delayed_ipv6(void * arg)1041 mdns_send_unicast_msg_delayed_ipv6(void *arg)
1042 {
1043 struct netif *netif = (struct netif*)arg;
1044 struct mdns_host *mdns = netif_mdns_data(netif);
1045 err_t res;
1046
1047 res = mdns_send_outpacket(&mdns->ipv6.delayed_msg_unicast, netif);
1048 if(res != ERR_OK) {
1049 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed unicast send failed - IPv6\n"));
1050 }
1051 else {
1052 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed unicast send successful - IPv6\n"));
1053 mdns_clear_outmsg(&mdns->ipv6.delayed_msg_unicast);
1054 mdns->ipv6.unicast_msg_in_use = 0;
1055 }
1056 }
1057
1058 /** Start all multicast timeouts for IPv6
1059 * Timeouts started:
1060 * - do not multicast within one second
1061 * - do not multicast a probe response within 250ms
1062 * - send a multicast answer on a QU question if not send recently.
1063 *
1064 * @param netif network interface to start timeouts on
1065 */
1066 void
mdns_start_multicast_timeouts_ipv6(struct netif * netif)1067 mdns_start_multicast_timeouts_ipv6(struct netif *netif)
1068 {
1069 struct mdns_host *mdns = netif_mdns_data(netif);
1070
1071 mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv6,
1072 &mdns->ipv6.multicast_timeout);
1073 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv6\n"));
1074 mdns_set_timeout(netif, MDNS_MULTICAST_PROBE_TIMEOUT, mdns_multicast_probe_timeout_reset_ipv6,
1075 &mdns->ipv6.multicast_probe_timeout);
1076 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout started - IPv6\n"));
1077 mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv6,
1078 &mdns->ipv6.multicast_timeout_25TTL);
1079 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv6\n"));
1080 }
1081 #endif
1082
1083 /**
1084 * This function clears the output message without changing the destination
1085 * address or port. This is useful for clearing the delayed msg structs without
1086 * loosing the set IP.
1087 *
1088 * @param outmsg pointer to output message to clear.
1089 */
1090 static void
mdns_clear_outmsg(struct mdns_outmsg * outmsg)1091 mdns_clear_outmsg(struct mdns_outmsg *outmsg)
1092 {
1093 int i;
1094
1095 outmsg->tx_id = 0;
1096 outmsg->flags = 0;
1097 outmsg->cache_flush = 0;
1098 outmsg->unicast_reply_requested = 0;
1099 outmsg->legacy_query = 0;
1100 outmsg->probe_query_recv = 0;
1101 outmsg->host_questions = 0;
1102 outmsg->host_replies = 0;
1103 outmsg->host_reverse_v6_replies = 0;
1104
1105 for(i = 0; i < MDNS_MAX_SERVICES; i++) {
1106 outmsg->serv_questions[i] = 0;
1107 outmsg->serv_replies[i] = 0;
1108 }
1109 }
1110
1111 /**
1112 * Sets a timer that calls the handler when finished.
1113 * Depending on the busy_flag the timer is restarted or started. The flag is
1114 * set before return. Sys_timeout does not give us this functionality.
1115 *
1116 * @param netif Network interface info
1117 * @param msecs Time value to set
1118 * @param handler Callback function to call
1119 * @param busy_flag Pointer to flag that displays if the timer is running or not.
1120 */
1121 void
mdns_set_timeout(struct netif * netif,u32_t msecs,sys_timeout_handler handler,u8_t * busy_flag)1122 mdns_set_timeout(struct netif *netif, u32_t msecs, sys_timeout_handler handler,
1123 u8_t *busy_flag)
1124 {
1125 if(*busy_flag) {
1126 /* restart timer */
1127 sys_untimeout(handler, netif);
1128 sys_timeout(msecs, handler, netif);
1129 }
1130 else {
1131 /* start timer */
1132 sys_timeout(msecs, handler, netif);
1133 }
1134 /* Now we have a timer running */
1135 *busy_flag = 1;
1136 }
1137
1138 #ifdef LWIP_MDNS_SEARCH
1139 /**
1140 * Send search request containing all our known data
1141 * @param req The request to send
1142 * @param netif The network interface to send on
1143 * @param destination The target address to send to (usually multicast address)
1144 */
1145 err_t
mdns_send_request(struct mdns_request * req,struct netif * netif,const ip_addr_t * destination)1146 mdns_send_request(struct mdns_request *req, struct netif *netif, const ip_addr_t *destination)
1147 {
1148 struct mdns_outmsg outmsg;
1149 err_t res;
1150
1151 memset(&outmsg, 0, sizeof(outmsg));
1152 outmsg.query = req;
1153 outmsg.dest_port = LWIP_IANA_PORT_MDNS;
1154 SMEMCPY(&outmsg.dest_addr, destination, sizeof(outmsg.dest_addr));
1155 res = mdns_send_outpacket(&outmsg, netif);
1156 if(res != ERR_OK) {
1157 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Multicast query request send failed\n"));
1158 }
1159 else {
1160 LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Multicast query request send successful\n"));
1161 }
1162 return res;
1163 }
1164 #endif
1165
1166 #endif /* LWIP_MDNS_RESPONDER */
1167