xref: /btstack/3rd-party/lwip/core/src/apps/mdns/mdns_out.c (revision 97dc5e692c7d94a280158af58036a0efee5b0e56)
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