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