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