Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers fnet_mdns.c Source File

fnet_mdns.c

00001 /**************************************************************************
00002 *
00003 * Copyright (c) 2017, Arm Limited and affiliates.
00004 * Copyright 2016 by Andrey Butok. FNET Community.
00005 *
00006 ***************************************************************************
00007 *
00008 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
00009 *  not use this file except in compliance with the License.
00010 *  You may obtain a copy of the License at
00011 *
00012 *  http://www.apache.org/licenses/LICENSE-2.0
00013 *
00014 *  Unless required by applicable law or agreed to in writing, software
00015 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00016 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00017 *  See the License for the specific language governing permissions and
00018 *  limitations under the License.
00019 *
00020 **********************************************************************/
00021 /*!
00022 * @brief mDNS (Bonjour) Server/Responder implementation (RFC6762).
00023 *
00024 ***************************************************************************/
00025 #include "fnet.h"
00026 #include <stdio.h>
00027 
00028 #if FNET_CFG_MDNS
00029 
00030 #include "fnet_mdns.h"
00031 #include "services/dns/fnet_dns_prv.h" //TBD use common DNS definitions and use common code for DNS, mDNS and LLMNR.
00032 #include "fnet_netif_prv.h"
00033 
00034 #if FNET_CFG_DEBUG_MDNS && FNET_CFG_DEBUG
00035     #define FNET_DEBUG_MDNS   FNET_DEBUG
00036 #else
00037     #define FNET_DEBUG_MDNS(...)   do{}while(0)
00038 #endif
00039 
00040 /* mDNS requires multicast support.*/
00041 #if FNET_CFG_MULTICAST == 0
00042     #error FNET_CFG_MULTICAST must be enabled for MDNS
00043 #endif
00044 
00045 /************************************************************************
00046 *     Definitions
00047 *************************************************************************/
00048 /* MDNS settings */
00049 #define FNET_MDNS_DOMAIN_NAME              "local"                 /* mDNS top level domain (TLD) name: local */
00050 #define FNET_MDNS_PORT                     FNET_CFG_MDNS_PORT      /* mDNS port */
00051 
00052 #define FNET_MDNS_WAIT                     250                     /* Wait 250ms to check domain name. */  
00053 #define FNET_MDNS_PROBE_WAIT               (5*1000)                /* Wait 5 seconds before trying again. */  
00054 #define FNET_MDNS_PROBE_DEFER_WAIT         (1*1000)                /* Defers to the winning host by waiting one second. */  
00055 #define FNET_MDNS_SHARED_RESPONSE_DELAY    (200)                   /* Delay for shared response. Random amount of time selected with uniform random distribution in the range 20-120 ms. */  
00056 
00057 #define FNET_MDNS_ANNOUNCE_COUNT           (2)                     /* The Multicast DNS responder MUST send at least two unsolicited responses. */  
00058 #define FNET_MDNS_ANNOUNCE_INTERVAL        (1000)                  /* one second apart. */
00059 
00060 #define FNET_MDNS_HEADER_CLASS_IN          0x01                    /* Internet */
00061 #define FNET_MDNS_HEADER_CACHE_FLUSH       0x8000                  /* Cache flush */
00062 
00063 #define FNET_MDNS_DOMAIN_NAME_COMPRESSION  0xC0                    /* Domain Name Compression flag */
00064 
00065 /* MDNS Header Flags.*/
00066 #define FNET_MDNS_HEADER_FLAGS_QR           0x8000
00067 #define FNET_MDNS_HEADER_FLAGS_OPCODE       0x7800
00068 #define FNET_MDNS_HEADER_FLAGS_TC           0x0200                  /* Trancation Flag */
00069 #define FNET_MDNS_HEADER_FLAGS_C            0x0400
00070 
00071 #define FNET_MDNS_PACKET_SIZE               512                     /* mDNS maximum packet size*/
00072 
00073 /* [RFC6762] All Multicast DNS responses (including responses sent via unicast)
00074 * SHOULD be sent with IP TTL set to 255.  This is recommended to
00075 * provide backwards-compatibility with older Multicast DNS queriers
00076 * (implementing a draft version of this document, posted in February
00077 * 2004) that check the IP TTL on reception to determine whether the
00078 * packet originated on the local link.  These older queriers discard
00079 * all packets with TTLs other than 255.*/
00080 #define FNET_MDNS_IP_TTL              (255u)
00081 
00082 #define FNET_MDNS_NAME_MAX              64  /**< Maximum length for MDNS name. */
00083 #define FNET_MDNS_HOST_NAME_LEN_MAX     (FNET_MDNS_NAME_MAX+sizeof(" 4294967295"))               /**< Maximum length of the host name. */
00084 #define FNET_MDNS_RR_NAME_LEN_MAX       (FNET_MDNS_HOST_NAME_LEN_MAX+sizeof("._saccessdata-f2d._tcp."FNET_MDNS_DOMAIN_NAME)) /**< Maximum length of the RR name. */
00085 /* Maximum RR record size of probe RR - SRV RR*/
00086 #define FNET_MDNS_RR_PROBE_LEN_MAX    (FNET_MDNS_RR_NAME_LEN_MAX + sizeof(fnet_mdns_rr_header_t) + sizeof(fnet_mdns_rr_data_srv_t) + FNET_MDNS_RR_NAME_LEN_MAX ) /**< Maximum length of the SRV RR. */
00087 
00088 /* Error strings.*/
00089 #define FNET_MDNS_ERR_PARAMS             "MDNS: Wrong input parameters."
00090 #define FNET_MDNS_ERR_SOCKET_CREATION    "MDNS: Socket creation error."
00091 #define FNET_MDNS_ERR_SOCKET_BIND        "MDNS: Socket Error during bind."
00092 #define FNET_MDNS_ERR_SERVICE            "MDNS: Service registration is failed."
00093 #define FNET_MDNS_ERR_IS_INITIALIZED     "MDNS: Is already initialized."
00094 #define FNET_MDNS_ERR_JOIN_MULTICAST     "MDNS: Joining to multicast group is failed."
00095 
00096 /*******************************************************************************
00097 * Types definitions
00098 *******************************************************************************/
00099 /* RR record types */
00100 typedef enum
00101 {
00102     FNET_MDNS_RR_PTR   = 0x000C,    /* PTR record */
00103     FNET_MDNS_RR_NSEC  = 0x002F,    /* NSEC record */
00104     FNET_MDNS_RR_TXT   = 0x0010,    /* TXT record */
00105     FNET_MDNS_RR_ANY   = 0x00FF,    /* ANY record */
00106     FNET_MDNS_RR_SRV   = 0x0021,    /* SRV record */
00107     FNET_MDNS_RR_OPT   = 0x0029,    /* OPT record */
00108     FNET_MDNS_RR_A     = 0x0001,    /* IPv4 record */
00109     FNET_MDNS_RR_AAAA  = 0x001C,    /* IPv6 record */
00110 }fnet_mdns_rr_type_t;
00111 
00112 /* Query RR record types (bitmap). */
00113 typedef enum
00114 {
00115     FNET_MDNS_QUERY_NONE  = 0,       /* No record */
00116     FNET_MDNS_QUERY_PTR   = 1<<0,    /* PTR record */
00117     FNET_MDNS_QUERY_TXT   = 1<<1,    /* TXT record */
00118     FNET_MDNS_QUERY_SRV   = 1<<2,    /* SRV record */
00119     FNET_MDNS_QUERY_A     = 1<<3,    /* IPv4 record */
00120     FNET_MDNS_QUERY_AAAA  = 1<<4,    /* IPv6 record */
00121     FNET_MDNS_QUERY_ANY   = (FNET_MDNS_QUERY_PTR | FNET_MDNS_QUERY_TXT | FNET_MDNS_QUERY_SRV | FNET_MDNS_QUERY_A | FNET_MDNS_QUERY_AAAA)     /* ANY record  */
00122 } fnet_mdns_query_type_t;
00123 
00124 /* mDNS-server states. */
00125 typedef enum
00126 {
00127     FNET_MDNS_STATE_DISABLED = 0,      /**< @brief mDNS server is not initialized or released. */
00128     FNET_MDNS_STATE_PROBING_WAIT,      /**< @brief mDNS server is waiting five seconds after any failed probe attempt before trying again. */
00129     /*RFC6762: Whenever a Multicast DNS responder starts up, wakes up from sleep,
00130     receives an indication of a network interface "Link Change" event, or
00131     has any other reason to believe that its network connectivity may
00132     have changed in some relevant way, it MUST perform the two startup
00133     steps below: Probing (Section 8.1) and Announcing (Section 8.3).*/
00134     FNET_MDNS_STATE_PROBING,           /**< @brief mDNS server is sending probe queries. */
00135     FNET_MDNS_STATE_ANNOUNCING,        /**< @brief mDNS server is sending aannouncements. */
00136     FNET_MDNS_STATE_WAITING_REQUEST    /**< @brief mDNS server is waiting for a request from a mDNS client. */
00137 } fnet_mdns_state_t;
00138 
00139 typedef struct fnet_mdns_service_if_s
00140 {
00141     const char                  *service_type;                      /* Service Type. Null-terminated string. Example _http._tcp*/
00142     fnet_uint16_t               service_port;                       /* Service Port number (in network byte order). */
00143     const fnet_uint8_t          *(*service_get_txt)(void);          /* Call-back function, which returns pointer to the service TXT record (null-terminated). 
00144                                                                     * If the service does not provide any TXT record, this parameter must be set to NULL. */
00145     fnet_uint16_t               offset_service_name;                /* Pointer to service name. Offset from the start of the DNS message. Used for Domain Name Compression. */
00146     fnet_uint16_t               offset_service_type;                /* Pointer to service type. Offset from the start of the DNS message. Used for Domain Name Compression. */
00147     fnet_mdns_query_type_t      response_type;                      /* Response type used in mDNS response.*/ 
00148 } fnet_mdns_service_if_t;
00149 
00150 /* MDNS interface structure */
00151 typedef struct fnet_mdns_if
00152 {
00153     fnet_mdns_state_t           state;                                          /* Current state */
00154     fnet_poll_desc_t            service_descriptor;                             /* Service descriptor. */
00155     fnet_netif_desc_t           netif;                                          /* Network interface descriptor. */
00156     fnet_uint32_t               rr_ttl;                                         /* Resource record TTL */
00157     fnet_uint32_t               rr_ttl_ip;                                      /* Resource record TTL for IP header, hop-count limit for a packet */
00158     fnet_address_family_t       addr_family;                                    /* Address family (IPv6 or IPv4 or both) the server will listen and send */
00159     fnet_size_t                 name_length;                                    /* Length of the service name without index postfix */
00160     char                        host_name[FNET_MDNS_HOST_NAME_LEN_MAX+1];       /* Parsed "name" containing only legal symbols, optionally appended with host_name_count */  
00161     fnet_uint32_t               host_name_count;                                /* Count of try device name */
00162     char                        service_name[FNET_MDNS_HOST_NAME_LEN_MAX+1];    /* Service name, optionally appended with host_name_count */  
00163     fnet_uint32_t               probe_count;                                    /* Number of sent probe queries without name conflict.*/
00164     fnet_uint32_t               announce_count;                                 /* Count of sent annoncemnts */
00165     fnet_socket_t               socket_listen;                                  /* Listening socket.*/
00166     fnet_uint32_t               host_name_conflict_timestamp;                   /* Last Conflict timestamp. */
00167     fnet_uint32_t               probe_wait_interval;                            /* Lenghth of time before next probe attempt. */
00168     fnet_uint32_t               send_timestamp;                                 /* Last Send timestamp.*/
00169     fnet_uint8_t                buffer[FNET_MDNS_PACKET_SIZE];                  /* TX/RX Data buffer. */
00170     fnet_uint16_t               offset_host_name;                               /* Pointer to host name. Offset from the start of the DNS message. Used for Domain Name Compression. */
00171     fnet_bool_t                 is_truncated;                                   /* RFC6762:In query messages, if the TC bit is set, it means that additional Known-Answer records may be following shortly.  A responder SHOULD
00172                                                                                 * record this fact, and wait for those additional Known-Answer records, before deciding whether to respond.*/
00173     fnet_bool_t                 is_legacy_unicast;                              /* If the source UDP port in a received Multicast DNS query is not port 5353*/
00174     fnet_bool_t                 is_shared;                                      /* Response contains only shared records. 
00175                                                                                 * RFC 6762: In any case where there may be multiple responses, such as queries
00176                                                                                 * where the answer is a member of a shared resource record set, each
00177                                                                                 * responder SHOULD delay its response by a random amount of time
00178                                                                                 * selected with uniform random distribution in the range 20-120 ms.  */
00179     fnet_uint32_t               is_shared_timestamp;                            /* Timestamp of shared response query.*/
00180     struct sockaddr             remote_address;                                 /* Remote address.*/
00181     fnet_address_family_t       response_address_family;                        /* Address family used in mDNS response.*/                 
00182     fnet_mdns_query_type_t     response_type;                                   /* Response type used in mDNS response.*/  
00183     fnet_mdns_service_if_t     service_if_list[FNET_CFG_MDNS_SERVICE_MAX];      /* Service Discovery List */
00184 } fnet_mdns_if_t;
00185 
00186 /* MDNS packet header - count of all records */
00187 FNET_COMP_PACKED_BEGIN
00188 typedef struct fnet_mdns_header_s
00189 {
00190     fnet_uint16_t    ip  FNET_COMP_PACKED; 
00191     fnet_uint16_t    flags   FNET_COMP_PACKED;          /* flags */
00192     fnet_uint16_t    qdcount FNET_COMP_PACKED;          /* count of questions */
00193     fnet_uint16_t    ancount FNET_COMP_PACKED;          /* count of answers */
00194     fnet_uint16_t    nscount FNET_COMP_PACKED;          /* Authority Record Count. Number of RR in the Authority section. (mDNS - name server). */
00195     fnet_uint16_t    arcount FNET_COMP_PACKED;          /* count of additional */
00196 } fnet_mdns_header_t;
00197 FNET_COMP_PACKED_END
00198 
00199 /* MDNS record header */
00200 FNET_COMP_PACKED_BEGIN
00201 typedef struct fnet_mdns_rr_header_s
00202 {
00203     fnet_uint16_t    type    FNET_COMP_PACKED;          /* RR type */
00204     fnet_uint16_t    rr_class    FNET_COMP_PACKED;      /* RR class */
00205     fnet_uint32_t    ttl FNET_COMP_PACKED;              /* time to live (in seconds) */
00206     fnet_uint16_t    data_length FNET_COMP_PACKED;      /* length of data */
00207 } fnet_mdns_rr_header_t;
00208 FNET_COMP_PACKED_END
00209 
00210 /* MDNS query Question Entry header */
00211 FNET_COMP_PACKED_BEGIN
00212 typedef struct fnet_mdns_qe_header_s
00213 {
00214     fnet_uint16_t    type    FNET_COMP_PACKED;           /* Question  type */
00215     fnet_uint16_t    rr_class    FNET_COMP_PACKED;       /* Question  class */
00216 } fnet_mdns_qe_header_t;
00217 FNET_COMP_PACKED_END
00218 
00219 /* MDNS data RR SRV */
00220 FNET_COMP_PACKED_BEGIN
00221 typedef struct fnet_mdns_rr_data_srv_s
00222 {
00223     fnet_uint16_t priority   FNET_COMP_PACKED;
00224     fnet_uint16_t weight FNET_COMP_PACKED;
00225     fnet_uint16_t port   FNET_COMP_PACKED;
00226 } fnet_mdns_rr_data_srv_t;
00227 FNET_COMP_PACKED_END
00228 
00229 static void fnet_mdns_poll( void *fnet_mdns_if_p );
00230 static fnet_uint8_t * fnet_mdns_add_domain_name(fnet_uint8_t *buf, fnet_uint32_t buf_size, const char * domain_name);
00231 static void fnet_mdns_send_response(fnet_mdns_if_t *mdns_if, fnet_uint32_t ttl, fnet_uint32_t ttl_ip);
00232 static fnet_uint8_t * fnet_mdns_add_rr_header(fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_mdns_rr_type_t type, fnet_bool_t flush, fnet_uint32_t ttl, fnet_uint16_t data_length);
00233 static void fnet_mdns_send(fnet_mdns_if_t *mdns_if, fnet_address_family_t address_family, fnet_uint8_t * buffer, fnet_uint32_t send_size);
00234 static void fnet_mdns_update_name(fnet_mdns_if_t *mdns_if, const fnet_char_t *name);
00235 static void fnet_mdns_update_name_counter(fnet_mdns_if_t *mdns_if);
00236 static void fnet_mdns_change_state(fnet_mdns_if_t *mdns_if, fnet_mdns_state_t state);
00237 static void fnet_mdns_recv(fnet_mdns_if_t *mdns_if);
00238 static void fnet_mdns_send_probe(fnet_mdns_if_t *mdns_if);
00239 static void fnet_mdns_process_simultaneous_probe(fnet_mdns_if_t *mdns_if, const fnet_uint8_t *ns_ptr, fnet_uint8_t *packet, fnet_uint32_t packet_size);
00240 fnet_uint8_t * fnet_mdns_add_rr_txt(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_mdns_service_if_t *service_if, fnet_uint32_t ttl, fnet_bool_t flush, fnet_bool_t compression);
00241 static fnet_uint8_t *fnet_mdns_add_rr_ptr(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_mdns_service_if_t *service_if, fnet_uint32_t ttl, fnet_bool_t compression);
00242 static fnet_uint8_t * fnet_mdns_add_rr_srv(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_mdns_service_if_t *service_if, fnet_uint32_t ttl, fnet_bool_t flush, fnet_bool_t compression);
00243 #if FNET_CFG_IP4
00244 static fnet_uint8_t * fnet_mdns_add_rr_a(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_uint32_t ttl, fnet_bool_t flush, fnet_bool_t compression);
00245 #endif
00246 static fnet_uint8_t * fnet_mdns_add_rr_aaaa(fnet_mdns_if_t *mdns_if,  fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_uint32_t ttl, fnet_bool_t flush, fnet_bool_t compression);
00247 static fnet_uint8_t * fnet_mdns_add_qe_any(fnet_uint8_t *buf, fnet_uint32_t buf_size);
00248 static fnet_uint8_t * fnet_mdns_add_host_name(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_bool_t compression);
00249 static fnet_uint8_t * fnet_mdns_add_service_name(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_mdns_service_if_t *service_if, fnet_bool_t compression);
00250 static fnet_uint8_t * fnet_mdns_add_service_type_name(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_mdns_service_if_t *service_if, fnet_bool_t compression);
00251 static fnet_uint8_t * fnet_mdns_add_domain_name_compression(fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_uint16_t name_offset);
00252 static const fnet_uint8_t *fnet_mdns_get_rr_name(char *rr_name, fnet_uint32_t rr_name_size, const fnet_uint8_t *rr, const fnet_uint8_t *packet);
00253 static fnet_bool_t fnet_mdns_cmp_rr_name(const char * rr_name, const char *name_1, const char *name_2);
00254 static fnet_bool_t fnet_mdns_is_rr_win(fnet_uint8_t *our_rr, const fnet_uint8_t *ns_ptr, fnet_uint16_t ns_count, fnet_uint8_t *packet);
00255 static const fnet_uint8_t *fnet_mdns_get_ns(fnet_uint8_t *packet, fnet_uint32_t packet_size);
00256 static const fnet_uint8_t *fnet_mdns_get_an(const fnet_uint8_t *packet, fnet_uint32_t packet_size);
00257 static fnet_int32_t fnet_mdns_cmp_rr(fnet_uint8_t *our_rr, const fnet_uint8_t **rr, const fnet_uint8_t *packet);
00258 static fnet_mdns_query_type_t fnet_mdns_get_query_type(fnet_uint16_t type);
00259 static void fnet_mdns_process_duplicate_answer(fnet_mdns_if_t *mdns_if, const fnet_uint8_t *an_ptr, const fnet_uint8_t *packet, fnet_uint32_t packet_size);
00260 static fnet_bool_t fnet_mdns_is_our_host_name(fnet_mdns_if_t *mdns_if, char *host_name);
00261 static fnet_mdns_service_if_t *fnet_mdns_get_service_by_name(fnet_mdns_if_t *mdns_if, char *service_name);
00262 static fnet_mdns_service_if_t *fnet_mdns_get_service_by_type(fnet_mdns_if_t *mdns_if, char *service_name);
00263 static void fnet_mdns_send_announcement(fnet_mdns_if_t *mdns_if, fnet_uint32_t ttl, fnet_uint32_t ttl_ip);
00264 static fnet_bool_t fnet_mdns_cmp_name(const char **rr_name_p, const char *name);
00265 static const fnet_uint8_t *fnet_mdns_process_query(fnet_mdns_if_t *mdns_if, fnet_address_family_t address_family, const fnet_uint8_t *ptr, fnet_uint8_t *packet, fnet_uint32_t packet_size);
00266 static const fnet_uint8_t *fnet_mdns_process_response(fnet_mdns_if_t *mdns_if, const fnet_uint8_t * ptr, fnet_uint8_t *packet, fnet_uint32_t packet_size);
00267 static fnet_int32_t fnet_mdns_cmp_rr(fnet_uint8_t *our_rr, const fnet_uint8_t **rr, const fnet_uint8_t *packet);
00268 static fnet_uint32_t fnet_mdns_key_value_record_len(const fnet_uint8_t *record);
00269 
00270 /* RFC 6762:  The destination UDP port in all Multicast DNS responses MUST be 5353,
00271    and the destination address MUST be the mDNS IPv4 link-local
00272    multicast address 224.0.0.251 or its IPv6 equivalent FF02::FB, except
00273    when generating a reply to a query that explicitly requested a
00274    unicast response*/
00275 #define FNET_MDNS_IP4_MULTICAST_ADDR   FNET_IP4_ADDR_INIT(224u, 0u, 0u, 251u)
00276 static const fnet_ip6_addr_t fnet_mdns_ip6_multicast_addr = FNET_IP6_ADDR_INIT(0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB);
00277 
00278 /* The MDNS interface list*/
00279 static  fnet_mdns_if_t mdns_if_list[FNET_CFG_MDNS_MAX];
00280 
00281 
00282 /************************************************************************
00283 * DESCRIPTION: Initializes mDNS server/responder.
00284 ************************************************************************/
00285 fnet_mdns_desc_t fnet_mdns_init( struct fnet_mdns_params *params )
00286 {
00287     struct fnet_mdns_if     *mdns_if = FNET_NULL;
00288     fnet_index_t            i;
00289     struct sockaddr         local_addr;
00290     fnet_uint32_t           option;
00291     fnet_size_t             name_length;
00292     fnet_scope_id_t         scope_id;
00293 
00294     /* Check input paramters. */
00295     if((params == 0) || (params->netif_desc == 0) || (params->name == 0)
00296        || ((name_length = fnet_strlen(params->name)) == 0u) || (name_length >= FNET_MDNS_NAME_MAX))
00297     {
00298         FNET_DEBUG_MDNS(FNET_MDNS_ERR_PARAMS);
00299         goto ERROR_1;
00300     }
00301 
00302     scope_id = fnet_netif_get_scope_id(params->netif_desc);
00303     if(scope_id == 0)
00304     {
00305         FNET_DEBUG_MDNS(FNET_MDNS_ERR_PARAMS);
00306         goto ERROR_1;
00307     }
00308 
00309     /* Try to find free mDNS server descriptor. */
00310     for(i = 0u; i < FNET_CFG_MDNS_MAX; i++)
00311     {
00312         if(mdns_if_list[i].state == FNET_MDNS_STATE_DISABLED)
00313         {
00314             mdns_if = &mdns_if_list[i];
00315         }
00316     }
00317 
00318     if(mdns_if == FNET_NULL)
00319     {
00320         /* No free mDNS descriptor. */
00321         FNET_DEBUG_MDNS(FNET_MDNS_ERR_IS_INITIALIZED);
00322         goto ERROR_1;
00323     }
00324 
00325     /* Reset interface structure. */
00326     fnet_memset_zero(mdns_if, sizeof(struct fnet_mdns_if));
00327 
00328     /* Set parameters.*/
00329     mdns_if->netif = params->netif_desc;
00330     if(params->rr_ttl == 0u)
00331     {
00332         mdns_if->rr_ttl = FNET_CFG_MDNS_RR_TTL;
00333     }
00334     else
00335     {
00336         mdns_if->rr_ttl = params->rr_ttl;
00337     }
00338 
00339     /* TTL for AAAA record */
00340     if(params->rr_ttl_ip == 0u)
00341     {
00342         mdns_if->rr_ttl_ip = FNET_MDNS_IP_TTL;
00343     }
00344     else
00345     {
00346         mdns_if->rr_ttl_ip = params->rr_ttl_ip;
00347     }
00348 
00349     option = mdns_if->rr_ttl_ip;
00350 
00351     /* Generate host_name.*/
00352     fnet_mdns_update_name(mdns_if, params->name);
00353 
00354     /* Init local socket address.*/
00355     fnet_memset_zero(&local_addr, sizeof(local_addr));
00356     if(local_addr.sa_family == AF_UNSPEC)
00357     {
00358         local_addr.sa_family = AF_SUPPORTED;
00359     }
00360     else
00361     {
00362         local_addr.sa_family = params->addr_family;
00363     }
00364     local_addr.sa_port = FNET_MDNS_PORT;
00365     local_addr.sa_scope_id = scope_id;
00366 
00367     mdns_if->addr_family = local_addr.sa_family;
00368 
00369     /* Create listen socket */
00370     mdns_if->socket_listen = fnet_socket(local_addr.sa_family, SOCK_DGRAM, 0u);
00371     if(mdns_if->socket_listen == FNET_NULL)
00372     {
00373         FNET_DEBUG_MDNS(FNET_MDNS_ERR_SOCKET_CREATION);
00374         goto ERROR_1;
00375     }
00376 
00377     /* Bind socket. */
00378     if(fnet_socket_bind(mdns_if->socket_listen, &local_addr, sizeof(local_addr)) == FNET_ERR)
00379     {
00380         FNET_DEBUG_MDNS(FNET_MDNS_ERR_SOCKET_BIND);
00381         goto ERROR_2;
00382     }
00383 
00384     /* Join Multicast Group.*/
00385 #if FNET_CFG_IP4
00386     if((local_addr.sa_family & AF_INET) != 0u)
00387     {
00388         struct ip_mreq mreq; /* Multicast group information.*/
00389 
00390         mreq.imr_multiaddr.s_addr = FNET_MDNS_IP4_MULTICAST_ADDR;
00391         mreq.imr_interface = scope_id;
00392 
00393         /* Join multicast group. */
00394         if(fnet_socket_setopt(mdns_if->socket_listen, IPPROTO_IP, IP_ADD_MEMBERSHIP, (fnet_char_t *)&mreq, sizeof(mreq)) == FNET_ERR)
00395         {
00396             FNET_DEBUG_MDNS(FNET_MDNS_ERR_JOIN_MULTICAST);
00397             goto ERROR_2;
00398         }
00399         /* Set IPv4 TTL. */
00400         fnet_socket_setopt(mdns_if->socket_listen, IPPROTO_IP, IP_MULTICAST_TTL, (fnet_char_t *) &option, sizeof(option));
00401     }
00402 #endif
00403 #if FNET_CFG_IP6
00404     if((local_addr.sa_family & AF_INET6) != 0u)
00405     {
00406         struct ipv6_mreq mreq6; /* Multicast group information.*/
00407 
00408         FNET_IP6_ADDR_COPY(&fnet_mdns_ip6_multicast_addr, &mreq6.ipv6imr_multiaddr.s6_addr);
00409         mreq6.ipv6imr_interface = scope_id;
00410 
00411         /* Join multicast group. */
00412         if(fnet_socket_setopt(mdns_if->socket_listen, IPPROTO_IPV6, IPV6_JOIN_GROUP, (fnet_char_t *)&mreq6, sizeof(mreq6)) == FNET_ERR)
00413         {
00414             FNET_DEBUG_MDNS(FNET_MDNS_ERR_JOIN_MULTICAST);
00415             goto ERROR_2;
00416         }
00417 
00418         /* Set IPv6 Hop Limit. */
00419         fnet_socket_setopt(mdns_if->socket_listen, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (fnet_char_t *) &option, sizeof(option));
00420     }
00421 #endif
00422 
00423     /* Register service. */
00424     mdns_if->service_descriptor = fnet_poll_service_register(fnet_mdns_poll, (void *) mdns_if);
00425     if(mdns_if->service_descriptor == 0)
00426     {
00427         FNET_DEBUG_MDNS(FNET_MDNS_ERR_SERVICE);
00428         goto ERROR_2;
00429     }
00430 
00431     /* Start probing.*/
00432     fnet_mdns_change_state(mdns_if, FNET_MDNS_STATE_PROBING);
00433 
00434     return (fnet_mdns_desc_t)mdns_if;
00435 
00436 ERROR_2:
00437     fnet_socket_close(mdns_if->socket_listen);
00438 ERROR_1:
00439     return 0;
00440 }
00441 
00442 /************************************************************************
00443 * DESCRIPTION: Registers application-specific service in the mDNS server.
00444 ************************************************************************/
00445 fnet_mdns_service_desc_t fnet_mdns_service_register(fnet_mdns_desc_t mdns_desc, const fnet_mdns_service_t *service)
00446 {
00447     fnet_mdns_service_desc_t   result = 0;
00448     fnet_mdns_if_t             *mdns_if = (fnet_mdns_if_t *)mdns_desc;
00449     fnet_index_t               i;
00450 
00451     if(mdns_if)
00452     {
00453         /* Initialize Service List */
00454         if(service && service->service_type)
00455         {
00456 
00457             if (fnet_strlen(service->service_type) >= FNET_MDNS_NAME_MAX) {
00458                 return 0;
00459             }
00460 
00461             for(i = 0; i<FNET_CFG_MDNS_SERVICE_MAX; i++)
00462             {
00463                 /* Find empty service entry.*/
00464                 if(mdns_if->service_if_list[i].service_type == NULL) 
00465                 {
00466                     mdns_if->service_if_list[i].service_type = service->service_type;
00467                     mdns_if->service_if_list[i].service_port = service->service_port;
00468                     mdns_if->service_if_list[i].service_get_txt = service->service_get_txt;
00469 
00470                     result = (fnet_mdns_service_desc_t)(&mdns_if->service_if_list[i]);
00471                     break;
00472                 }
00473             }
00474         }
00475 
00476         /* Probing new service */
00477         if(result && ((mdns_if->state == FNET_MDNS_STATE_WAITING_REQUEST) || (mdns_if->state ==FNET_MDNS_STATE_ANNOUNCING)) )
00478         {
00479             fnet_mdns_change_state(mdns_if, FNET_MDNS_STATE_PROBING); /* Start probing.*/
00480         }
00481     }
00482 
00483     return result;
00484 }
00485 
00486 /************************************************************************
00487 * DESCRIPTION: Unregisters application service from the mDNS server.
00488 ************************************************************************/
00489 void fnet_mdns_service_unregister(fnet_mdns_service_desc_t service_desc)
00490 {
00491     fnet_mdns_service_if_t *service_if = (fnet_mdns_service_if_t *)service_desc;
00492 
00493     /* Free service entry.*/
00494     if(service_if)
00495     {
00496         service_if->service_type = NULL;
00497     }
00498 }
00499 
00500 /************************************************************************
00501 * DESCRIPTION: Sends unsolicited mDNS announcement.
00502 ************************************************************************/
00503 void fnet_mdns_announce(fnet_mdns_desc_t mdns_desc)
00504 {
00505     fnet_mdns_if_t   *mdns_if = (fnet_mdns_if_t *)mdns_desc;
00506 
00507     if(mdns_if)
00508     {
00509         /* RFC6762: At any time, if the rdata of any of a host's Multicast DNS records
00510         changes, the host MUST repeat the Announcing step described above to
00511         update neighboring caches.  For example, if any of a host's IP
00512         addresses change, it MUST re-announce those address records.  The
00513         host does not need to repeat the Probing step because it has already
00514         established unique ownership of that name.*/
00515         if((mdns_if->state == FNET_MDNS_STATE_WAITING_REQUEST)
00516             || (mdns_if->state == FNET_MDNS_STATE_ANNOUNCING))
00517         {
00518             fnet_mdns_change_state(mdns_if, FNET_MDNS_STATE_ANNOUNCING);
00519         }
00520     }
00521 }
00522 
00523 /************************************************************************
00524 * DESCRIPTION: Releases the mDNS server/responder.
00525 ************************************************************************/
00526 void fnet_mdns_release(fnet_mdns_desc_t mdns_desc)
00527 {
00528     struct fnet_mdns_if *mdns_if = (struct fnet_mdns_if *)mdns_desc;
00529 
00530     if(mdns_if && (mdns_if->state != FNET_MDNS_STATE_DISABLED))
00531     {
00532         /* Send "goodbye" */
00533         fnet_mdns_change_state(mdns_if, FNET_MDNS_STATE_DISABLED );
00534 
00535         fnet_socket_close(mdns_if->socket_listen);
00536 
00537         fnet_poll_service_unregister(mdns_if->service_descriptor); /* Delete service.*/
00538     }
00539 }
00540 
00541 /************************************************************************
00542 * DESCRIPTION: This function returns FNET_TRUE if the mDNS server
00543 *              is enabled/initialised.
00544 ************************************************************************/
00545 fnet_bool_t fnet_mdns_is_enabled(fnet_mdns_desc_t desc)
00546 {
00547     struct fnet_mdns_if     *mdns_if = (struct fnet_mdns_if *) desc;
00548     fnet_bool_t             result;
00549 
00550     if(mdns_if)
00551     {
00552         result = (mdns_if->state == FNET_MDNS_STATE_DISABLED) ? FNET_FALSE : FNET_TRUE;
00553     }
00554     else
00555     {
00556         result = FNET_FALSE;
00557     }
00558 
00559     return result;
00560 }
00561 
00562 /************************************************************************
00563 * DESCRIPTION: Generate host and service name.
00564 ************************************************************************/
00565 static void fnet_mdns_update_name(fnet_mdns_if_t *mdns_if, const fnet_char_t *name)
00566 {
00567     FNET_ASSERT(mdns_if != NULL);
00568     FNET_ASSERT(name != NULL);
00569 
00570     fnet_char_t *c;
00571     fnet_size_t length = fnet_strlen(name);
00572 
00573     if(length <= FNET_MDNS_NAME_MAX)
00574     {
00575         /* Reset device name counter */
00576         mdns_if->host_name_count = 0;
00577 
00578         /* Save name length.*/
00579         mdns_if->name_length = fnet_strlen(name);
00580 
00581         /* Copy name. */
00582         fnet_strcpy(mdns_if->host_name, name);
00583         fnet_strcpy(mdns_if->service_name, name);
00584        
00585         /* Allow only legal characters in address record names.*/
00586         for(c = mdns_if->host_name; *c != '\0'; c++)
00587         {
00588             /*7-bit ASCII embedded in an 8 bit byte whose high order bit is always 0.*/
00589             if((size_t)*c <= 127)
00590             {
00591                 /*RFC6762: For names that are restricted to US-ASCII [RFC0020] letters, digits and and hyphens*/
00592                 if( !(((*c<='Z') && (*c>='A'))||
00593                     ((*c<='z') && (*c>='a'))||
00594                     ((*c<='9') && (*c>='0'))||
00595                     (*c=='-') ||
00596                     (*c=='_') ) )
00597                 {
00598                     /* Replace illegal label symbols by '-'*/
00599                     *c = '-';
00600                 }
00601             }
00602             /* else UTF-8 */
00603         }
00604     }
00605 
00606     FNET_DEBUG_MDNS("MDNS: Host-name set to (%s).", mdns_if->host_name);
00607 }
00608 /************************************************************************
00609 * DESCRIPTION: Update counter of host and service name. 
00610 ************************************************************************/
00611 static void fnet_mdns_update_name_counter(fnet_mdns_if_t *mdns_if)
00612 {
00613     FNET_ASSERT(mdns_if != NULL);
00614 
00615     /* Update name counter. */
00616     mdns_if->host_name_count++;
00617 
00618     /* Change name to device (count) */
00619     if(mdns_if->host_name_count>0)
00620     {
00621         snprintf(&mdns_if->host_name[mdns_if->name_length], (sizeof(mdns_if->host_name) - mdns_if->name_length), "-%d", (int)mdns_if->host_name_count);
00622         snprintf(&mdns_if->service_name[mdns_if->name_length], (sizeof(mdns_if->service_name) - mdns_if->name_length), " %d", (int)mdns_if->host_name_count);
00623     }
00624     else
00625     {
00626         mdns_if->host_name[mdns_if->name_length] = '\0';
00627         mdns_if->service_name[mdns_if->name_length] = '\0';
00628     }
00629 
00630     FNET_DEBUG_MDNS("MDNS: Host-name set to (%s).", mdns_if->host_name);
00631 }
00632 
00633 
00634 /************************************************************************
00635 * DESCRIPTION: mDNS server poll (state machine).
00636 ************************************************************************/
00637 static void fnet_mdns_poll( void *fnet_mdns_if_p )
00638 {
00639     struct fnet_mdns_if     *mdns_if = (struct fnet_mdns_if *)fnet_mdns_if_p;
00640 
00641     if(mdns_if)
00642     {
00643         fnet_mdns_recv(mdns_if);  /* Receive mDNS packets. */
00644 
00645         switch(mdns_if->state)
00646         {
00647             case FNET_MDNS_STATE_PROBING_WAIT:
00648                 if( (fnet_timer_get_ms() - mdns_if->host_name_conflict_timestamp) > mdns_if->probe_wait_interval )
00649                 {
00650                     fnet_mdns_change_state(mdns_if, FNET_MDNS_STATE_PROBING); /* Start probing.*/
00651                 }
00652                 break;
00653             case FNET_MDNS_STATE_PROBING:
00654                 /* RFC:   250 ms after the first query, the host should send a second; then,
00655                    250 ms after that, a third. */
00656                 if( (fnet_timer_get_ms() - mdns_if->send_timestamp) > FNET_MDNS_WAIT )
00657                 {
00658                     /* Any response from this name => try three times */
00659                     if(mdns_if->probe_count < 3)
00660                     {
00661                         fnet_mdns_send_probe(mdns_if);   /* Send next probe.*/
00662                     }
00663                     else
00664                     {
00665                         /* RFC6762: If, by 250 ms after the third probe, no
00666                         conflicting Multicast DNS responses have been received, the host may
00667                         move to the next step, announcing. */
00668                         fnet_mdns_change_state(mdns_if, FNET_MDNS_STATE_ANNOUNCING);
00669                     }
00670                 }
00671                 break;
00672             case FNET_MDNS_STATE_ANNOUNCING:
00673                 if( (fnet_timer_get_ms() - mdns_if->send_timestamp) > FNET_MDNS_ANNOUNCE_INTERVAL )
00674                 {
00675                     /* RFC6762: The Multicast DNS responder MUST send at least two unsolicited
00676                     responses, one second apart.*/
00677                     if(mdns_if->announce_count < FNET_MDNS_ANNOUNCE_COUNT)
00678                     {
00679                         mdns_if->announce_count++;
00680                         fnet_mdns_send_announcement(mdns_if, mdns_if->rr_ttl, mdns_if->rr_ttl_ip);
00681                     }
00682                     else
00683                     {
00684                        fnet_mdns_change_state(mdns_if, FNET_MDNS_STATE_WAITING_REQUEST);
00685                     }
00686                 }
00687                 break;
00688             case FNET_MDNS_STATE_WAITING_REQUEST:
00689                 if( (mdns_if->is_shared == FNET_TRUE) &&
00690                     ((fnet_timer_get_ms() - mdns_if->is_shared_timestamp) > FNET_MDNS_SHARED_RESPONSE_DELAY) )
00691                 {
00692                     mdns_if->is_shared = FNET_FALSE; /* REST FLAG.*/
00693                 }
00694 
00695                 if(mdns_if->is_truncated == FNET_FALSE)
00696                 {
00697                     /* RFC6762: In any case where there may be multiple responses, such as queries
00698                     * where the answer is a member of a shared resource record set, each
00699                     * responder SHOULD delay its response by a random amount of time
00700                     * selected with uniform random distribution in the range 20-120 ms.
00701                     * The reason for requiring that the delay be at least 20 ms is to
00702                     * accommodate the situation where two or more query packets are sent
00703                     * back-to-back, because in that case we want a responder with answers
00704                     * to more than one of those queries to have the opportunity to
00705                     * aggregate all of its answers into a single response message.*/
00706                     if(mdns_if->is_shared == FNET_FALSE)
00707                     {
00708                         /* Send response */
00709                         fnet_mdns_send_response(mdns_if, mdns_if->rr_ttl, mdns_if->rr_ttl_ip);
00710                     }
00711                 }
00712                 break;
00713             default:
00714                 break;
00715         }
00716     }
00717 }
00718 
00719 /************************************************************************
00720 * DESCRIPTION: Change state of the mDNS server.
00721 ************************************************************************/
00722 static void fnet_mdns_change_state(fnet_mdns_if_t *mdns_if, fnet_mdns_state_t state )
00723 {
00724     FNET_ASSERT(mdns_if != NULL);
00725 
00726     mdns_if->state = state;
00727     switch (state)
00728     {
00729         case FNET_MDNS_STATE_DISABLED:
00730             /* RFC6762: In the case where a host knows that certain resource record data is
00731             * about to become invalid (for example, when the host is undergoing a
00732             * clean shutdown), the host SHOULD send an unsolicited Multicast DNS */
00733             /* "goodbye" announcement with RR TTL zero */
00734             fnet_mdns_send_announcement(mdns_if, 0, 0);
00735             break;
00736         case FNET_MDNS_STATE_PROBING_WAIT:
00737             break;
00738         case FNET_MDNS_STATE_PROBING:
00739             mdns_if->probe_count = 0;   /* Reset probe counter.*/
00740             fnet_mdns_send_probe(mdns_if);   /* First probing.*/
00741             break;
00742         case FNET_MDNS_STATE_ANNOUNCING:
00743             /* RFC6762: The second startup step is that the Multicast DNS responder MUST send
00744             * an unsolicited Multicast DNS response containing, in the Answer
00745             * Section, all of its newly registered resource records (both shared
00746             * records, and unique records that have completed the probing step). */
00747             mdns_if->announce_count = 1;
00748             fnet_mdns_send_announcement(mdns_if, mdns_if->rr_ttl, mdns_if->rr_ttl_ip);
00749             break;
00750         case FNET_MDNS_STATE_WAITING_REQUEST:
00751             break;
00752         default:
00753             break;
00754     }
00755 }
00756 
00757 /************************************************************************
00758 * DESCRIPTION: Compare R names.
00759 ************************************************************************/
00760 static fnet_bool_t fnet_mdns_cmp_rr_name(const char *rr_name, const char *name_1, const char *name_2)
00761 {
00762     FNET_ASSERT(rr_name != NULL);
00763     FNET_ASSERT(name_1 != NULL);
00764     FNET_ASSERT(name_2 != NULL);
00765 
00766     fnet_bool_t   result;
00767 
00768     result = fnet_mdns_cmp_name(&rr_name, name_1);
00769     if( result == FNET_TRUE)
00770     {
00771         result = fnet_mdns_cmp_name(&rr_name, name_2);
00772         if( result == FNET_TRUE)
00773         {
00774             result = fnet_mdns_cmp_name(&rr_name, FNET_MDNS_DOMAIN_NAME);
00775         }
00776     }
00777 
00778     return result;
00779 }
00780 
00781 /************************************************************************
00782 * DESCRIPTION: Compare R name with sub-name. 
00783 ************************************************************************/
00784 static fnet_bool_t fnet_mdns_cmp_name(const char **rr_name_p, const char *name)
00785 {
00786     FNET_ASSERT(rr_name_p != NULL);
00787     FNET_ASSERT(name != NULL);
00788 
00789     fnet_index_t        i=0;
00790     const fnet_char_t   *rr_name = *rr_name_p;
00791     fnet_uint32_t       name_length = fnet_strlen(name);
00792     fnet_uint32_t       rr_name_length = fnet_strlen(rr_name);
00793 
00794     if(name_length)
00795     {
00796         if(name_length > rr_name_length)
00797         {
00798             return FNET_FALSE;
00799         }
00800 
00801         rr_name++; /* Skip length byte */
00802 
00803         for(i=0; i<name_length; i++)
00804         {
00805             if(name[i] == '.')
00806             {
00807                 continue;
00808             }
00809 
00810             if(fnet_tolower(rr_name[i]) != fnet_tolower(name[i]))
00811             {
00812                 return FNET_FALSE;
00813             }
00814         }
00815 
00816         *rr_name_p = &rr_name[i];
00817     }
00818 
00819     return FNET_TRUE;
00820 }
00821 
00822 /************************************************************************
00823 * DESCRIPTION: Put RR name to rr_name. Retutns pointer to the next pointer; 0 if error. 
00824 If rr_name or rr_name_size are 0, just skip name. 
00825 ************************************************************************/
00826 static const fnet_uint8_t *fnet_mdns_get_rr_name(char *rr_name, fnet_uint32_t rr_name_size, const fnet_uint8_t *rr, const fnet_uint8_t *packet)
00827 {
00828     FNET_ASSERT(rr != NULL);
00829     FNET_ASSERT(packet != NULL);
00830 
00831     const fnet_uint8_t   *ptr = rr;
00832     fnet_uint8_t         length = *rr;
00833     fnet_uint16_t        offset = 0;
00834     const fnet_uint8_t   *result = ptr; 
00835 
00836     while(length != 0)
00837     {
00838         /* Check if compression is used */
00839         while((*ptr & FNET_MDNS_DOMAIN_NAME_COMPRESSION) == FNET_MDNS_DOMAIN_NAME_COMPRESSION)
00840         {
00841             if(offset == 0) /* Is it first compression?*/
00842             {
00843                 result += 2; /* 2 bytes (compression+length) */
00844             }
00845 
00846             offset = (fnet_uint16_t)((*ptr) & ~FNET_MDNS_DOMAIN_NAME_COMPRESSION)<<8;
00847             offset = offset + *(ptr + 1);
00848             if(offset < FNET_MDNS_PACKET_SIZE) /* Check maximum offset */
00849             {
00850                 ptr = packet+offset;
00851             }
00852             else
00853             {
00854                 /* Wrong offset */
00855                 goto ERROR;
00856             }
00857         }
00858 
00859         if((*ptr & FNET_MDNS_DOMAIN_NAME_COMPRESSION) != 0) /* Top two bits may be used only by the compression flag.*/
00860         {
00861             goto ERROR;
00862         }
00863                 
00864         length = *ptr;
00865 
00866         if( rr_name && rr_name_size ) /* Copy to rr_name buffer.*/
00867         {
00868             if((size_t)(length+1) <= rr_name_size) /* Check maximum rr_name_size */
00869             {
00870                 fnet_memcpy(rr_name, ptr, length+1);
00871 
00872                 rr_name += (length+1);
00873                 rr_name_size -= (length+1);
00874             }        
00875             else
00876             {
00877                 goto ERROR;
00878             }
00879         }
00880 
00881         ptr += (length+1);
00882         if(ptr > result)
00883         {
00884             result = ptr;
00885         }
00886     }
00887 
00888     return result;
00889 ERROR:
00890     return NULL;
00891 }
00892 
00893 /************************************************************************
00894 * DESCRIPTION: Get query type.
00895 ************************************************************************/
00896 static fnet_mdns_query_type_t fnet_mdns_get_query_type(fnet_uint16_t type)
00897 {
00898     fnet_mdns_query_type_t query_rr_type;
00899 
00900     switch(type)
00901     {
00902         case FNET_HTONS(FNET_MDNS_RR_PTR):
00903             query_rr_type = FNET_MDNS_QUERY_PTR;
00904             break;
00905         case FNET_HTONS(FNET_MDNS_RR_TXT):
00906             query_rr_type = FNET_MDNS_QUERY_TXT;
00907             break;
00908         case FNET_HTONS(FNET_MDNS_RR_SRV):
00909             query_rr_type = FNET_MDNS_QUERY_SRV;
00910             break;
00911         case FNET_HTONS(FNET_MDNS_RR_A):
00912             query_rr_type = FNET_MDNS_QUERY_A;
00913             break;
00914         case FNET_HTONS(FNET_MDNS_RR_AAAA):
00915             query_rr_type = FNET_MDNS_QUERY_AAAA;
00916             break;
00917         case FNET_HTONS(FNET_MDNS_RR_ANY):
00918             query_rr_type = FNET_MDNS_QUERY_ANY;
00919             break; 
00920         default:
00921             query_rr_type = FNET_MDNS_QUERY_NONE;
00922             break;                                
00923     }
00924 
00925     return query_rr_type;
00926 }
00927 
00928 /* Print query name */
00929 /************************************************************************
00930 * DESCRIPTION: Print MDNS query name.
00931 ************************************************************************/
00932 #if FNET_CFG_DEBUG_MDNS && FNET_CFG_DEBUG
00933 static void fnet_mdns_print_qe_name(const fnet_char_t *prefix, const fnet_char_t *qe_name)
00934 {
00935     fnet_size_t     qe_name_legth = fnet_strlen(qe_name);
00936     fnet_uint8_t    name_length_index = 0;
00937     fnet_index_t    i;
00938 
00939     fnet_print("%s", prefix); /* Print prefix*/    
00940 
00941     for(i=0; i<qe_name_legth; i++)
00942     {
00943         if(i == name_length_index)
00944         {
00945             fnet_print("."); /* Instead of name length */
00946             name_length_index += qe_name[i]+1; /* Next name length byte */
00947         }
00948         else
00949         {
00950             fnet_print("%c", qe_name[i]);
00951         }
00952     }
00953 
00954     //fnet_prinln("");
00955 }
00956 #endif
00957 
00958 /************************************************************************
00959 * DESCRIPTION: Received MDNS query (request) and process it.
00960 ************************************************************************/
00961 static const fnet_uint8_t * fnet_mdns_process_query(fnet_mdns_if_t *mdns_if, fnet_address_family_t address_family, const fnet_uint8_t *ptr, fnet_uint8_t *packet, fnet_uint32_t packet_size)
00962 {
00963     FNET_ASSERT(mdns_if != NULL);
00964     FNET_ASSERT(ptr != NULL);
00965     FNET_ASSERT(packet != NULL);
00966 
00967     fnet_char_t            qe_name[FNET_MDNS_RR_NAME_LEN_MAX] = {0};
00968     fnet_mdns_header_t     *mdns_header = (fnet_mdns_header_t *)packet;
00969     fnet_mdns_qe_header_t  *qe_header;
00970     fnet_mdns_service_if_t *service = NULL;
00971 
00972     if( packet_size > (sizeof(fnet_mdns_header_t) + sizeof(fnet_mdns_qe_header_t)) )
00973     {
00974         /* Get Requested name */
00975         ptr = fnet_mdns_get_rr_name(qe_name, sizeof(qe_name), ptr, packet);
00976 
00977         if(ptr)
00978         {
00979             qe_header = (fnet_mdns_qe_header_t*)ptr;
00980 
00981             switch(mdns_if->state)
00982             {
00983                 case FNET_MDNS_STATE_ANNOUNCING:
00984                 case FNET_MDNS_STATE_WAITING_REQUEST:
00985                     /* Compare received hostname with my_device.local, my_device._hap._tcp.local or _hap._tcp.local */
00986                     if( fnet_mdns_is_our_host_name(mdns_if, qe_name)
00987                         || (service = fnet_mdns_get_service_by_name(mdns_if, qe_name))     /* service instance name */
00988                         || (service = fnet_mdns_get_service_by_type(mdns_if, qe_name)) )   /* service type in a domain */
00989                     {
00990                     #if FNET_CFG_DEBUG_MDNS && FNET_CFG_DEBUG
00991                         fnet_mdns_print_qe_name("MDNS: RX Query for:", qe_name);
00992                     #endif
00993 
00994                         /* Check query record */ //TBD move it UP
00995                         if( (qe_header->rr_class &(~FNET_HTONS(FNET_MDNS_HEADER_CACHE_FLUSH)))== FNET_HTONS(FNET_MDNS_HEADER_CLASS_IN)) /* Support only IN = Internet protocol. Ignore flush flag.*/
00996                         {
00997                             fnet_mdns_query_type_t query_type = fnet_mdns_get_query_type(qe_header->type);
00998                             if(fnet_mdns_get_service_by_type(mdns_if, qe_name)) /* Service Type has only PTR record.*/
00999                             {
01000                                 query_type &= FNET_MDNS_QUERY_PTR;
01001                                 if(query_type) /* Shared response.*/
01002                                 {
01003                                     if(mdns_if->is_shared == FNET_FALSE)
01004                                     {
01005                                         mdns_if->is_shared = FNET_TRUE;
01006                                         mdns_if->is_shared_timestamp = fnet_timer_get_ms();
01007                                     }
01008                                     else if((fnet_timer_get_ms() - mdns_if->is_shared_timestamp) > FNET_MDNS_SHARED_RESPONSE_DELAY)
01009                                     {
01010                                         mdns_if->is_shared = FNET_FALSE;
01011                                     }
01012                                 }
01013                             }
01014                             /* Send later */
01015                             mdns_if->response_type |= query_type;
01016                             if(service)
01017                             {
01018                                 service->response_type |= query_type;
01019                             }
01020                             mdns_if->response_address_family |= address_family;         
01021                         }
01022                     }
01023                     break;
01024                 case FNET_MDNS_STATE_PROBING:
01025                     /* Compare received hostname with my_device.local or my_device._hap._tcp.local*/
01026                     if(fnet_mdns_is_our_host_name(mdns_if, qe_name) 
01027                         || fnet_mdns_get_service_by_name(mdns_if, qe_name)) 
01028                     {
01029                     #if FNET_CFG_DEBUG_MDNS && FNET_CFG_DEBUG
01030                         fnet_mdns_print_qe_name("MDNS: RX Probe for:", qe_name);
01031                     #endif
01032 
01033                         /* Simultaneous Probe Tiebreaking */
01034                         /* RFC6762: When a host that is probing for a record sees another host issue a
01035                         * query for the same record, it consults the Authority Section of that
01036                         * query.  If it finds any resource record(s) there which answers the
01037                         * query, then it compares the data of that (those) resource record(s)
01038                         * with its own tentative data. */
01039                         if(mdns_header->nscount > 0)
01040                         {
01041                             const fnet_uint8_t *authority_ptr;
01042 
01043                             authority_ptr = fnet_mdns_get_ns(packet, packet_size); /* Authority section */
01044                             fnet_mdns_process_simultaneous_probe(mdns_if, authority_ptr, packet, packet_size);
01045                         }
01046                     }
01047                     break;
01048                 default:
01049                     /* Ignore.*/
01050                     break;
01051             }
01052 
01053             ptr += sizeof(fnet_mdns_qe_header_t);
01054         }
01055     }
01056 
01057     return ptr;
01058 }
01059 
01060 /************************************************************************
01061 * DESCRIPTION: Avoid duplicate answer. 
01062 ************************************************************************/
01063 static void fnet_mdns_process_duplicate_answer(fnet_mdns_if_t *mdns_if, const fnet_uint8_t *an_ptr, const fnet_uint8_t *packet, fnet_uint32_t packet_size)
01064 {
01065     FNET_ASSERT(mdns_if != NULL);
01066     FNET_ASSERT(an_ptr != NULL);
01067     FNET_ASSERT(packet != NULL); 
01068 
01069     fnet_uint8_t            our_rr[FNET_MDNS_RR_PROBE_LEN_MAX];
01070     fnet_mdns_header_t      *mdns_header = (fnet_mdns_header_t *)packet;
01071     fnet_uint16_t           an_count = FNET_HTONS(mdns_header->ancount);
01072     const fnet_uint8_t      *ptr = an_ptr;
01073     fnet_mdns_rr_header_t   *rr_header;   
01074     fnet_uint32_t           i;
01075     fnet_mdns_query_type_t  rr_type;
01076     fnet_bool_t             skip;
01077     fnet_mdns_service_if_t  *service;
01078     char                    rr_name[FNET_MDNS_RR_NAME_LEN_MAX];
01079 
01080     /* Check all RRs in known answer records.*/
01081     for(i=0; ptr && (i<an_count) && (ptr < (packet + packet_size)); i++ )
01082     {
01083         service = NULL;
01084 
01085         rr_header = (fnet_mdns_rr_header_t *)fnet_mdns_get_rr_name(rr_name, sizeof(rr_name), ptr, packet);
01086         if(rr_header == NULL)
01087         {
01088             goto ERROR;
01089         }
01090 
01091         rr_type = fnet_mdns_get_query_type(rr_header->type);
01092  
01093         skip = FNET_FALSE;
01094 
01095         /* Generate our record.*/
01096         switch(rr_type)
01097         {
01098             case FNET_MDNS_QUERY_PTR:
01099                 service = fnet_mdns_get_service_by_type(mdns_if, rr_name);
01100                 if(service)
01101                 {
01102                     if(fnet_mdns_add_rr_ptr(mdns_if, our_rr, sizeof(our_rr), service, mdns_if->rr_ttl, FNET_FALSE) == NULL)
01103                     {
01104                         goto ERROR;
01105                     }
01106                 }
01107                 else
01108                 {
01109                     skip = FNET_TRUE;
01110                 }
01111                 break;
01112             case FNET_MDNS_QUERY_TXT:
01113                 service = fnet_mdns_get_service_by_name(mdns_if, rr_name);
01114                 if(service)
01115                 {
01116                     if(fnet_mdns_add_rr_txt(mdns_if, our_rr, sizeof(our_rr), service, mdns_if->rr_ttl, FNET_FALSE, FNET_FALSE) == NULL)
01117                     {
01118                         goto ERROR;
01119                     }
01120                 }
01121                 else
01122                 {
01123                     skip = FNET_TRUE;
01124                 }
01125                 break;
01126             case FNET_MDNS_QUERY_SRV:
01127                 service = fnet_mdns_get_service_by_name(mdns_if, rr_name);
01128                 if(service)
01129                 {
01130                     if(fnet_mdns_add_rr_srv(mdns_if, our_rr,  sizeof(our_rr), service, mdns_if->rr_ttl, FNET_FALSE, FNET_FALSE) == NULL)
01131                     {
01132                         goto ERROR;
01133                     }
01134                 }
01135                 else
01136                 {
01137                     skip = FNET_TRUE;
01138                 }
01139                 break;
01140             case FNET_MDNS_QUERY_AAAA:
01141                 if(fnet_mdns_add_rr_aaaa(mdns_if, our_rr,  sizeof(our_rr), mdns_if->rr_ttl_ip, FNET_FALSE, FNET_FALSE) == NULL)
01142                 {
01143                     goto ERROR;
01144                 }
01145                 break;
01146             case FNET_MDNS_QUERY_A:
01147 #if FNET_CFG_IP4
01148                 if(fnet_mdns_add_rr_a(mdns_if, our_rr,  sizeof(our_rr), mdns_if->rr_ttl, FNET_FALSE, FNET_FALSE) == NULL)
01149                 {
01150                     goto ERROR;
01151                 }
01152 #endif
01153                 break;
01154             default:
01155                 skip = FNET_TRUE;
01156                 break;
01157         }
01158         
01159         if(skip == FNET_TRUE)
01160         {   /* Skip RR record.*/
01161             ptr += sizeof(fnet_mdns_rr_header_t) + FNET_HTONS(rr_header->data_length);
01162         }
01163         else
01164         {
01165             /* Check if the same RR in answer section.*/
01166             if(fnet_mdns_cmp_rr(our_rr, &ptr, packet) == 0)
01167             {
01168                 /* Remove duplicate answer */
01169                 if(service)
01170                 {
01171                     service->response_type = (fnet_mdns_query_type_t)(service->response_type & (~rr_type));
01172                 }
01173                 else
01174                 {
01175                     mdns_if->response_type = (fnet_mdns_query_type_t)(mdns_if->response_type & (~rr_type));
01176                 }
01177                 FNET_DEBUG_MDNS("MDNS: RX Duplicate Answer for: %s ; rr_type =0x%X", our_rr, rr_type);
01178             }
01179         }
01180     }
01181 ERROR:
01182     return;
01183 }
01184 
01185 /************************************************************************
01186 * DESCRIPTION: Simultaneous Probe Tiebreaking.
01187 ************************************************************************/
01188 static void fnet_mdns_process_simultaneous_probe(fnet_mdns_if_t *mdns_if, const fnet_uint8_t *ns_ptr, fnet_uint8_t *packet, fnet_uint32_t packet_size)
01189 {
01190     FNET_ASSERT(mdns_if != NULL);
01191     FNET_ASSERT(ns_ptr != NULL);
01192     FNET_ASSERT(packet != NULL);
01193 
01194     fnet_uint8_t        our_rr[FNET_MDNS_RR_PROBE_LEN_MAX] = {0};
01195     fnet_mdns_header_t  *mdns_header = (fnet_mdns_header_t *)packet;
01196     fnet_uint16_t       ns_count = FNET_HTONS(mdns_header->nscount);
01197     fnet_bool_t         is_win = FNET_FALSE;
01198 
01199     FNET_DEBUG_MDNS("MDNS: RX Simultaneous probe");
01200 
01201     (void)packet_size;
01202 #if FNET_CFG_IP4
01203     /* Prepare and Compare Our RR A record */
01204     if(fnet_mdns_add_rr_a(mdns_if, our_rr,  sizeof(our_rr), mdns_if->rr_ttl, FNET_FALSE, FNET_FALSE) == NULL)
01205     {
01206         goto ERROR;
01207     }
01208 #endif
01209 
01210     if(fnet_mdns_is_rr_win(our_rr, ns_ptr, ns_count, packet) == FNET_TRUE)
01211     {
01212         /* Prepare and Compare Our RR AAAA record */
01213         if(fnet_mdns_add_rr_aaaa(mdns_if, our_rr,  sizeof(our_rr), mdns_if->rr_ttl_ip, FNET_FALSE, FNET_FALSE) == NULL)
01214         {
01215             goto ERROR;
01216         }
01217         if(fnet_mdns_is_rr_win(our_rr, ns_ptr, ns_count, packet) == FNET_TRUE)
01218         {
01219             fnet_uint32_t    i;
01220             
01221             is_win = FNET_TRUE;    
01222             
01223             for(i = 0; i<FNET_CFG_MDNS_SERVICE_MAX; i++)
01224             {
01225                 if(mdns_if->service_if_list[i].service_type != NULL) 
01226                 {
01227                     /* Prepare and Compare Our RR SRV records */
01228                     if(fnet_mdns_add_rr_srv(mdns_if, our_rr,  sizeof(our_rr), &mdns_if->service_if_list[i], mdns_if->rr_ttl, FNET_FALSE, FNET_FALSE) == NULL)
01229                     {
01230                         goto ERROR;
01231                     }
01232                     if(fnet_mdns_is_rr_win(our_rr, ns_ptr, ns_count, packet) == FNET_TRUE)
01233                     {
01234                         is_win = FNET_TRUE;
01235                     }
01236                     else
01237                     {
01238                         is_win = FNET_FALSE;
01239                         break; 
01240                     }
01241                 }
01242             }
01243         }
01244     }
01245 
01246     if(is_win == FNET_FALSE)
01247     {
01248         /* RFC6762: If the host finds that its
01249         own data is lexicographically earlier, then it defers to the winning
01250         host by waiting one second, and then begins probing for this record again.*/
01251         mdns_if->probe_wait_interval = FNET_MDNS_PROBE_DEFER_WAIT;     
01252         /* Save conflict timestamp.*/
01253         mdns_if->host_name_conflict_timestamp = fnet_timer_get_ms(); //TBD move to state change.
01254         fnet_mdns_change_state(mdns_if, FNET_MDNS_STATE_PROBING_WAIT); /* Reset probing.*/
01255     }
01256 ERROR:
01257     return;
01258 }
01259 
01260 /************************************************************************
01261 * DESCRIPTION: Get pointer to Answer Record. 
01262 ************************************************************************/
01263 static const fnet_uint8_t *fnet_mdns_get_an(const fnet_uint8_t *packet, fnet_uint32_t packet_size)
01264 {
01265     FNET_ASSERT(packet != NULL);
01266 
01267     fnet_mdns_header_t      *mdns_header = (fnet_mdns_header_t *)packet;
01268     fnet_uint16_t           qd_count; /* Question Count */
01269     fnet_uint16_t           an_count; /* Answer Record Count */    
01270     const fnet_uint8_t      *result = NULL;
01271     fnet_index_t            i;
01272     const fnet_uint8_t      *ptr;
01273 
01274     if(packet_size > sizeof(fnet_mdns_header_t))
01275     {
01276         qd_count = FNET_HTONS(mdns_header->qdcount);  /* Question Count */
01277         an_count = FNET_HTONS(mdns_header->ancount);  /* Answer Record Count */
01278     
01279         /* Skip mDNS header.*/
01280         ptr = packet + sizeof(fnet_mdns_header_t);
01281 
01282         /* Skip Questions.*/
01283         for(i=0; (i < qd_count) && (ptr < (packet + packet_size)); i++)
01284         {
01285             /* Get Requested name */
01286             ptr = fnet_mdns_get_rr_name(NULL, 0, ptr, packet);
01287 
01288             if(ptr)
01289             {
01290                 ptr += sizeof(fnet_mdns_qe_header_t);
01291             }
01292             else
01293             {
01294                 goto ERROR;
01295             }
01296         }
01297 
01298         if(an_count > 0)
01299         {
01300             result = ptr; /*Pointer to Answer Record*/
01301         }
01302     }
01303 
01304 ERROR:
01305     return result;
01306 }
01307 
01308 /************************************************************************
01309 * DESCRIPTION: Get pointer to Name Server (Authority Record). 
01310 ************************************************************************/
01311 static const fnet_uint8_t *fnet_mdns_get_ns(fnet_uint8_t *packet, fnet_uint32_t packet_size)
01312 {
01313     FNET_ASSERT(packet != NULL);
01314 
01315     fnet_mdns_header_t      *mdns_header = (fnet_mdns_header_t *)packet;
01316     fnet_uint16_t           qd_count; /* Question Count */
01317     fnet_uint16_t           an_count; /* Answer Record Count */    
01318     fnet_uint16_t           ns_count; /* Authority Record Count */   
01319     const fnet_uint8_t      *result = NULL;
01320     fnet_index_t            i;
01321     const fnet_uint8_t      *ptr;
01322 
01323     if(packet_size > sizeof(fnet_mdns_header_t))
01324     {
01325         qd_count = FNET_HTONS(mdns_header->qdcount);  /* Question Count */
01326         an_count = FNET_HTONS(mdns_header->ancount);  /* Answer Record Count */
01327         ns_count = FNET_HTONS(mdns_header->nscount);  /* Authority Record Count */
01328     
01329         /* Skip mDNS header.*/
01330         ptr = packet + sizeof(fnet_mdns_header_t);
01331 
01332         /* Skip Questions.*/
01333         for(i=0; (i < qd_count) && (ptr < (packet + packet_size)); i++)
01334         {
01335             /* Get Requested name */
01336             ptr = fnet_mdns_get_rr_name(NULL, 0, ptr, packet);
01337 
01338             if(ptr)
01339             {
01340                 ptr += sizeof(fnet_mdns_qe_header_t);
01341             }
01342             else
01343             {
01344                 goto ERROR;
01345             }
01346         }
01347 
01348         /* Skip Answers.*/
01349         for(i=0; (i < an_count) && (ptr < (packet + packet_size)); i++)
01350         {
01351             fnet_mdns_rr_header_t *rr_header;
01352 
01353             /* Get RR name */
01354             ptr = fnet_mdns_get_rr_name(NULL, 0, ptr, packet);
01355 
01356             if(ptr)
01357             {
01358                 rr_header = (fnet_mdns_rr_header_t *)ptr;
01359                 ptr += sizeof(fnet_mdns_rr_header_t) + FNET_HTONS(rr_header->data_length);
01360             }
01361             else
01362             {
01363                 goto ERROR;
01364             }
01365         }  
01366 
01367         if(ns_count > 0)
01368         {
01369             result = ptr; /*Pointer to Authority Record*/
01370         }
01371     }
01372 
01373 ERROR:
01374     return result;
01375 }
01376 
01377 /************************************************************************
01378 * DESCRIPTION: Compare RRs.
01379 ************************************************************************/
01380 static fnet_int32_t fnet_mdns_cmp_rr(fnet_uint8_t *our_rr, const fnet_uint8_t **rr, const fnet_uint8_t *packet)
01381 {
01382     FNET_ASSERT(our_rr != NULL);
01383     FNET_ASSERT(rr != NULL);
01384     FNET_ASSERT(packet != NULL);
01385 
01386     fnet_uint16_t           rr_type;        /* RR type */
01387     fnet_uint16_t           rr_class;       /* RR class */
01388     const fnet_uint8_t      *rr_data;
01389     fnet_uint16_t           rr_data_length; 
01390     fnet_mdns_rr_header_t   *rr_header;
01391     const fnet_uint8_t      *ptr = *rr;
01392     fnet_char_t             rr_name[FNET_MDNS_RR_NAME_LEN_MAX];
01393     fnet_uint16_t           our_rr_type;        /* RR type */
01394     fnet_uint16_t           our_rr_class;       /* RR class */
01395     const fnet_uint8_t      *our_rr_data;
01396     fnet_uint16_t           our_rr_data_length;
01397     fnet_mdns_rr_header_t   *our_rr_header;   
01398     fnet_int32_t            result;
01399 
01400     our_rr_header = (fnet_mdns_rr_header_t *)(our_rr + fnet_strlen((char *)our_rr)+1);
01401     our_rr_class = FNET_HTONS(our_rr_header->rr_class);
01402     our_rr_type = FNET_HTONS(our_rr_header->type);
01403     our_rr_data = ((fnet_uint8_t *)our_rr_header) + sizeof(fnet_mdns_rr_header_t);
01404     our_rr_data_length = FNET_HTONS(our_rr_header->data_length);
01405 
01406     /* RFC6762: When a host that is probing for a record sees another host issue a
01407     query for the same record, it consults the Authority Section of that
01408     query.  If it finds any resource record(s) there which answers the
01409     query, then it compares the data of that (those) resource record(s)
01410     with its own tentative data.  We consider first the simple case of a
01411     host probing for a single record, receiving a simultaneous probe from
01412     another host also probing for a single record.  The two records are
01413     compared and the lexicographically later data wins.*/
01414 
01415     /* Get RR name */
01416     ptr = fnet_mdns_get_rr_name(rr_name, sizeof(rr_name), ptr, packet);
01417     if(ptr)
01418     {
01419         rr_header = (fnet_mdns_rr_header_t *)ptr;
01420         ptr += sizeof(fnet_mdns_rr_header_t); 
01421 
01422         rr_data_length = FNET_HTONS(rr_header->data_length);
01423      
01424         /* Compare RR names.*/
01425         if(fnet_strcmp((char*)our_rr, (char*)rr_name) == 0)
01426         {
01427             rr_data = ptr;
01428             rr_class = FNET_HTONS(rr_header->rr_class) & (~FNET_HTONS(FNET_MDNS_HEADER_CACHE_FLUSH));
01429             rr_type = FNET_HTONS(rr_header->type);
01430      
01431             /* RFC6762: The determination of "lexicographically later" is performed by first
01432             comparing the record class (excluding the cache-flush bit described
01433             in Section 10.2), then the record type, then raw comparison of the
01434             binary content of the rdata without regard for meaning or structure.
01435             If the record classes differ, then the numerically greater class is
01436             considered "lexicographically later".*/
01437             if(rr_class < our_rr_class)
01438             {
01439                 result = 1; /* Win. */
01440             }
01441             else if(rr_class > our_rr_class)
01442             {
01443                 result = -1; /* Loss. */
01444             }
01445             else
01446             {
01447                 /* RFC6762: Otherwise, if the record types
01448                 differ, then the numerically greater type is considered
01449                 "lexicographically later".*/ 
01450                 if(rr_type < our_rr_type)
01451                 {
01452                     result = 1; /* Win. */
01453                 }
01454                 else if(rr_type > our_rr_type)
01455                 {
01456                     result = -1; /* Loss. */
01457                 }
01458                 /* RFC6762: If the rrtype and rrclass both match,
01459                 then the rdata is compared.*/ 
01460                 else if(rr_data_length) 
01461                 {
01462                     int             cmp_res;
01463                     fnet_uint16_t        cmp_length;
01464      
01465                     cmp_length = (rr_data_length > our_rr_data_length)? our_rr_data_length : rr_data_length; /* Get min length value */
01466      
01467                     cmp_res = fnet_memcmp(rr_data, our_rr_data, cmp_length);
01468      
01469                     if(cmp_res < 0)
01470                     {
01471                         result = 1; /* Win. */
01472                     }                                              
01473                     else if (cmp_res > 0) 
01474                     {
01475                         result = -1; /* Loss. */
01476                     }
01477                     else /* cmp_res == 0 */
01478                     {
01479                         /* RFC:If both lists run out of records at the same time without any difference
01480                         being found, then this indicates that two devices are advertising
01481                         identical sets of records, as is sometimes done for fault tolerance,
01482                         and there is, in fact, no conflict.*/
01483                         if(rr_data_length < our_rr_data_length)
01484                         {
01485                             result = 1; /* Win. */
01486                         }
01487                         else if(rr_data_length > our_rr_data_length)
01488                         {
01489                             result = -1; /* Loss. */
01490                         }
01491                         else
01492                         {
01493                             /* Check TTL. Used for Duplicate Suppression */
01494                             if(FNET_HTONL(rr_header->ttl) > (FNET_HTONL(our_rr_header->ttl)>>1))
01495                             {
01496                                 result = 0; /* Absoulutely same records */
01497                             }
01498                             else
01499                             {
01500                                 result = 1; 
01501                             }
01502                         }
01503                     }
01504                 }
01505                 else
01506                 {
01507                     result = 1; /* Win. */
01508                 }
01509             }
01510         }
01511         else
01512         {
01513             result = 1; /* Win. */
01514         }
01515 
01516         ptr += rr_data_length;
01517     }
01518     else
01519     {
01520         /* Malformed packet.*/
01521         result = 1; /* Win. */
01522     }
01523 
01524     *rr = ptr;
01525 
01526     return result;
01527 }
01528 
01529 /************************************************************************
01530 * DESCRIPTION: Is our RR winner.
01531 ************************************************************************/
01532 static fnet_bool_t fnet_mdns_is_rr_win(fnet_uint8_t *our_rr, const fnet_uint8_t *ns_ptr, fnet_uint16_t ns_count, fnet_uint8_t *packet)
01533 {
01534     FNET_ASSERT(our_rr != NULL);
01535     FNET_ASSERT(ns_ptr != NULL);
01536 
01537     fnet_index_t              i;
01538     const fnet_uint8_t        *ptr = ns_ptr;
01539     fnet_bool_t               result;
01540 
01541     /* RFC6762: When a host that is probing for a record sees another host issue a
01542     query for the same record, it consults the Authority Section of that
01543     query.  If it finds any resource record(s) there which answers the
01544     query, then it compares the data of that (those) resource record(s)
01545     with its own tentative data.  We consider first the simple case of a
01546     host probing for a single record, receiving a simultaneous probe from
01547     another host also probing for a single record.  The two records are
01548     compared and the lexicographically later data wins.*/
01549 
01550     /* Check all RRs. Find lowest class */
01551     for(i=0; i<ns_count; i++ )
01552     {
01553         if(fnet_mdns_cmp_rr(our_rr, &ptr, packet) >= 0)
01554         {
01555             break; /* Win */
01556         }
01557     }
01558 
01559     if(i == ns_count)
01560     {
01561        result = FNET_FALSE; 
01562     }
01563     else
01564     {
01565        result = FNET_TRUE; 
01566     }
01567 
01568     return result;
01569 }
01570 
01571 /************************************************************************
01572 * DESCRIPTION: Process MDNS response 
01573 ************************************************************************/
01574 static const fnet_uint8_t *fnet_mdns_process_response(fnet_mdns_if_t *mdns_if, const fnet_uint8_t * ptr, fnet_uint8_t *packet, fnet_uint32_t packet_size)
01575 {
01576     FNET_ASSERT(mdns_if != NULL);
01577     FNET_ASSERT(ptr != NULL);
01578     FNET_ASSERT(packet != NULL);
01579 
01580     fnet_char_t    rr_name[FNET_MDNS_RR_NAME_LEN_MAX];
01581 
01582     /* Header follows the hostname and the terminating zero */
01583     fnet_mdns_rr_header_t *rr_header; 
01584 
01585     if( packet_size > (sizeof(fnet_mdns_header_t) + sizeof(fnet_mdns_rr_header_t)) ) /* TND make it universal*/
01586     {
01587         /* Get RR name */
01588         ptr = fnet_mdns_get_rr_name(rr_name, sizeof(rr_name), ptr, packet);
01589 
01590         if(ptr)
01591         {
01592             rr_header = (fnet_mdns_rr_header_t *)ptr;
01593             ptr += sizeof(fnet_mdns_rr_header_t) + FNET_HTONS(rr_header->data_length);
01594 
01595             /* Compare received hostname with my_device.local */
01596             if( (fnet_mdns_is_our_host_name(mdns_if, rr_name)
01597                 || fnet_mdns_get_service_by_name(mdns_if, rr_name))
01598                 && ( rr_header->rr_class == FNET_HTONS((FNET_MDNS_HEADER_CLASS_IN | FNET_MDNS_HEADER_CACHE_FLUSH)) )
01599             #if 0 /* Cause of Test warnings.*/
01600                 && ((rr_header->type == FNET_HTONS(FNET_MDNS_RR_SRV)) ||
01601                     (rr_header->type == FNET_HTONS(FNET_MDNS_RR_A)) || 
01602                     (rr_header->type == FNET_HTONS(FNET_MDNS_RR_AAAA))) 
01603             #endif
01604                 )   /* service instance name */
01605             {
01606                 FNET_DEBUG_MDNS("MDNS: RX response for - %s", rr_name);
01607 
01608                 /* RFC: In the case of a host
01609                 probing using query type "ANY" as recommended above, any answer
01610                 containing a record with that name, of any type, MUST be considered a
01611                 conflicting response and handled accordingly.*/
01612 
01613                 /* Save conflict timestamp.*/
01614                 mdns_if->host_name_conflict_timestamp = fnet_timer_get_ms();
01615 
01616                 /* If in Probing state, change name and try again */
01617                 if((mdns_if->state == FNET_MDNS_STATE_PROBING))
01618                 {
01619                     fnet_mdns_update_name_counter(mdns_if); /* Regenerate name.*/
01620                 }
01621 
01622                 /* RFC: If fifteen conflicts occur within any ten-second period, then the
01623                    host MUST wait at least five seconds before each successive
01624                    additional probe attempt.  This is to help ensure that, in the event
01625                    of software bugs or other unanticipated problems, errant hosts do not
01626                    flood the network with a continuous stream of multicast traffic.  For
01627                    very simple devices, a valid way to comply with this requirement is
01628                    to always wait five seconds after any failed probe attempt before
01629                    trying again.*/
01630                 /* We use the simple device aproach.*/
01631                 mdns_if->probe_wait_interval = FNET_MDNS_PROBE_WAIT;
01632                 fnet_mdns_change_state(mdns_if, FNET_MDNS_STATE_PROBING_WAIT); /* Reset probing.*/
01633             }
01634         }
01635     }
01636     else
01637     {
01638         ptr = NULL;
01639     }
01640 
01641     return ptr;
01642 }
01643 
01644 /************************************************************************
01645 * DESCRIPTION: MDNS receive.
01646 ************************************************************************/
01647 static void fnet_mdns_recv(fnet_mdns_if_t *mdns_if)
01648 {
01649     FNET_ASSERT(mdns_if != NULL);
01650 
01651     fnet_int32_t            received;
01652     fnet_mdns_header_t      *mdns_header;
01653     fnet_uint32_t           cnt=0;
01654     const fnet_uint8_t      *ptr;
01655     fnet_index_t            i;
01656     fnet_size_t             addr_len;
01657  
01658     /* Receive UDP data */
01659     addr_len = sizeof(mdns_if->remote_address);
01660     received = fnet_socket_recvfrom( mdns_if->socket_listen, mdns_if->buffer, sizeof(mdns_if->buffer), 0u, &mdns_if->remote_address, &addr_len );
01661     if(received > 0)
01662     {
01663         switch(mdns_if->state)
01664         {
01665             case FNET_MDNS_STATE_PROBING:
01666             case FNET_MDNS_STATE_ANNOUNCING:
01667             case FNET_MDNS_STATE_WAITING_REQUEST:
01668                 /* Received MDNS header */
01669                 if((size_t)received > sizeof(fnet_mdns_header_t))
01670                 {
01671                     mdns_header = (fnet_mdns_header_t*)&mdns_if->buffer[0];
01672  
01673                     char *hostname = (char*)&mdns_if->buffer[sizeof(fnet_mdns_header_t)];
01674  
01675                     /* Query */
01676                     if( ((mdns_header->flags & FNET_HTONS(FNET_MDNS_HEADER_FLAGS_QR)) == 0)       /* Query.*/
01677                                && ((mdns_header->flags & FNET_HTONS(FNET_MDNS_HEADER_FLAGS_OPCODE)) == 0) ) /* Standard Query */
01678                     {
01679                         if(mdns_if->remote_address.sa_port != FNET_MDNS_PORT)
01680                         {
01681                             mdns_if->is_legacy_unicast = FNET_TRUE;
01682                         }
01683                         else
01684                         {
01685                             mdns_if->is_legacy_unicast = FNET_FALSE;
01686                         }
01687  
01688                         if( (mdns_header->flags & FNET_HTONS(FNET_MDNS_HEADER_FLAGS_TC)) == 0)       /* Trancation.*/
01689                         {
01690                             mdns_if->is_truncated = FNET_FALSE;
01691                         }
01692                         else
01693                         {
01694                             mdns_if->is_truncated = FNET_TRUE;
01695                         }
01696  
01697                         ptr = (fnet_uint8_t*)hostname;
01698                         for(i=0; i<FNET_HTONS(mdns_header->qdcount); i++)
01699                         {
01700                             ptr = fnet_mdns_process_query(mdns_if, mdns_if->remote_address.sa_family, ptr, mdns_if->buffer, received);
01701                             if(ptr == NULL)
01702                             {
01703                                 return;
01704                             }
01705                         }
01706                         
01707                         /* Duplicate Suppression.*/
01708                         if(mdns_if->response_type != FNET_MDNS_QUERY_NONE)
01709                         {
01710                             const fnet_uint8_t           *an_ptr;
01711  
01712                             an_ptr = fnet_mdns_get_an(mdns_if->buffer, received);
01713                             
01714                             /* Eliminate duplicated answers */
01715                             if(an_ptr)
01716                             {
01717                                 fnet_mdns_process_duplicate_answer(mdns_if, an_ptr, mdns_if->buffer, received);
01718                             }
01719                         }
01720                     }
01721                     /* Response */
01722                     else if( ( ((mdns_header->flags & FNET_HTONS(FNET_MDNS_HEADER_FLAGS_QR)) != 0) &&      /* Response.*/
01723                             (mdns_header->qdcount == 0)) &&
01724                             ( (mdns_header->nscount > 0)
01725                             || (mdns_header->arcount > 0)
01726                             || (mdns_header->ancount > 0))
01727                             )
01728                     {
01729                         cnt = FNET_HTONS(mdns_header->nscount) + FNET_HTONS(mdns_header->arcount) + FNET_HTONS(mdns_header->ancount) + FNET_HTONS(mdns_header->qdcount);
01730  
01731                         ptr = (fnet_uint8_t*)hostname;
01732                         for(i=0; (i < cnt) && (ptr < (mdns_if->buffer + received)); i++)
01733                         {
01734                             ptr = fnet_mdns_process_response(mdns_if, ptr, mdns_if->buffer, received);
01735                             if(ptr == NULL)
01736                             {
01737                                 break;
01738                             }
01739                         }
01740                     }
01741                 }
01742                 break;
01743             case FNET_MDNS_STATE_PROBING_WAIT:
01744             default:
01745                 /* Ignore packet. */
01746                 break;
01747         }
01748     }
01749  
01750 }
01751 
01752 /************************************************************************
01753 * DESCRIPTION: Prepare domain name - replace dots by length of string 
01754 ************************************************************************/
01755 static fnet_uint8_t *fnet_mdns_add_domain_name(fnet_uint8_t *buf, fnet_uint32_t buf_size, const char * domain_name)
01756 {
01757     FNET_ASSERT(buf != NULL);
01758     FNET_ASSERT(domain_name != NULL);
01759 
01760     fnet_uint32_t   domain_len = fnet_strlen(domain_name) + 1;
01761     fnet_uint32_t   len = 0;
01762     fnet_index_t    i;      
01763     fnet_index_t    p = 0;
01764     fnet_uint8_t    *result = NULL;
01765 
01766     if(domain_len <= buf_size) /* Check buffer size limit */
01767     {
01768         for(i=0; i<domain_len; i++)
01769         {
01770             buf[i+1] = domain_name[i];
01771             len++;
01772 
01773             if(domain_name[i] == '.')
01774             {
01775                 buf[p] = len-1;
01776                 p = i+1;
01777                 len = 0;
01778             }
01779         }
01780 
01781         /* the last part */
01782         buf[p] = len ? len-1 : 0;
01783         result = buf + domain_len;
01784     }
01785 
01786     return result;
01787 }
01788 
01789 /************************************************************************
01790 * DESCRIPTION: Send probe query.
01791    RFC: All probe queries SHOULD be done
01792    using the desired resource record name and class (usually class 1,
01793    "Internet"), and query type "ANY" (255), to elicit answers for all
01794    types of records with that name.  This allows a single question to be
01795    used in place of several questions, which is more efficient on the
01796    network.  It also allows a host to verify exclusive ownership of a
01797    name for all rrtypes, which is desirable in most cases.
01798 ************************************************************************/
01799 static void fnet_mdns_send_probe(fnet_mdns_if_t *mdns_if)
01800 {
01801     FNET_ASSERT(mdns_if != NULL);
01802 
01803     fnet_uint8_t        *ptr;
01804     fnet_uint32_t       send_size = 0;
01805     fnet_uint16_t       nscount = 0;
01806     fnet_uint16_t       qdcount = 0;
01807     fnet_index_t        i;
01808     fnet_mdns_header_t  *mdns_header;
01809     fnet_uint8_t        *buf_end = &mdns_if->buffer[FNET_MDNS_PACKET_SIZE-1];
01810 
01811     fnet_memset(mdns_if->buffer, 0, sizeof(mdns_if->buffer));
01812 
01813     mdns_header = (fnet_mdns_header_t*)&mdns_if->buffer[0];
01814 
01815     ptr = (fnet_uint8_t*)mdns_header + sizeof(fnet_mdns_header_t);
01816 
01817     /* RFC: All probe queries SHOULD be done
01818     using the desired resource record name and class (usually class 1,
01819     "Internet"), and query type "ANY" (255), to elicit answers for all
01820     types of records with that name. */
01821 
01822     /* Question section: */
01823     /*RFC6762: When a host is probing for a group of related records with the same
01824     name (e.g., the SRV and TXT record describing a DNS-SD service), only
01825     a single question need be placed in the Question Section, since query
01826     type "ANY" (255) is used, which will elicit answers for all records
01827     with that name.*/
01828 
01829     /* Prepary ANY records with service name */
01830     for(i = 0; i<FNET_CFG_MDNS_SERVICE_MAX; i++)
01831     {
01832         if(mdns_if->service_if_list[i].service_type)
01833         {
01834             ptr = fnet_mdns_add_service_name(mdns_if, ptr, (buf_end - ptr), &mdns_if->service_if_list[i], FNET_TRUE);
01835             if(ptr == NULL)
01836             {
01837                 goto ERROR;
01838             }
01839             ptr = fnet_mdns_add_qe_any(ptr, (buf_end - ptr));
01840             if(ptr == NULL)
01841             {
01842                 goto ERROR;
01843             }
01844             qdcount++;
01845         }
01846     }
01847 
01848     /* Prepary ANY record with device/host name */
01849     ptr = fnet_mdns_add_host_name(mdns_if, ptr, (buf_end - ptr), FNET_TRUE);
01850     if(ptr == NULL)
01851     {
01852         goto ERROR;
01853     }
01854     ptr = fnet_mdns_add_qe_any(ptr, (buf_end - ptr));
01855     if(ptr == NULL)
01856     {
01857         goto ERROR;
01858     }
01859     qdcount++;
01860 
01861     /* Count */
01862     mdns_header->qdcount = FNET_HTONS(qdcount);
01863 
01864     /* Authority section: */
01865     /* RFC6762: A probe query can be distinguished from a normal query by the fact that a probe
01866     query contains a proposed record in the Authority Section that
01867     answers the question in the Question Section (for more details, see
01868     Section 8.2, "Simultaneous Probe Tiebreaking"). */
01869 
01870     /* RFC: For tiebreaking to work correctly in all
01871     cases, the Authority Section must contain *all* the records and
01872     proposed rdata being probed for uniqueness.*/
01873 
01874     /*  The cache-flush bit MUST NOT be set in any resource records in the
01875     Known-Answer list of any query message.*/
01876 
01877     /* Prepare RR SRV records */
01878     for(i = 0; i<FNET_CFG_MDNS_SERVICE_MAX; i++)
01879     {
01880         if(mdns_if->service_if_list[i].service_type)
01881         {
01882             ptr = fnet_mdns_add_rr_srv(mdns_if, ptr, (buf_end - ptr), &mdns_if->service_if_list[i], mdns_if->rr_ttl, FNET_FALSE, FNET_TRUE);
01883             if(ptr == NULL)
01884             {
01885                 goto ERROR;
01886             }
01887             nscount++;
01888         }
01889     }
01890 
01891 #if FNET_CFG_IP4
01892     /* Prepare RR A record */
01893     ptr = fnet_mdns_add_rr_a(mdns_if, ptr, (buf_end - ptr), mdns_if->rr_ttl, FNET_FALSE, FNET_TRUE);
01894     if(ptr == NULL)
01895     {
01896         goto ERROR;
01897     }
01898     nscount++;
01899 #endif
01900    
01901     /* Prepare RR AAAA record */
01902     ptr = fnet_mdns_add_rr_aaaa(mdns_if, ptr, (buf_end - ptr), mdns_if->rr_ttl_ip, FNET_FALSE, FNET_TRUE);
01903     if(ptr == NULL)
01904     {
01905         goto ERROR;
01906     }
01907     nscount++;
01908 
01909     mdns_header->nscount = FNET_HTONS(nscount);
01910 
01911     /* Message size.*/
01912     send_size = ptr - mdns_if->buffer;
01913 
01914     FNET_DEBUG_MDNS("MDNS: Probing...");
01915 
01916     /* Send mdns packet */
01917     fnet_mdns_send(mdns_if, mdns_if->addr_family, mdns_if->buffer, send_size);
01918 
01919 ERROR:
01920     mdns_if->probe_count++;
01921     return;
01922 }
01923 
01924 /************************************************************************
01925 * DESCRIPTION: Actual Send.
01926 ************************************************************************/
01927 static void fnet_mdns_send(fnet_mdns_if_t *mdns_if, fnet_address_family_t address_family, fnet_uint8_t *buffer, fnet_uint32_t send_size)
01928 {
01929     FNET_ASSERT(mdns_if != NULL);
01930     FNET_ASSERT(buffer != NULL);
01931 
01932     fnet_index_t     i;
01933     struct sockaddr  *address;
01934     struct sockaddr  multicast_addr;
01935 
01936     /* Reset Domain Name Compression pointers.*/
01937     mdns_if->offset_host_name = 0;
01938     for(i = 0; i<FNET_CFG_MDNS_SERVICE_MAX; i++)
01939     {
01940         mdns_if->service_if_list[i].offset_service_name = 0;
01941         mdns_if->service_if_list[i].offset_service_type = 0;
01942     }
01943 
01944     mdns_if->send_timestamp = fnet_timer_get_ms(); /* Save last sending time stamp.*/
01945 
01946 #if FNET_CFG_IP4
01947     if(address_family & AF_INET)
01948     {
01949         if(mdns_if->is_legacy_unicast == FNET_TRUE)
01950         {
01951             address = &mdns_if->remote_address;
01952         }
01953         else
01954         {
01955             fnet_memset_zero(&multicast_addr, sizeof(multicast_addr));
01956             multicast_addr.sa_family = AF_INET;
01957             multicast_addr.sa_port = FNET_MDNS_PORT;
01958             multicast_addr.sa_scope_id = fnet_netif_get_scope_id(mdns_if->netif);
01959             ((struct sockaddr_in*)(&multicast_addr))->sin_addr.s_addr = FNET_MDNS_IP4_MULTICAST_ADDR;
01960 
01961             address = &multicast_addr;
01962         }
01963 
01964         /* Send to IPv4 address */
01965         fnet_socket_sendto ( mdns_if->socket_listen, buffer, send_size, 0u, address, sizeof(*address) );
01966     }
01967 #endif
01968 #if FNET_CFG_IP6
01969     if(address_family & AF_INET6)
01970     {
01971         if(mdns_if->is_legacy_unicast == FNET_TRUE)
01972         {
01973             address = &mdns_if->remote_address;
01974         }
01975         else
01976         {
01977             fnet_memset_zero(&multicast_addr, sizeof(multicast_addr));
01978             multicast_addr.sa_family = AF_INET6;
01979             multicast_addr.sa_port = FNET_MDNS_PORT;
01980             multicast_addr.sa_scope_id = fnet_netif_get_scope_id(mdns_if->netif);
01981             FNET_IP6_ADDR_COPY(&fnet_mdns_ip6_multicast_addr, &((struct sockaddr_in6 *)(&multicast_addr))->sin6_addr.s6_addr);
01982 
01983             address = &multicast_addr;
01984         }
01985 
01986         /* Send to IPv6 address */
01987         fnet_socket_sendto ( mdns_if->socket_listen, buffer, send_size, 0u, address, sizeof(*address) );
01988     }
01989 #endif
01990 
01991     /* Reset flag.*/
01992     mdns_if->is_legacy_unicast = FNET_FALSE;
01993 }
01994 
01995 /************************************************************************
01996 * DESCRIPTION: Prepare all mdns records to send.
01997 ************************************************************************/
01998 static void fnet_mdns_send_response(fnet_mdns_if_t *mdns_if, fnet_uint32_t ttl, fnet_uint32_t ttl_ip)
01999 {
02000     FNET_ASSERT(mdns_if != NULL);
02001 
02002     fnet_uint8_t        *ptr;
02003     fnet_uint32_t       send_size = 0;
02004     fnet_mdns_header_t  *mdns_header = (fnet_mdns_header_t*)&mdns_if->buffer[0];
02005     fnet_uint16_t       answer_count = 0;
02006     fnet_uint16_t       additional_count = 0;
02007     fnet_bool_t         has_srv = FNET_FALSE;
02008     fnet_bool_t         has_ptr = FNET_FALSE;
02009     fnet_index_t        i;
02010     fnet_bool_t         flush;
02011     fnet_uint8_t        *buf_end = &mdns_if->buffer[FNET_MDNS_PACKET_SIZE-1];
02012 
02013     fnet_memset(mdns_if->buffer, 0, sizeof(mdns_if->buffer));
02014 
02015     ptr = (fnet_uint8_t*)mdns_header + sizeof(fnet_mdns_header_t);
02016     send_size += sizeof(fnet_mdns_header_t);
02017 
02018     mdns_header->flags |= FNET_HTONS(FNET_MDNS_HEADER_FLAGS_QR | FNET_MDNS_HEADER_FLAGS_C);
02019 
02020     if(mdns_if->is_legacy_unicast == FNET_TRUE)
02021     {
02022         /* RFC6762: The cache-flush  bit MUST NOT be set in legacy unicast responses.*/
02023         flush = FNET_FALSE;
02024     }
02025     else
02026     {
02027         flush = FNET_TRUE;
02028     }
02029 
02030     /* Answer records */
02031     for(i = 0; i<FNET_CFG_MDNS_SERVICE_MAX; i++)
02032     {
02033         if(mdns_if->service_if_list[i].service_type) 
02034         {
02035             /* Prepare TXT record */
02036             if(mdns_if->service_if_list[i].response_type & FNET_MDNS_QUERY_TXT)
02037             {
02038                 if((&mdns_if->service_if_list[i])->service_get_txt) /* Check if service has TXT */
02039                 {
02040                     ptr = fnet_mdns_add_rr_txt(mdns_if, ptr, (buf_end - ptr), &mdns_if->service_if_list[i], ttl, flush, FNET_TRUE);
02041                     if(ptr == NULL)
02042                     {
02043                         goto ERROR;
02044                     }
02045                     answer_count++;
02046                 }
02047             }
02048 
02049             /* Prepare RR PTR record */
02050             if(mdns_if->service_if_list[i].response_type & FNET_MDNS_QUERY_PTR)
02051             {
02052                 ptr = fnet_mdns_add_rr_ptr(mdns_if, ptr, (buf_end - ptr), &mdns_if->service_if_list[i], ttl, FNET_TRUE);
02053                 if(ptr == NULL)
02054                 {
02055                     goto ERROR;
02056                 }
02057                 answer_count++;
02058                 has_ptr = FNET_TRUE;
02059             }
02060 
02061             /* Prepare RR SRV record */
02062             if(mdns_if->service_if_list[i].response_type & FNET_MDNS_QUERY_SRV)
02063             {
02064                 ptr = fnet_mdns_add_rr_srv(mdns_if, ptr, (buf_end - ptr), &mdns_if->service_if_list[i], ttl, flush, FNET_TRUE);
02065                 if(ptr == NULL)
02066                 {
02067                     goto ERROR;
02068                 }
02069                 answer_count++;
02070                 has_srv = FNET_TRUE;
02071             }
02072         }
02073     }
02074 
02075 #if FNET_CFG_IP4
02076     // Do not send A record in IPV6 only stack
02077     /* Prepare RR A record */
02078     if(mdns_if->response_type & FNET_MDNS_QUERY_A) 
02079     {
02080         ptr = fnet_mdns_add_rr_a(mdns_if, ptr, (buf_end - ptr), ttl, flush, FNET_TRUE);
02081         if(ptr == NULL)
02082         {
02083             goto ERROR;
02084         }
02085         answer_count++;
02086     }
02087 #endif
02088 
02089     /* Prepare RR AAAA record */
02090     if(mdns_if->response_type & FNET_MDNS_QUERY_AAAA)
02091     {
02092         ptr = fnet_mdns_add_rr_aaaa(mdns_if, ptr, (buf_end - ptr), ttl_ip, flush, FNET_TRUE);
02093         if(ptr == NULL)
02094         {
02095             goto ERROR;
02096         }
02097         answer_count++;
02098     }
02099 
02100     /* Additional records */
02101 
02102     /* RFC6763: When including a DNS-SD Service Instance Enumeration or Selective
02103     Instance Enumeration (subtype) PTR record in a response packet, the
02104     server/responder SHOULD include the following additional records:
02105     o  The SRV record(s) named in the PTR rdata.
02106     o  The TXT record(s) named in the PTR rdata.
02107     o  All address records (type "A" and "AAAA") named in the SRV rdata.*/
02108     for(i = 0; i<FNET_CFG_MDNS_SERVICE_MAX; i++)
02109     {
02110         if(mdns_if->service_if_list[i].service_type) 
02111         {
02112             if(mdns_if->service_if_list[i].response_type & FNET_MDNS_QUERY_PTR)
02113             {
02114                 if((mdns_if->service_if_list[i].response_type & FNET_MDNS_QUERY_SRV) == 0)
02115                 {
02116                     ptr = fnet_mdns_add_rr_srv(mdns_if, ptr, (buf_end - ptr), &mdns_if->service_if_list[i], ttl, flush, FNET_TRUE);
02117                     if(ptr == NULL)
02118                     {
02119                         goto ERROR;
02120                     }
02121                     additional_count++;
02122                 }
02123 
02124                 if((mdns_if->service_if_list[i].response_type & FNET_MDNS_QUERY_TXT) == 0)
02125                 {
02126                     if((&mdns_if->service_if_list[i])->service_get_txt) /* Check if service has TXT */
02127                     {
02128                         ptr = fnet_mdns_add_rr_txt(mdns_if, ptr, (buf_end - ptr), &mdns_if->service_if_list[i], ttl, flush, FNET_TRUE);
02129                         if(ptr == NULL)
02130                         {
02131                             goto ERROR;
02132                         }
02133                         additional_count++;
02134                     }
02135                 }
02136             }
02137         }
02138     }
02139 
02140     /* RFC6763: When including an SRV record in a response packet, the
02141     server/responder SHOULD include the following additional records:
02142     o  All address records (type "A" and "AAAA") named in the SRV rdata.*/
02143     if((has_ptr == FNET_TRUE) || (has_srv == FNET_TRUE))
02144     {
02145 #if FNET_CFG_IP4
02146         if((mdns_if->response_type & FNET_MDNS_QUERY_A) == 0)
02147         {
02148             /* Prepare RR A record */
02149             ptr = fnet_mdns_add_rr_a(mdns_if, ptr, (buf_end - ptr), ttl, flush, FNET_TRUE);
02150             if(ptr == NULL)
02151             {
02152                 goto ERROR;
02153             }
02154             additional_count++;
02155         }
02156 #endif
02157         if((mdns_if->response_type & FNET_MDNS_QUERY_AAAA) == 0)
02158         {
02159             /* Prepare RR AAAA record */
02160             ptr = fnet_mdns_add_rr_aaaa(mdns_if, ptr, (buf_end - ptr), ttl_ip, flush, FNET_TRUE);
02161             if(ptr == NULL)
02162             {
02163                 goto ERROR;
02164             }
02165             additional_count++;
02166         }
02167     }
02168 
02169     /* RFC6762:  Multicast DNS responses MUST NOT contain any questions in the
02170     * Question Section.  */
02171     if(answer_count) /* Check if any answer for sending*/
02172     {
02173         /* Answers */
02174         mdns_header->ancount = FNET_HTONS(answer_count);
02175         /* Additional */
02176         mdns_header->arcount = FNET_HTONS(additional_count);
02177 
02178         send_size = ptr - (fnet_uint8_t*)mdns_header;
02179 
02180         /* Send all mdns records */
02181         fnet_mdns_send(mdns_if, mdns_if->response_address_family, mdns_if->buffer, send_size);
02182     }
02183 
02184 ERROR:
02185     /* Reset response parameters.*/
02186     mdns_if->response_type = FNET_MDNS_QUERY_NONE;
02187     for(i = 0; i<FNET_CFG_MDNS_SERVICE_MAX; i++)
02188     {
02189         mdns_if->service_if_list[i].response_type = FNET_MDNS_QUERY_NONE;
02190     }
02191     mdns_if->response_address_family = AF_UNSPEC;
02192     mdns_if->is_shared = FNET_FALSE;
02193     mdns_if->is_legacy_unicast = FNET_FALSE;
02194 }
02195 
02196 /************************************************************************
02197 * DESCRIPTION: Send announcement.
02198 ************************************************************************/
02199 static void fnet_mdns_send_announcement(fnet_mdns_if_t *mdns_if, fnet_uint32_t ttl, fnet_uint32_t ttl_ip)
02200 {
02201     FNET_ASSERT(mdns_if != NULL);
02202 
02203     fnet_index_t i;
02204 
02205     /* Set response_type to ANY */
02206     mdns_if->response_type = FNET_MDNS_QUERY_ANY;
02207     for(i = 0; i<FNET_CFG_MDNS_SERVICE_MAX; i++)
02208     {
02209         mdns_if->service_if_list[i].response_type = FNET_MDNS_QUERY_ANY;
02210     }
02211     mdns_if->response_address_family = mdns_if->addr_family;
02212 
02213     fnet_mdns_send_response(mdns_if, ttl, ttl_ip);
02214 }
02215 
02216 /************************************************************************
02217 * DESCRIPTION: Add record header.
02218 ************************************************************************/
02219 static fnet_uint8_t * fnet_mdns_add_rr_header(fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_mdns_rr_type_t type, fnet_bool_t flush, fnet_uint32_t ttl, fnet_uint16_t data_length)
02220 {
02221     FNET_ASSERT(buf != NULL);
02222 
02223     fnet_uint8_t            *ptr = buf;
02224     fnet_mdns_rr_header_t   *mdns_rr_header = (fnet_mdns_rr_header_t*)buf;
02225     fnet_uint16_t           rr_class = FNET_MDNS_HEADER_CLASS_IN; /* RFC: generally only DNS class 1 ("Internet") is used */
02226     fnet_uint8_t            *result = NULL;
02227 
02228     if(sizeof(fnet_mdns_rr_header_t) <= buf_size)
02229     {
02230         if(flush != FNET_FALSE)
02231         {
02232             rr_class |= FNET_MDNS_HEADER_CACHE_FLUSH;
02233         }
02234 
02235         mdns_rr_header->type        = FNET_HTONS( (fnet_uint16_t) type );
02236         mdns_rr_header->rr_class    = FNET_HTONS( (fnet_uint16_t) rr_class );
02237         mdns_rr_header->ttl         = FNET_HTONL( (fnet_uint32_t) ttl );
02238         mdns_rr_header->data_length = FNET_HTONS( (fnet_uint16_t) data_length );
02239 
02240         result = ptr + sizeof(fnet_mdns_rr_header_t);
02241     }
02242     return result;
02243 }
02244 
02245 /************************************************************************
02246 * DESCRIPTION: Add TXT record to buffer.
02247 ************************************************************************/
02248 fnet_uint8_t *fnet_mdns_add_rr_txt(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_mdns_service_if_t *service_if, fnet_uint32_t ttl, fnet_bool_t flush, fnet_bool_t compression)
02249 {
02250     FNET_ASSERT(mdns_if != NULL);
02251     FNET_ASSERT(buf != NULL);
02252 
02253     fnet_uint8_t        *rr_header_ptr;
02254     fnet_uint8_t        *txt_ptr;
02255     fnet_uint32_t       rr_txt_length = 0;
02256     const fnet_uint8_t  *txt_user_buffer;
02257     fnet_uint8_t        *ptr = buf;
02258     fnet_uint8_t        *result = NULL;
02259 
02260     /* RR Name */
02261     /* Add service name */
02262     ptr = fnet_mdns_add_service_name(mdns_if, ptr, (buf+buf_size) - ptr, service_if, compression);
02263     if(ptr == NULL)
02264     {
02265         goto ERROR;
02266     }
02267 
02268     if((size_t)((buf+buf_size) - ptr) > sizeof(fnet_mdns_rr_header_t))
02269     {
02270         rr_header_ptr = ptr;
02271         txt_ptr = ptr + sizeof(fnet_mdns_rr_header_t);
02272 
02273         /* TXT */
02274         if(service_if->service_get_txt)
02275         {
02276             txt_user_buffer = service_if->service_get_txt();
02277 
02278             if(txt_user_buffer)
02279             {
02280                 rr_txt_length = fnet_mdns_key_value_record_len(txt_user_buffer);
02281                 if( (size_t)((buf+buf_size) - txt_ptr) < (rr_txt_length+1) )
02282                 {
02283                     goto ERROR;
02284                 }
02285                 fnet_memcpy(txt_ptr, txt_user_buffer, rr_txt_length);
02286             }
02287         }
02288 
02289         /* RR TXT header */
02290         ptr = fnet_mdns_add_rr_header(rr_header_ptr, sizeof(fnet_mdns_rr_header_t), FNET_MDNS_RR_TXT, flush, ttl, rr_txt_length);
02291 
02292         ptr += rr_txt_length;
02293 
02294         result = ptr;
02295     }
02296 
02297 ERROR:
02298     return result;
02299 }
02300 
02301 /************************************************************************
02302 * DESCRIPTION: Add PTR record to buffer.
02303 ************************************************************************/
02304 static fnet_uint8_t *fnet_mdns_add_rr_ptr(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_mdns_service_if_t *service_if, fnet_uint32_t ttl, fnet_bool_t compression)
02305 {
02306     FNET_ASSERT(mdns_if != NULL);
02307     FNET_ASSERT(buf != NULL);
02308 
02309     fnet_uint8_t     *rr_header_ptr;
02310     fnet_uint8_t     *ptr = buf;
02311     fnet_uint8_t     *result = NULL;
02312 
02313     /* Add service type */
02314     ptr = fnet_mdns_add_service_type_name(mdns_if, ptr, (buf+buf_size) - ptr, service_if, compression);
02315     if(ptr == NULL)
02316     {
02317         goto ERROR;
02318     }
02319 
02320     if((size_t)((buf+buf_size) - ptr) > sizeof(fnet_mdns_rr_header_t))
02321     {
02322         /* Add RR header later, when calculate data size */
02323         rr_header_ptr = ptr;
02324         ptr = ptr + sizeof(fnet_mdns_rr_header_t);
02325 
02326         /* Add PTR data */
02327         ptr = fnet_mdns_add_service_name(mdns_if, ptr, (buf+buf_size) - ptr, service_if, compression);
02328         if(ptr == NULL)
02329         {
02330             goto ERROR;
02331         }
02332 
02333         /* Add RR PTR header */
02334         fnet_mdns_add_rr_header(rr_header_ptr,  sizeof(fnet_mdns_rr_header_t), FNET_MDNS_RR_PTR, FNET_FALSE, ttl, ptr - rr_header_ptr - sizeof(fnet_mdns_rr_header_t));
02335 
02336         result = ptr;
02337     }
02338 ERROR:
02339     return result;
02340 }
02341 
02342 /************************************************************************
02343 * DESCRIPTION:  Add SRV record to buffer.
02344 ************************************************************************/
02345 static fnet_uint8_t *fnet_mdns_add_rr_srv(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_mdns_service_if_t *service_if, fnet_uint32_t ttl, fnet_bool_t flush, fnet_bool_t compression)
02346 {
02347     FNET_ASSERT(mdns_if != NULL);
02348     FNET_ASSERT(buf != NULL);
02349 
02350     fnet_mdns_rr_data_srv_t    data;
02351     fnet_uint8_t                     *rr_header_ptr;
02352     fnet_uint8_t                     *ptr = buf;
02353     fnet_uint8_t                     *result = NULL;
02354 
02355     /* Add service name */
02356     ptr = fnet_mdns_add_service_name(mdns_if, ptr, (buf+buf_size) - ptr, service_if, compression);
02357     if(ptr == NULL)
02358     {
02359         goto ERROR;
02360     }
02361 
02362     if((size_t)((buf+buf_size) - ptr) > (sizeof(fnet_mdns_rr_header_t) + sizeof(fnet_mdns_rr_data_srv_t)))
02363     {
02364         /* Add RR header later, when calculate data size */
02365         rr_header_ptr = ptr;
02366         ptr = ptr + sizeof(fnet_mdns_rr_header_t);
02367 
02368         /* Add SRV data */
02369         fnet_memset(&data, 0, sizeof(data));
02370         data.port = service_if->service_port;
02371         fnet_memcpy(ptr, (fnet_uint8_t*)&data, sizeof(fnet_mdns_rr_data_srv_t));
02372         ptr += sizeof(data);
02373 
02374         ptr = fnet_mdns_add_host_name(mdns_if, ptr, (buf+buf_size) - ptr, compression);
02375         if(ptr == NULL)
02376         {
02377             goto ERROR;
02378         }
02379 
02380         /* Add RR SRV header */
02381         fnet_mdns_add_rr_header(rr_header_ptr, sizeof(fnet_mdns_rr_header_t), FNET_MDNS_RR_SRV, flush, ttl, ptr - rr_header_ptr - sizeof(fnet_mdns_rr_header_t));
02382 
02383         result = ptr;
02384     }
02385 
02386 ERROR:
02387     return result;
02388 }
02389 
02390 /************************************************************************
02391 * DESCRIPTION:  Add A record to buffer.
02392 ************************************************************************/
02393 #if FNET_CFG_IP4
02394 static fnet_uint8_t * fnet_mdns_add_rr_a(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_uint32_t ttl, fnet_bool_t flush, fnet_bool_t compression)
02395 {
02396     FNET_ASSERT(mdns_if != NULL);
02397     FNET_ASSERT(buf != NULL);
02398 
02399     fnet_ip4_addr_t     my_addr;
02400     fnet_uint8_t        *ptr = buf;
02401     fnet_uint8_t        *result = NULL;
02402 
02403     my_addr = fnet_netif_get_ip4_addr(mdns_if->netif);
02404 
02405     ptr = fnet_mdns_add_host_name(mdns_if, ptr, (buf+buf_size) - ptr, compression);
02406     if(ptr == NULL)
02407     {
02408         goto ERROR;
02409     }
02410 
02411     /* Prepare RR A record */
02412     ptr = fnet_mdns_add_rr_header(ptr, (buf+buf_size) - ptr, FNET_MDNS_RR_A, flush, ttl, sizeof(my_addr));
02413     if(ptr == NULL)
02414     {
02415         goto ERROR;
02416     }
02417 
02418     if(((buf+buf_size) - ptr) > sizeof(my_addr))
02419     {
02420         fnet_memcpy(ptr, &my_addr, sizeof(my_addr));
02421         ptr += sizeof(my_addr);
02422 
02423         result = ptr;
02424     }
02425 
02426 ERROR:
02427     return result;
02428 }
02429 #endif /* FNET_CFG_IP4 */
02430 
02431 /************************************************************************
02432 * DESCRIPTION:  Add AAAA record to buffer.
02433 ************************************************************************/
02434 static fnet_uint8_t * fnet_mdns_add_rr_aaaa(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_uint32_t ttl, fnet_bool_t flush, fnet_bool_t compression)
02435 {
02436     FNET_ASSERT(mdns_if != NULL);
02437     FNET_ASSERT(buf != NULL);
02438 
02439     fnet_uint8_t                *ptr = buf;
02440     fnet_uint8_t                *result = NULL;
02441     fnet_netif_ip6_addr_info_t  addr_info = {.state = FNET_NETIF_IP6_ADDR_STATE_NOT_USED};
02442 
02443     fnet_netif_get_ip6_addr (mdns_if->netif, 0u, &addr_info); /* Just get 1st address.*/
02444  
02445     ptr = fnet_mdns_add_host_name(mdns_if, ptr, (buf+buf_size) - ptr, compression);
02446     if(ptr == NULL)
02447     {
02448         goto ERROR;
02449     }
02450 
02451     /* Prepare RR AAAA record */
02452     ptr = fnet_mdns_add_rr_header(ptr, (buf+buf_size) - ptr, FNET_MDNS_RR_AAAA, flush, ttl, sizeof(addr_info.address));
02453     if(ptr == NULL)
02454     {
02455         goto ERROR;
02456     }
02457 
02458     if((size_t)((buf+buf_size) - ptr) > sizeof(addr_info.address))
02459     {
02460         fnet_memcpy(ptr, &addr_info.address, sizeof(addr_info.address));
02461         ptr += sizeof(addr_info.address);
02462 
02463         result = ptr;
02464     }
02465 
02466 ERROR:
02467     return result;
02468 }
02469 
02470 /************************************************************************
02471 * DESCRIPTION:  Add ANY Question Entry to buffer.
02472 ************************************************************************/
02473 static fnet_uint8_t * fnet_mdns_add_qe_any(fnet_uint8_t *buf, fnet_uint32_t buf_size)
02474 {
02475     FNET_ASSERT(buf != NULL);
02476 
02477     fnet_mdns_qe_header_t   *qe_header;
02478     fnet_uint8_t            *ptr = buf;
02479     fnet_uint8_t            *result = NULL;
02480 
02481     if(buf_size > sizeof(fnet_mdns_qe_header_t))
02482     {
02483         /* Prepare  Question type and class*/
02484         qe_header = (fnet_mdns_qe_header_t *)ptr;
02485         qe_header->rr_class = FNET_HTONS( (fnet_uint16_t) FNET_MDNS_HEADER_CLASS_IN );
02486         qe_header->type = FNET_HTONS( (fnet_uint16_t) FNET_MDNS_RR_ANY );
02487         ptr += sizeof(fnet_mdns_qe_header_t);
02488         result = ptr;
02489     }
02490 
02491     return result;
02492 }
02493 
02494 /************************************************************************
02495 * DESCRIPTION:  Add domain name compression.
02496 ************************************************************************/
02497 static fnet_uint8_t * fnet_mdns_add_domain_name_compression(fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_uint16_t name_offset)
02498 {
02499     FNET_ASSERT(buf != NULL);
02500 
02501     fnet_uint8_t     *ptr = buf;
02502     fnet_uint8_t     *result = NULL;
02503 
02504     if(buf_size > 2)
02505     {
02506         *ptr = FNET_MDNS_DOMAIN_NAME_COMPRESSION|((name_offset&0x3F00)>>8);
02507         ptr++;
02508         *ptr = name_offset&0xFF;
02509         ptr++;
02510 
02511         result = ptr;
02512     }
02513 
02514     return result;
02515 }
02516 
02517 /************************************************************************
02518 * DESCRIPTION:  Add host name string.
02519 ************************************************************************/
02520 static fnet_uint8_t * fnet_mdns_add_host_name(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_bool_t compression)
02521 {
02522     FNET_ASSERT(mdns_if != NULL);
02523     FNET_ASSERT(buf != NULL);
02524     
02525     fnet_uint8_t     *ptr = buf;
02526     fnet_uint8_t     *result = NULL;
02527 
02528     if(mdns_if->offset_host_name && compression)
02529     {
02530         /* Use Domain Name Compression */
02531         ptr = fnet_mdns_add_domain_name_compression(ptr, (buf+buf_size) - ptr, mdns_if->offset_host_name);
02532         if(ptr == NULL)
02533         {
02534             goto ERROR;
02535         }
02536     }
02537     else
02538     {
02539         if(compression)
02540         {
02541             /* Offset, used by Domain Name Compression.*/
02542             fnet_uint16_t offset = ptr - mdns_if->buffer;
02543                 
02544             if(offset <= 0x3FFF) /* Check offset maximum value.*/
02545             {
02546                 mdns_if->offset_host_name = offset;
02547             }
02548         }
02549 
02550         ptr = fnet_mdns_add_domain_name(ptr, (buf+buf_size) - ptr, mdns_if->host_name);
02551         if(ptr == NULL)
02552         {
02553             goto ERROR;
02554         }
02555         ptr = fnet_mdns_add_domain_name(ptr, (buf+buf_size) - ptr, FNET_MDNS_DOMAIN_NAME);
02556         if(ptr == NULL)
02557         {
02558             goto ERROR;
02559         }
02560         if(((buf+buf_size) - ptr) < 2)
02561         {
02562             goto ERROR;
02563         }
02564         *ptr++ = 0;
02565     }
02566 
02567     result = ptr;
02568 
02569 ERROR:
02570     return result;
02571 }
02572 
02573 /************************************************************************
02574 * DESCRIPTION:  Add service name string.
02575 ************************************************************************/
02576 static fnet_uint8_t * fnet_mdns_add_service_name(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_mdns_service_if_t *service_if, fnet_bool_t compression)
02577 {
02578     FNET_ASSERT(mdns_if != NULL);
02579     FNET_ASSERT(buf != NULL);
02580     
02581     fnet_uint16_t    offset;
02582     fnet_uint8_t     *ptr = buf;
02583     fnet_uint8_t     *result = NULL;
02584 
02585     if(service_if->offset_service_name  && compression)
02586     {
02587         /* Use Domain Name Compression */
02588         ptr = fnet_mdns_add_domain_name_compression(ptr, (buf+buf_size) - ptr, service_if->offset_service_name);
02589         if(ptr == NULL)
02590         {
02591             goto ERROR;
02592         }
02593     }
02594     else
02595     {
02596         if(compression)
02597         {
02598             /* Offset, used by Domain Name Compression.*/
02599             offset = ptr - mdns_if->buffer;
02600             if(offset <= 0x3FFF) /* Check offset maximum value.*/
02601             {
02602                 service_if->offset_service_name = offset;
02603             }
02604         }
02605 
02606         ptr = fnet_mdns_add_domain_name(ptr, (buf+buf_size) - ptr, mdns_if->service_name);
02607         if(ptr == NULL)
02608         {
02609             goto ERROR;
02610         }
02611 
02612         if(compression && (service_if->offset_service_type == 0))
02613         {
02614             /* Offset, used by Domain Name Compression.*/
02615             offset = ptr - mdns_if->buffer;
02616             if(offset <= 0x3FFF) /* Check offset maximum value.*/
02617             {
02618                 service_if->offset_service_type = offset;
02619             }
02620         }
02621 
02622         ptr = fnet_mdns_add_domain_name(ptr, (buf+buf_size) - ptr, service_if->service_type);
02623         if(ptr == NULL)
02624         {
02625             goto ERROR;
02626         }
02627         ptr = fnet_mdns_add_domain_name(ptr, (buf+buf_size) - ptr, FNET_MDNS_DOMAIN_NAME);
02628         if(ptr == NULL)
02629         {
02630             goto ERROR;
02631         }
02632         if(((buf+buf_size) - ptr) < 2)
02633         {
02634             goto ERROR;
02635         }
02636         *ptr++ = 0;
02637     }
02638 
02639     result = ptr;
02640 
02641 ERROR:
02642     return result;
02643 }
02644 
02645 /************************************************************************
02646 * DESCRIPTION:  Add service type string.
02647 ************************************************************************/
02648 static fnet_uint8_t * fnet_mdns_add_service_type_name(fnet_mdns_if_t *mdns_if, fnet_uint8_t *buf, fnet_uint32_t buf_size, fnet_mdns_service_if_t *service_if, fnet_bool_t compression)
02649 {
02650     FNET_ASSERT(mdns_if != NULL);
02651     FNET_ASSERT(buf != NULL);
02652 
02653     fnet_uint8_t     *ptr = buf;
02654     fnet_uint16_t    offset;
02655     fnet_uint8_t     *result = NULL;
02656 
02657     if(service_if->offset_service_type && compression)
02658     {
02659         /* Use Domain Name Compression */
02660         ptr = fnet_mdns_add_domain_name_compression(ptr, (buf+buf_size) - ptr, service_if->offset_service_type);
02661         if(ptr == NULL)
02662         {
02663             goto ERROR;
02664         }
02665     }
02666     else
02667     {
02668         if(compression)
02669         {
02670             /* Offset, used by Domain Name Compression.*/
02671             offset = ptr - mdns_if->buffer;
02672             if(offset <= 0x3FFF) /* Check offset maximum value.*/
02673             {
02674                 service_if->offset_service_type = offset;
02675             }
02676         }
02677 
02678         ptr = fnet_mdns_add_domain_name(ptr, (buf+buf_size) - ptr, service_if->service_type);
02679         if(ptr == NULL)
02680         {
02681             goto ERROR;
02682         }
02683         ptr = fnet_mdns_add_domain_name(ptr, (buf+buf_size) - ptr, FNET_MDNS_DOMAIN_NAME);
02684         if(ptr == NULL)
02685         {
02686             goto ERROR;
02687         }
02688         if(((buf+buf_size) - ptr) < 2)
02689         {
02690             goto ERROR;
02691         }
02692         *ptr++ = 0;
02693     }
02694 
02695     result = ptr;
02696 
02697 ERROR:
02698     return result;
02699 }
02700 
02701 /************************************************************************
02702 * DESCRIPTION:  Determines if host_name is our fully qualified domain 
02703 *               name FQDN (hostname.domain).
02704 ************************************************************************/
02705 static fnet_bool_t fnet_mdns_is_our_host_name(fnet_mdns_if_t *mdns_if, char *host_name)
02706 {
02707     FNET_ASSERT(mdns_if != NULL);
02708 
02709     return fnet_mdns_cmp_rr_name(host_name, "", mdns_if->host_name);    
02710 }
02711 
02712 /************************************************************************
02713 * DESCRIPTION:  Gets service interfcase by name (servicename.type.domain).
02714 ************************************************************************/
02715 static fnet_mdns_service_if_t *fnet_mdns_get_service_by_name(fnet_mdns_if_t *mdns_if, char *service_name)
02716 {
02717     FNET_ASSERT(mdns_if != NULL);
02718 
02719     fnet_index_t            i;
02720     fnet_mdns_service_if_t  *result = NULL;
02721 
02722     for(i = 0; i<FNET_CFG_MDNS_SERVICE_MAX; i++)
02723     {
02724         if(mdns_if->service_if_list[i].service_type != NULL) 
02725         {
02726             if(fnet_mdns_cmp_rr_name(service_name, mdns_if->service_name, mdns_if->service_if_list[i].service_type) == FNET_TRUE)
02727             {
02728                 result = &mdns_if->service_if_list[i];
02729                 break; /* Found.*/
02730             }
02731         }
02732     }
02733 
02734     return result;
02735 }
02736 
02737 /************************************************************************
02738 * DESCRIPTION: Gets service interfcase by type (type.domain).
02739 ************************************************************************/
02740 static fnet_mdns_service_if_t *fnet_mdns_get_service_by_type(fnet_mdns_if_t *mdns_if, char *service_name)
02741 {
02742     FNET_ASSERT(mdns_if != NULL);
02743 
02744     fnet_index_t            i;
02745     fnet_mdns_service_if_t *result = NULL;
02746 
02747     for(i = 0; i<FNET_CFG_MDNS_SERVICE_MAX; i++)
02748     {
02749         if(mdns_if->service_if_list[i].service_type != NULL) 
02750         {
02751             if(fnet_mdns_cmp_rr_name(service_name, "", mdns_if->service_if_list[i].service_type) == FNET_TRUE)
02752             {
02753                 result = &mdns_if->service_if_list[i];
02754                 break; /* Found.*/
02755             }
02756         }
02757     }
02758 
02759     return result;
02760 }
02761 
02762 /************************************************************************
02763 * DESCRIPTION: Calculate length of key-value record that may have binary data.
02764 ************************************************************************/
02765 static fnet_uint32_t fnet_mdns_key_value_record_len(const fnet_uint8_t *record)
02766 {
02767     const fnet_uint8_t *ptr;
02768 
02769     if (!record) {
02770         return 0;
02771     }
02772 
02773     ptr = record;
02774     do {
02775         ptr += (*ptr + 1);
02776     } while (*ptr != 0);
02777 
02778     return ptr - record;
02779 }
02780 
02781 #endif /* FNET_CFG_MDNS*/