Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mdns_responder.c Source File

mdns_responder.c

Go to the documentation of this file.
00001 /**
00002  * @file mdns_responder.c
00003  * @brief mDNS responder (Multicast DNS)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL MDNS_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <stdlib.h>
00034 #include <ctype.h>
00035 #include "core/net.h"
00036 #include "mdns/mdns_responder.h"
00037 #include "mdns/mdns_common.h"
00038 #include "dns/dns_debug.h"
00039 #include "dns_sd/dns_sd.h"
00040 #include "str.h"
00041 #include "debug.h"
00042 
00043 //Check TCP/IP stack configuration
00044 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
00045 
00046 //Tick counter to handle periodic operations
00047 systime_t mdnsResponderTickCounter;
00048 
00049 
00050 /**
00051  * @brief Initialize settings with default values
00052  * @param[out] settings Structure that contains mDNS responder settings
00053  **/
00054 
00055 void mdnsResponderGetDefaultSettings(MdnsResponderSettings *settings)
00056 {
00057    //Use default interface
00058    settings->interface = netGetDefaultInterface();
00059 
00060    //Number of announcement packets
00061    settings->numAnnouncements = MDNS_ANNOUNCE_NUM;
00062    //TTL resource record
00063    settings->ttl = MDNS_DEFAULT_RR_TTL;
00064    //FSM state change event
00065    settings->stateChangeEvent = NULL;
00066 }
00067 
00068 
00069 /**
00070  * @brief mDNS responder initialization
00071  * @param[in] context Pointer to the mDNS responder context
00072  * @param[in] settings mDNS responder specific settings
00073  * @return Error code
00074  **/
00075 
00076 error_t mdnsResponderInit(MdnsResponderContext *context,
00077    const MdnsResponderSettings *settings)
00078 {
00079    NetInterface *interface;
00080 
00081    //Debug message
00082    TRACE_INFO("Initializing mDNS responder...\r\n");
00083 
00084    //Ensure the parameters are valid
00085    if(context == NULL || settings == NULL)
00086       return ERROR_INVALID_PARAMETER;
00087 
00088    //Invalid network interface?
00089    if(settings->interface == NULL)
00090       return ERROR_INVALID_PARAMETER;
00091 
00092    //Point to the underlying network interface
00093    interface = settings->interface;
00094 
00095    //Clear the mDNS responder context
00096    memset(context, 0, sizeof(MdnsResponderContext));
00097    //Save user settings
00098    context->settings = *settings;
00099 
00100    //mDNS responder is currently suspended
00101    context->running = FALSE;
00102    //Initialize state machine
00103    context->state = MDNS_STATE_INIT;
00104 
00105    //Attach the mDNS responder context to the network interface
00106    interface->mdnsResponderContext = context;
00107 
00108    //Successful initialization
00109    return NO_ERROR;
00110 }
00111 
00112 
00113 /**
00114  * @brief Start mDNS responder
00115  * @param[in] context Pointer to the mDNS responder context
00116  * @return Error code
00117  **/
00118 
00119 error_t mdnsResponderStart(MdnsResponderContext *context)
00120 {
00121    //Check parameter
00122    if(context == NULL)
00123       return ERROR_INVALID_PARAMETER;
00124 
00125    //Debug message
00126    TRACE_INFO("Starting mDNS responder...\r\n");
00127 
00128    //Get exclusive access
00129    osAcquireMutex(&netMutex);
00130 
00131    //Start mDNS responder
00132    context->running = TRUE;
00133    //Initialize state machine
00134    context->state = MDNS_STATE_INIT;
00135 
00136    //Release exclusive access
00137    osReleaseMutex(&netMutex);
00138 
00139    //Successful processing
00140    return NO_ERROR;
00141 }
00142 
00143 
00144 /**
00145  * @brief Stop mDNS responder
00146  * @param[in] context Pointer to the mDNS responder context
00147  * @return Error code
00148  **/
00149 
00150 error_t mdnsResponderStop(MdnsResponderContext *context)
00151 {
00152    //Check parameter
00153    if(context == NULL)
00154       return ERROR_INVALID_PARAMETER;
00155 
00156    //Debug message
00157    TRACE_INFO("Stopping mDNS responder...\r\n");
00158 
00159    //Get exclusive access
00160    osAcquireMutex(&netMutex);
00161 
00162    //Suspend mDNS responder
00163    context->running = FALSE;
00164    //Reinitialize state machine
00165    context->state = MDNS_STATE_INIT;
00166 
00167    //Release exclusive access
00168    osReleaseMutex(&netMutex);
00169 
00170    //Successful processing
00171    return NO_ERROR;
00172 }
00173 
00174 
00175 /**
00176  * @brief Retrieve current state
00177  * @param[in] context Pointer to the mDNS responder context
00178  * @return Current mDNS responder state
00179  **/
00180 
00181 MdnsState mdnsResponderGetState(MdnsResponderContext *context)
00182 {
00183    MdnsState state;
00184 
00185    //Get exclusive access
00186    osAcquireMutex(&netMutex);
00187    //Get current state
00188    state = context->state;
00189    //Release exclusive access
00190    osReleaseMutex(&netMutex);
00191 
00192    //Return current state
00193    return state;
00194 }
00195 
00196 
00197 /**
00198  * @brief Set hostname
00199  * @param[in] context Pointer to the mDNS responder context
00200  * @param[in] hostname NULL-terminated string that contains the hostname
00201  * @return Error code
00202  **/
00203 
00204 error_t mdnsResponderSetHostname(MdnsResponderContext *context,
00205    const char_t *hostname)
00206 {
00207    NetInterface *interface;
00208 
00209    //Check parameters
00210    if(context == NULL || hostname == NULL)
00211       return ERROR_INVALID_PARAMETER;
00212 
00213    //Get exclusive access
00214    osAcquireMutex(&netMutex);
00215 
00216    //Point to the underlying network interface
00217    interface = context->settings.interface;
00218 
00219    //Check whether a hostname is already assigned
00220    if(context->hostname[0] != '\0')
00221    {
00222       //Check whether the link is up
00223       if(interface->linkState)
00224       {
00225          //Send a goodbye packet
00226          mdnsResponderSendGoodbye(context);
00227       }
00228    }
00229 
00230    //Set hostname
00231    strSafeCopy(context->hostname, hostname,
00232       MDNS_RESPONDER_MAX_HOSTNAME_LEN);
00233 
00234    //Restart probing process (hostname)
00235    mdnsResponderStartProbing(interface->mdnsResponderContext);
00236 
00237 #if (DNS_SD_SUPPORT == ENABLED)
00238    //Restart probing process (service instance name)
00239    dnsSdStartProbing(interface->dnsSdContext);
00240 #endif
00241 
00242    //Release exclusive access
00243    osReleaseMutex(&netMutex);
00244 
00245    //Successful processing
00246    return NO_ERROR;
00247 }
00248 
00249 
00250 /**
00251  * @brief Generate domain name for reverse DNS lookup (IPv4)
00252  * @param[in] context Pointer to the mDNS responder context
00253  * @return Error code
00254  **/
00255 
00256 error_t mdnsResponderSetIpv4ReverseName(MdnsResponderContext *context)
00257 {
00258 #if (IPV4_SUPPORT == ENABLED)
00259    uint8_t *addr;
00260    NetInterface *interface;
00261 
00262    //Check whether the mDNS responder has been properly instantiated
00263    if(context == NULL)
00264       return ERROR_INVALID_PARAMETER;
00265 
00266    //Point to the underlying network interface
00267    interface = context->settings.interface;
00268 
00269    //Check whether the host address is valid
00270    if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_VALID)
00271    {
00272       //Cast the IPv4 address as byte array
00273       addr = (uint8_t *) &interface->ipv4Context.addr;
00274 
00275       //Generate the domain name for reverse DNS lookup
00276       sprintf(context->ipv4ReverseName, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8,
00277          addr[3], addr[2], addr[1], addr[0]);
00278    }
00279    else
00280    {
00281       //The host address is not valid
00282       context->ipv4ReverseName[0] = '\0';
00283    }
00284 #endif
00285 
00286    //Successful processing
00287    return NO_ERROR;
00288 }
00289 
00290 
00291 /**
00292  * @brief Generate domain name for reverse DNS lookup (IPv6)
00293  * @param[in] context Pointer to the mDNS responder context
00294  * @return Error code
00295  **/
00296 
00297 error_t mdnsResponderSetIpv6ReverseName(MdnsResponderContext *context)
00298 {
00299 #if (IPV6_SUPPORT == ENABLED)
00300    uint_t i;
00301    uint_t m;
00302    uint_t n;
00303    char_t *p;
00304    uint8_t *addr;
00305    NetInterface *interface;
00306 
00307    //Check whether the mDNS responder has been properly instantiated
00308    if(context == NULL)
00309       return ERROR_INVALID_PARAMETER;
00310 
00311    //Point to the underlying network interface
00312    interface = context->settings.interface;
00313 
00314    //Point to the buffer where to format the reverse name
00315    p = context->ipv6ReverseName;
00316 
00317    //Check whether the link-local address is valid
00318    if(ipv6GetLinkLocalAddrState(interface) == IPV6_ADDR_STATE_PREFERRED)
00319    {
00320       //Cast the IPv4 address as byte array
00321       addr = interface->ipv6Context.addrList[0].addr.b;
00322 
00323       //Generate the domain name for reverse DNS lookup
00324       for(i = 0; i < 32; i++)
00325       {
00326          //Calculate the shift count
00327          n = (31 - i) / 2;
00328          m = (i % 2) * 4;
00329 
00330          //Format the current digit
00331          p += sprintf(p, "%" PRIx8, (addr[n] >> m) & 0x0F);
00332 
00333          //Add a delimiter character
00334          if(i != 31)
00335             p += sprintf(p, ".");
00336       }
00337    }
00338    else
00339    {
00340       //The link-local address is not valid
00341       p[0] = '\0';
00342    }
00343 #endif
00344 
00345    //Successful processing
00346    return NO_ERROR;
00347 }
00348 
00349 
00350 /**
00351  * @brief Restart probing process
00352  * @param[in] context Pointer to the mDNS responder context
00353  * @return Error code
00354  **/
00355 
00356 error_t mdnsResponderStartProbing(MdnsResponderContext *context)
00357 {
00358    //Check whether the mDNS responder has been properly instantiated
00359    if(context == NULL)
00360       return ERROR_INVALID_PARAMETER;
00361 
00362    //Generate domain names for reverse DNS lookup
00363    mdnsResponderSetIpv4ReverseName(context);
00364    mdnsResponderSetIpv6ReverseName(context);
00365 
00366    //Force mDNS responder to start probing again
00367    context->state = MDNS_STATE_INIT;
00368 
00369    //Successful processing
00370    return NO_ERROR;
00371 }
00372 
00373 
00374 /**
00375  * @brief mDNS responder timer handler
00376  *
00377  * This routine must be periodically called by the TCP/IP stack to
00378  * manage mDNS operation
00379  *
00380  * @param[in] context Pointer to the mDNS responder context
00381  **/
00382 
00383 void mdnsResponderTick(MdnsResponderContext *context)
00384 {
00385    bool_t valid;
00386    systime_t time;
00387    systime_t delay;
00388    NetInterface *interface;
00389    IpAddr destIpAddr;
00390 
00391    //Make sure the mDNS responder has been properly instantiated
00392    if(context == NULL)
00393       return;
00394 
00395    //Point to the underlying network interface
00396    interface = context->settings.interface;
00397 
00398    //Get current time
00399    time = osGetSystemTime();
00400 
00401    //Check current state
00402    if(context->state == MDNS_STATE_INIT)
00403    {
00404       //Check whether a hostname has been assigned
00405       if(context->hostname[0] != '\0')
00406       {
00407          //Make sure that the link is up
00408          if(interface->linkState)
00409          {
00410             //Clear flag
00411             valid = FALSE;
00412 
00413 #if (IPV4_SUPPORT == ENABLED)
00414             //Check whether the IPv4 host address is valid
00415             if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_VALID)
00416                valid = TRUE;
00417 #endif
00418 
00419 #if (IPV6_SUPPORT == ENABLED)
00420             //Check whether the IPv6 link-local address is valid
00421             if(ipv6GetLinkLocalAddrState(interface) == IPV6_ADDR_STATE_PREFERRED)
00422                valid = TRUE;
00423 #endif
00424             //Any valid IP address assigned to the network interface?
00425             if(valid)
00426             {
00427                //Wait until both IPv4 and IPv6 addresses are valid
00428                mdnsResponderChangeState(context, MDNS_STATE_WAITING, 0);
00429             }
00430          }
00431       }
00432    }
00433    else if(context->state == MDNS_STATE_WAITING)
00434    {
00435       //Set flag
00436       valid = TRUE;
00437 
00438       //Check current time
00439       if(timeCompare(time, context->timestamp + MDNS_MAX_WAITING_DELAY) < 0)
00440       {
00441 #if (IPV4_SUPPORT == ENABLED)
00442          //Check whether the IPv4 host address is valid
00443          if(interface->ipv4Context.addrState != IPV4_ADDR_STATE_VALID)
00444             valid = FALSE;
00445 #endif
00446 
00447 #if (IPV6_SUPPORT == ENABLED)
00448          //Check whether the IPv6 link-local address is valid
00449          if(ipv6GetLinkLocalAddrState(interface) != IPV6_ADDR_STATE_PREFERRED)
00450             valid = FALSE;
00451 #endif
00452       }
00453 
00454       //Start probing?
00455       if(valid)
00456       {
00457          //Initial random delay
00458          delay = netGetRandRange(MDNS_RAND_DELAY_MIN, MDNS_RAND_DELAY_MAX);
00459          //Perform probing
00460          mdnsResponderChangeState(context, MDNS_STATE_PROBING, delay);
00461       }
00462    }
00463    else if(context->state == MDNS_STATE_PROBING)
00464    {
00465       //Probing failed?
00466       if(context->conflict && context->retransmitCount > 0)
00467       {
00468          //Programmatically change the host name
00469          mdnsResponderChangeHostname(context);
00470          //Probe again, and repeat as necessary until a unique name is found
00471          mdnsResponderChangeState(context, MDNS_STATE_PROBING, 0);
00472       }
00473       //Tie-break lost?
00474       else if(context->tieBreakLost && context->retransmitCount > 0)
00475       {
00476          //The host defers to the winning host by waiting one second, and
00477          //then begins probing for this record again
00478          mdnsResponderChangeState(context, MDNS_STATE_PROBING, MDNS_PROBE_DEFER);
00479       }
00480       else
00481       {
00482          //Check current time
00483          if(timeCompare(time, context->timestamp + context->timeout) >= 0)
00484          {
00485             //Probing is on-going?
00486             if(context->retransmitCount < MDNS_PROBE_NUM)
00487             {
00488                //First probe?
00489                if(context->retransmitCount == 0)
00490                {
00491                   //Apparently conflicting mDNS responses received before the
00492                   //first probe packet is sent must be silently ignored
00493                   context->conflict = FALSE;
00494                   context->tieBreakLost = FALSE;
00495                }
00496 
00497                //Send probe packet
00498                mdnsResponderSendProbe(context);
00499 
00500                //Save the time at which the packet was sent
00501                context->timestamp = time;
00502                //Time interval between subsequent probe packets
00503                context->timeout = MDNS_PROBE_DELAY;
00504                //Increment retransmission counter
00505                context->retransmitCount++;
00506             }
00507             //Probing is complete?
00508             else
00509             {
00510                //The mDNS responder must send unsolicited mDNS responses
00511                //containing all of its newly registered resource records
00512                if(context->settings.numAnnouncements > 0)
00513                   mdnsResponderChangeState(context, MDNS_STATE_ANNOUNCING, 0);
00514                else
00515                   mdnsResponderChangeState(context, MDNS_STATE_IDLE, 0);
00516             }
00517          }
00518       }
00519    }
00520    else if(context->state == MDNS_STATE_ANNOUNCING)
00521    {
00522       //Whenever a mDNS responder receives any mDNS response (solicited or
00523       //otherwise) containing a conflicting resource record, the conflict
00524       //must be resolved
00525       if(context->conflict)
00526       {
00527          //Probe again, and repeat as necessary until a unique name is found
00528          mdnsResponderChangeState(context, MDNS_STATE_PROBING, 0);
00529       }
00530       else
00531       {
00532          //Check current time
00533          if(timeCompare(time, context->timestamp + context->timeout) >= 0)
00534          {
00535             //Send announcement packet
00536             mdnsResponderSendAnnouncement(context);
00537 
00538             //Save the time at which the packet was sent
00539             context->timestamp = time;
00540             //Increment retransmission counter
00541             context->retransmitCount++;
00542 
00543             //First announcement packet?
00544             if(context->retransmitCount == 1)
00545             {
00546                //The mDNS responder must send at least two unsolicited
00547                //responses, one second apart
00548                context->timeout = MDNS_ANNOUNCE_DELAY;
00549             }
00550             else
00551             {
00552                //To provide increased robustness against packet loss, a mDNS
00553                //responder may send up to eight unsolicited responses, provided
00554                //that the interval between unsolicited responses increases by
00555                //at least a factor of two with every response sent
00556                context->timeout *= 2;
00557             }
00558 
00559             //Last announcement packet?
00560             if(context->retransmitCount >= context->settings.numAnnouncements)
00561             {
00562                //A mDNS responder must not send regular periodic announcements
00563                mdnsResponderChangeState(context, MDNS_STATE_IDLE, 0);
00564             }
00565          }
00566       }
00567    }
00568    else if(context->state == MDNS_STATE_IDLE)
00569    {
00570       //Whenever a mDNS responder receives any mDNS response (solicited or
00571       //otherwise) containing a conflicting resource record, the conflict
00572       //must be resolved
00573       if(context->conflict)
00574       {
00575          //Probe again, and repeat as necessary until a unique name is found
00576          mdnsResponderChangeState(context, MDNS_STATE_PROBING, 0);
00577       }
00578    }
00579 
00580 #if (IPV4_SUPPORT == ENABLED)
00581    //Any response message pending to be sent?
00582    if(context->ipv4Response.buffer != NULL)
00583    {
00584       //Check whether the time delay has elapsed
00585       if(timeCompare(time, context->ipv4Response.timestamp +
00586          context->ipv4Response.timeout) >= 0)
00587       {
00588 #if (DNS_SD_SUPPORT == ENABLED)
00589          //Additional record generation (DNS-SD)
00590          dnsSdGenerateAdditionalRecords(interface,
00591             &context->ipv4Response, FALSE);
00592 #endif
00593          //Additional record generation (mDNS)
00594          mdnsResponderGenerateAdditionalRecords(interface,
00595             &context->ipv4Response, FALSE);
00596 
00597          //Use mDNS IPv4 multicast address
00598          destIpAddr.length = sizeof(Ipv4Addr);
00599          destIpAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR;
00600 
00601          //Send mDNS response message
00602          mdnsSendMessage(interface, &context->ipv4Response,
00603             &destIpAddr, MDNS_PORT);
00604 
00605          //Free previously allocated memory
00606          mdnsDeleteMessage(&context->ipv4Response);
00607       }
00608    }
00609 #endif
00610 
00611 #if (IPV6_SUPPORT == ENABLED)
00612    //Any response message pending to be sent?
00613    if(context->ipv6Response.buffer != NULL)
00614    {
00615       //Check whether the time delay has elapsed
00616       if(timeCompare(time, context->ipv6Response.timestamp +
00617          context->ipv6Response.timeout) >= 0)
00618       {
00619 #if (DNS_SD_SUPPORT == ENABLED)
00620          //Additional record generation (DNS-SD)
00621          dnsSdGenerateAdditionalRecords(interface,
00622             &context->ipv6Response, FALSE);
00623 #endif
00624          //Additional record generation (mDNS)
00625          mdnsResponderGenerateAdditionalRecords(interface,
00626             &context->ipv6Response, FALSE);
00627 
00628          //Use mDNS IPv6 multicast address
00629          destIpAddr.length = sizeof(Ipv6Addr);
00630          destIpAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR;
00631 
00632          //Send mDNS response message
00633          mdnsSendMessage(interface, &context->ipv6Response,
00634             &destIpAddr, MDNS_PORT);
00635 
00636          //Free previously allocated memory
00637          mdnsDeleteMessage(&context->ipv6Response);
00638       }
00639    }
00640 #endif
00641 }
00642 
00643 
00644 /**
00645  * @brief Callback function for link change event
00646  * @param[in] context Pointer to the mDNS responder context
00647  **/
00648 
00649 void mdnsResponderLinkChangeEvent(MdnsResponderContext *context)
00650 {
00651    //Make sure the mDNS responder has been properly instantiated
00652    if(context == NULL)
00653       return;
00654 
00655 #if (IPV4_SUPPORT == ENABLED)
00656    //Free any response message pending to be sent
00657    mdnsDeleteMessage(&context->ipv4Response);
00658 #endif
00659 
00660 #if (IPV6_SUPPORT == ENABLED)
00661    //Free any response message pending to be sent
00662    mdnsDeleteMessage(&context->ipv6Response);
00663 #endif
00664 
00665    //Whenever a mDNS responder receives an indication of a link
00666    //change event, it must perform probing and announcing
00667    mdnsResponderChangeState(context, MDNS_STATE_INIT, 0);
00668 }
00669 
00670 
00671 /**
00672  * @brief Update FSM state
00673  * @param[in] context Pointer to the mDNS responder context
00674  * @param[in] newState New state to switch to
00675  * @param[in] delay Initial delay
00676  **/
00677 
00678 void mdnsResponderChangeState(MdnsResponderContext *context,
00679    MdnsState newState, systime_t delay)
00680 {
00681    NetInterface *interface;
00682 
00683    //Point to the underlying network interface
00684    interface = context->settings.interface;
00685 
00686    //Set time stamp
00687    context->timestamp = osGetSystemTime();
00688    //Set initial delay
00689    context->timeout = delay;
00690    //Reset retransmission counter
00691    context->retransmitCount = 0;
00692    //Switch to the new state
00693    context->state = newState;
00694 
00695    //Any registered callback?
00696    if(context->settings.stateChangeEvent != NULL)
00697    {
00698       //Release exclusive access
00699       osReleaseMutex(&netMutex);
00700       //Invoke user callback function
00701       context->settings.stateChangeEvent(context, interface, newState);
00702       //Get exclusive access
00703       osAcquireMutex(&netMutex);
00704    }
00705 }
00706 
00707 
00708 /**
00709  * @brief Programmatically change the host name
00710  * @param[in] context Pointer to the mDNS responder context
00711  **/
00712 
00713 void mdnsResponderChangeHostname(MdnsResponderContext *context)
00714 {
00715    size_t i;
00716    size_t m;
00717    size_t n;
00718    uint32_t index;
00719    char_t s[16];
00720 
00721    //Retrieve the length of the string
00722    n = strlen(context->hostname);
00723 
00724    //Parse the string backwards
00725    for(i = n; i > 0; i--)
00726    {
00727       //Check whether the current character is a digit
00728       if(!isdigit((uint8_t) context->hostname[i - 1]))
00729          break;
00730    }
00731 
00732    //Any number following the host name?
00733    if(context->hostname[i] != '\0')
00734    {
00735       //Retrieve the number at the end of the name
00736       index = atoi(context->hostname + i);
00737       //Increment the value
00738       index++;
00739 
00740       //Strip the digits
00741       context->hostname[i] = '\0';
00742    }
00743    else
00744    {
00745       //Append the digit "2" to the name
00746       index = 2;
00747    }
00748 
00749    //Convert the number to a string of characters
00750    m = sprintf(s, "%" PRIu32, index);
00751 
00752    //Sanity check
00753    if((i + m) <= NET_MAX_HOSTNAME_LEN)
00754    {
00755       //Add padding if necessary
00756       while((i + m) < n)
00757          context->hostname[i++] = '0';
00758 
00759       //Properly terminate the string
00760       context->hostname[i] = '\0';
00761       //Programmatically change the host name
00762       strcat(context->hostname, s);
00763    }
00764 }
00765 
00766 
00767 /**
00768  * @brief Send probe packet
00769  * @param[in] context Pointer to the mDNS responder context
00770  * @return Error code
00771  **/
00772 
00773 error_t mdnsResponderSendProbe(MdnsResponderContext *context)
00774 {
00775    error_t error;
00776    NetInterface *interface;
00777    DnsQuestion *dnsQuestion;
00778    MdnsMessage message;
00779 
00780    //Point to the underlying network interface
00781    interface = context->settings.interface;
00782 
00783    //Create an empty mDNS query message
00784    error = mdnsCreateMessage(&message, FALSE);
00785    //Any error to report?
00786    if(error)
00787       return error;
00788 
00789    //Start of exception handling block
00790    do
00791    {
00792       //Encode the host name using the DNS name notation
00793       message.length += mdnsEncodeName(context->hostname, "",
00794          ".local", message.dnsHeader->questions);
00795 
00796       //Point to the corresponding question structure
00797       dnsQuestion = DNS_GET_QUESTION(message.dnsHeader, message.length);
00798 
00799       //The probes should be sent as QU questions with the unicast-response
00800       //bit set, to allow a defending host to respond immediately via unicast
00801       dnsQuestion->qtype = HTONS(DNS_RR_TYPE_ANY);
00802       dnsQuestion->qclass = HTONS(MDNS_QCLASS_QU | DNS_RR_CLASS_IN);
00803 
00804       //Update the length of the mDNS query message
00805       message.length += sizeof(DnsQuestion);
00806 
00807       //Format A resource record
00808       error = mdnsResponderAddIpv4AddrRecord(interface,
00809          &message, FALSE, MDNS_DEFAULT_RR_TTL);
00810       //Any error to report?
00811       if(error)
00812          break;
00813 
00814       //Format AAAA resource record
00815       error = mdnsResponderAddIpv6AddrRecord(interface,
00816          &message, FALSE, MDNS_DEFAULT_RR_TTL);
00817       //Any error to report?
00818       if(error)
00819          break;
00820 
00821       //Number of questions in the Question Section
00822       message.dnsHeader->qdcount = 1;
00823       //Number of resource records in the Authority Section
00824       message.dnsHeader->nscount = message.dnsHeader->ancount;
00825       //Number of resource records in the Answer Section
00826       message.dnsHeader->ancount = 0;
00827 
00828       //Send mDNS message
00829       error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT);
00830 
00831       //End of exception handling block
00832    } while(0);
00833 
00834    //Free previously allocated memory
00835    mdnsDeleteMessage(&message);
00836 
00837    //Return status code
00838    return error;
00839 }
00840 
00841 
00842 /**
00843  * @brief Send announcement packet
00844  * @param[in] context Pointer to the mDNS responder context
00845  * @return Error code
00846  **/
00847 
00848 error_t mdnsResponderSendAnnouncement(MdnsResponderContext *context)
00849 {
00850    error_t error;
00851    NetInterface *interface;
00852    MdnsMessage message;
00853 
00854    //Point to the underlying network interface
00855    interface = context->settings.interface;
00856 
00857    //Create an empty mDNS response message
00858    error = mdnsCreateMessage(&message, TRUE);
00859    //Any error to report?
00860    if(error)
00861       return error;
00862 
00863    //Start of exception handling block
00864    do
00865    {
00866       //Format A resource record
00867       error = mdnsResponderAddIpv4AddrRecord(interface,
00868          &message, TRUE, MDNS_DEFAULT_RR_TTL);
00869       //Any error to report?
00870       if(error)
00871          break;
00872 
00873       //Format reverse address mapping PTR record (IPv4)
00874       error = mdnsResponderAddIpv4ReversePtrRecord(interface,
00875          &message, TRUE, MDNS_DEFAULT_RR_TTL);
00876       //Any error to report?
00877       if(error)
00878          break;
00879 
00880       //Format AAAA resource record
00881       error = mdnsResponderAddIpv6AddrRecord(interface,
00882          &message, TRUE, MDNS_DEFAULT_RR_TTL);
00883       //Any error to report?
00884       if(error)
00885          break;
00886 
00887       //Format reverse address mapping PTR record (IPv6)
00888       error = mdnsResponderAddIpv6ReversePtrRecord(interface,
00889          &message, TRUE, MDNS_DEFAULT_RR_TTL);
00890       //Any error to report?
00891       if(error)
00892          break;
00893 
00894       //Send mDNS message
00895       error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT);
00896 
00897       //End of exception handling block
00898    } while(0);
00899 
00900    //Free previously allocated memory
00901    mdnsDeleteMessage(&message);
00902 
00903    //Return status code
00904    return error;
00905 }
00906 
00907 
00908 /**
00909  * @brief Send goodbye packet
00910  * @param[in] context Pointer to the mDNS responder context
00911  * @return Error code
00912  **/
00913 
00914 error_t mdnsResponderSendGoodbye(MdnsResponderContext *context)
00915 {
00916    error_t error;
00917    NetInterface *interface;
00918    MdnsMessage message;
00919 
00920    //Point to the underlying network interface
00921    interface = context->settings.interface;
00922 
00923    //Create an empty mDNS response message
00924    error = mdnsCreateMessage(&message, TRUE);
00925    //Any error to report?
00926    if(error)
00927       return error;
00928 
00929    //Start of exception handling block
00930    do
00931    {
00932       //Format A resource record
00933       error = mdnsResponderAddIpv4AddrRecord(interface, &message, TRUE, 0);
00934       //Any error to report?
00935       if(error)
00936          break;
00937 
00938       //Format reverse address mapping PTR record (IPv4)
00939       error = mdnsResponderAddIpv4ReversePtrRecord(interface, &message, TRUE, 0);
00940       //Any error to report?
00941       if(error)
00942          break;
00943 
00944       //Format AAAA resource record
00945       error = mdnsResponderAddIpv6AddrRecord(interface, &message, TRUE, 0);
00946       //Any error to report?
00947       if(error)
00948          break;
00949 
00950       //Format reverse address mapping PTR record (IPv6)
00951       error = mdnsResponderAddIpv6ReversePtrRecord(interface, &message, TRUE, 0);
00952       //Any error to report?
00953       if(error)
00954          break;
00955 
00956       //Send mDNS message
00957       error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT);
00958 
00959       //End of exception handling block
00960    } while(0);
00961 
00962    //Free previously allocated memory
00963    mdnsDeleteMessage(&message);
00964 
00965    //Return status code
00966    return error;
00967 }
00968 
00969 
00970 /**
00971  * @brief Process mDNS query message
00972  * @param[in] interface Underlying network interface
00973  * @param[in] query Incoming mDNS query message
00974  **/
00975 
00976 void mdnsResponderProcessQuery(NetInterface *interface, MdnsMessage *query)
00977 {
00978    error_t error;
00979    uint_t i;
00980    size_t n;
00981    size_t offset;
00982    DnsQuestion *question;
00983    DnsResourceRecord *record;
00984    MdnsResponderContext *context;
00985    MdnsMessage *response;
00986    uint16_t destPort;
00987    IpAddr destIpAddr;
00988 
00989    //Point to the mDNS responder context
00990    context = interface->mdnsResponderContext;
00991    //Make sure the mDNS responder has been properly instantiated
00992    if(context == NULL)
00993       return;
00994 
00995 #if (IPV4_SUPPORT == ENABLED)
00996    //IPv4 query received?
00997    if(query->pseudoHeader->length == sizeof(Ipv4PseudoHeader))
00998    {
00999       //If the source UDP port in a received Multicast DNS query is not port 5353,
01000       //this indicates that the querier originating the query is a simple resolver
01001       if(ntohs(query->udpHeader->srcPort) != MDNS_PORT)
01002       {
01003          //The mDNS responder must send a UDP response directly back to the querier,
01004          //via unicast, to the query packet's source IP address and port
01005          destIpAddr.length = sizeof(Ipv4Addr);
01006          destIpAddr.ipv4Addr = query->pseudoHeader->ipv4Data.srcAddr;
01007       }
01008       else
01009       {
01010          //Use mDNS IPv4 multicast address
01011          destIpAddr.length = sizeof(Ipv4Addr);
01012          destIpAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR;
01013       }
01014 
01015       //Point to the mDNS response message
01016       response = &context->ipv4Response;
01017    }
01018    else
01019 #endif
01020 #if (IPV6_SUPPORT == ENABLED)
01021    //IPv6 query received?
01022    if(query->pseudoHeader->length == sizeof(Ipv6PseudoHeader))
01023    {
01024       //If the source UDP port in a received Multicast DNS query is not port 5353,
01025       //this indicates that the querier originating the query is a simple resolver
01026       if(ntohs(query->udpHeader->srcPort) != MDNS_PORT)
01027       {
01028          //The mDNS responder must send a UDP response directly back to the querier,
01029          //via unicast, to the query packet's source IP address and port
01030          destIpAddr.length = sizeof(Ipv6Addr);
01031          destIpAddr.ipv6Addr = query->pseudoHeader->ipv6Data.srcAddr;
01032       }
01033       else
01034       {
01035          //Use mDNS IPv6 multicast address
01036          destIpAddr.length = sizeof(Ipv6Addr);
01037          destIpAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR;
01038       }
01039 
01040       //Point to the mDNS response message
01041       response = &context->ipv6Response;
01042    }
01043    else
01044 #endif
01045    //Invalid query received?
01046    {
01047       //Discard the mDNS query message
01048       return;
01049    }
01050 
01051    //When possible, a responder should, for the sake of network
01052    //efficiency, aggregate as many responses as possible into a
01053    //single mDNS response message
01054    if(response->buffer == NULL)
01055    {
01056       //Create an empty mDNS response message
01057       error = mdnsCreateMessage(response, TRUE);
01058       //Any error to report?
01059       if(error)
01060          return;
01061    }
01062 
01063    //Take the identifier from the query message
01064    response->dnsHeader->id = query->dnsHeader->id;
01065 
01066    //Point to the first question
01067    offset = sizeof(DnsHeader);
01068 
01069    //Start of exception handling block
01070    do
01071    {
01072       //Parse the Question Section
01073       for(i = 0; i < ntohs(query->dnsHeader->qdcount); i++)
01074       {
01075          //Parse resource record name
01076          n = dnsParseName(query->dnsHeader, query->length, offset, NULL, 0);
01077          //Invalid name?
01078          if(!n)
01079             break;
01080          //Malformed mDNS message?
01081          if((n + sizeof(DnsQuestion)) > query->length)
01082             break;
01083 
01084          //Point to the corresponding entry
01085          question = DNS_GET_QUESTION(query->dnsHeader, n);
01086 
01087          //Parse question
01088          error = mdnsResponderParseQuestion(interface, query,
01089             offset, question, response);
01090          //Any error to report?
01091          if(error)
01092             break;
01093 
01094 #if (DNS_SD_SUPPORT == ENABLED)
01095          //Parse resource record
01096          error = dnsSdParseQuestion(interface, query, offset,
01097             question, response);
01098          //Any error to report?
01099          if(error)
01100             break;
01101 #endif
01102          //Point to the next question
01103          offset = n + sizeof(DnsQuestion);
01104       }
01105 
01106       //Any error while parsing the Question Section?
01107       if(i != ntohs(query->dnsHeader->qdcount))
01108          break;
01109 
01110       //Parse the Known-Answer Section
01111       for(i = 0; i < ntohs(query->dnsHeader->ancount); i++)
01112       {
01113          //Parse resource record name
01114          n = dnsParseName(query->dnsHeader, query->length, offset, NULL, 0);
01115          //Invalid name?
01116          if(!n)
01117             break;
01118 
01119          //Point to the associated resource record
01120          record = DNS_GET_RESOURCE_RECORD(query->dnsHeader, n);
01121          //Point to the resource data
01122          n += sizeof(DnsResourceRecord);
01123 
01124          //Make sure the resource record is valid
01125          if(n > query->length)
01126             break;
01127          if((n + ntohs(record->rdlength)) > query->length)
01128             break;
01129 
01130          //Parse resource record
01131          mdnsResponderParseKnownAnRecord(interface, query, offset,
01132             record, response);
01133 
01134          //Point to the next resource record
01135          offset = n + ntohs(record->rdlength);
01136       }
01137 
01138       //Any error while parsing the Answer Section?
01139       if(i != ntohs(query->dnsHeader->ancount))
01140          break;
01141 
01142       //Parse Authority Section
01143       for(i = 0; i < ntohs(query->dnsHeader->nscount); i++)
01144       {
01145          //Parse resource record name
01146          n = dnsParseName(query->dnsHeader, query->length, offset, NULL, 0);
01147          //Invalid name?
01148          if(!n)
01149             break;
01150 
01151          //Point to the associated resource record
01152          record = DNS_GET_RESOURCE_RECORD(query->dnsHeader, n);
01153          //Point to the resource data
01154          n += sizeof(DnsResourceRecord);
01155 
01156          //Make sure the resource record is valid
01157          if(n > query->length)
01158             break;
01159          if((n + ntohs(record->rdlength)) > query->length)
01160             break;
01161 
01162          //Check for host name conflict
01163          mdnsResponderParseNsRecord(interface, query, offset, record);
01164 
01165 #if (DNS_SD_SUPPORT == ENABLED)
01166          //Check for service instance name conflict
01167          dnsSdParseNsRecord(interface, query, offset, record);
01168 #endif
01169          //Point to the next resource record
01170          offset = n + ntohs(record->rdlength);
01171       }
01172 
01173       //Any error while parsing the Authority Section?
01174       if(i != ntohs(query->dnsHeader->nscount))
01175          break;
01176 
01177       //End of exception handling block
01178    } while(0);
01179 
01180    //Should a mDNS message be send in response to the query?
01181    if(response->dnsHeader->ancount > 0)
01182    {
01183       //If the source UDP port in a received Multicast DNS query is not port 5353,
01184       //this indicates that the querier originating the query is a simple resolver
01185       if(ntohs(query->udpHeader->srcPort) != MDNS_PORT)
01186       {
01187 #if (DNS_SD_SUPPORT == ENABLED)
01188          //Additional record generation (DNS-SD)
01189          dnsSdGenerateAdditionalRecords(interface, response, TRUE);
01190 #endif
01191          //Additional record generation (mDNS)
01192          mdnsResponderGenerateAdditionalRecords(interface, response, TRUE);
01193 
01194          //Destination port
01195          destPort = ntohs(query->udpHeader->srcPort);
01196 
01197          //Send mDNS response message
01198          mdnsSendMessage(interface, response, &destIpAddr, destPort);
01199          //Free previously allocated memory
01200          mdnsDeleteMessage(response);
01201       }
01202       else
01203       {
01204          //Check whether the answer should be delayed
01205          if(query->dnsHeader->tc)
01206          {
01207             //In the case where the query has the TC (truncated) bit set, indicating
01208             //that subsequent Known-Answer packets will follow, responders should
01209             //delay their responses by a random amount of time selected with uniform
01210             //random distribution in the range 400-500 ms
01211             response->timeout = netGetRandRange(400, 500);
01212 
01213             //Save current time
01214             response->timestamp = osGetSystemTime();
01215          }
01216          else if(response->sharedRecordCount > 0)
01217          {
01218             //In any case where there may be multiple responses, such as queries
01219             //where the answer is a member of a shared resource record set, each
01220             //responder should delay its response by a random amount of time
01221             //selected with uniform random distribution in the range 20-120 ms
01222             response->timeout = netGetRandRange(20, 120);
01223 
01224             //Save current time
01225             response->timestamp = osGetSystemTime();
01226          }
01227          else
01228          {
01229 #if (DNS_SD_SUPPORT == ENABLED)
01230             //Additional record generation (refer to RFC 6763 section 12)
01231             dnsSdGenerateAdditionalRecords(interface, response, FALSE);
01232 #endif
01233             //Additional record generation (mDNS)
01234             mdnsResponderGenerateAdditionalRecords(interface, response, FALSE);
01235 
01236             //Send mDNS response message
01237             mdnsSendMessage(interface, response, &destIpAddr, MDNS_PORT);
01238             //Free previously allocated memory
01239             mdnsDeleteMessage(response);
01240          }
01241       }
01242    }
01243    else
01244    {
01245       //Free mDNS response message
01246       mdnsDeleteMessage(response);
01247    }
01248 }
01249 
01250 
01251 /**
01252  * @brief Parse a question
01253  * @param[in] interface Underlying network interface
01254  * @param[in] query Incoming mDNS query message
01255  * @param[in] offset Offset to first byte of the question
01256  * @param[in] question Pointer to the question
01257  * @param[in,out] response mDNS response message
01258  * @return Error code
01259  **/
01260 
01261 error_t mdnsResponderParseQuestion(NetInterface *interface, const MdnsMessage *query,
01262    size_t offset, const DnsQuestion *question, MdnsMessage *response)
01263 {
01264    error_t error;
01265    uint16_t qclass;
01266    uint16_t qtype;
01267    uint32_t ttl;
01268    bool_t cacheFlush;
01269    MdnsResponderContext *context;
01270 
01271    //Point to the mDNS responder context
01272    context = interface->mdnsResponderContext;
01273 
01274    //Check the state of the mDNS responder
01275    if(context->state != MDNS_STATE_ANNOUNCING &&
01276       context->state != MDNS_STATE_IDLE)
01277    {
01278       //Do not respond to mDNS queries during probing
01279       return NO_ERROR;
01280    }
01281 
01282    //Convert the query class to host byte order
01283    qclass = ntohs(question->qclass);
01284    //Discard QU flag
01285    qclass &= ~MDNS_QCLASS_QU;
01286 
01287    //Convert the query type to host byte order
01288    qtype = ntohs(question->qtype);
01289 
01290    //Get the TTL resource record
01291    ttl = context->settings.ttl;
01292 
01293    //Check whether the querier originating the query is a simple resolver
01294    if(ntohs(query->udpHeader->srcPort) != MDNS_PORT)
01295    {
01296       //The resource record TTL given in a legacy unicast response should
01297       //not be greater than ten seconds, even if the true TTL of the mDNS
01298       //resource record is higher
01299       ttl = MIN(ttl, MDNS_LEGACY_UNICAST_RR_TTL);
01300 
01301       //The cache-flush bit must not be set in legacy unicast responses
01302       cacheFlush = FALSE;
01303    }
01304    else
01305    {
01306       //The cache-bit should be set for unique resource records
01307       cacheFlush = TRUE;
01308    }
01309 
01310    //Check the class of the query
01311    if(qclass == DNS_RR_CLASS_IN || qclass == DNS_RR_CLASS_ANY)
01312    {
01313       //Compare domain name
01314       if(!mdnsCompareName(query->dnsHeader, query->length,
01315          offset, context->hostname, "", ".local", 0))
01316       {
01317 #if (IPV4_SUPPORT == ENABLED)
01318          //A query?
01319          if(qtype == DNS_RR_TYPE_A)
01320          {
01321             //Format A resource record
01322             error = mdnsResponderAddIpv4AddrRecord(interface,
01323                response, cacheFlush, ttl);
01324             //Any error to report?
01325             if(error)
01326                return error;
01327          }
01328          else
01329 #endif
01330 #if (IPV6_SUPPORT == ENABLED)
01331          //AAAA query?
01332          if(qtype == DNS_RR_TYPE_AAAA)
01333          {
01334             //Format AAAA resource record
01335             error = mdnsResponderAddIpv6AddrRecord(interface,
01336                response, cacheFlush, ttl);
01337             //Any error to report?
01338             if(error)
01339                return error;
01340          }
01341          else
01342 #endif
01343          //ANY query?
01344          if(qtype == DNS_RR_TYPE_ANY)
01345          {
01346             //Format A resource record
01347             error = mdnsResponderAddIpv4AddrRecord(interface,
01348                response, cacheFlush, ttl);
01349             //Any error to report?
01350             if(error)
01351                return error;
01352 
01353             //Format AAAA resource record
01354             error = mdnsResponderAddIpv6AddrRecord(interface,
01355                response, cacheFlush, ttl);
01356             //Any error to report?
01357             if(error)
01358                return error;
01359 
01360             //Format NSEC resource record
01361             error = mdnsResponderAddNsecRecord(interface,
01362                response, cacheFlush, ttl);
01363             //Any error to report?
01364             if(error)
01365                return error;
01366          }
01367          else
01368          {
01369             //Format NSEC resource record
01370             error = mdnsResponderAddNsecRecord(interface,
01371                response, cacheFlush, ttl);
01372             //Any error to report?
01373             if(error)
01374                return error;
01375          }
01376       }
01377 
01378 #if (IPV4_SUPPORT == ENABLED)
01379       //Reverse DNS lookup?
01380       if(!mdnsCompareName(query->dnsHeader, query->length,
01381          offset, context->ipv4ReverseName, "in-addr", ".arpa", 0))
01382       {
01383          //PTR query?
01384          if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY)
01385          {
01386             //Format reverse address mapping PTR record (IPv4)
01387             error = mdnsResponderAddIpv4ReversePtrRecord(interface,
01388                response, cacheFlush, ttl);
01389             //Any error to report?
01390             if(error)
01391                return error;
01392          }
01393       }
01394 #endif
01395 #if (IPV6_SUPPORT == ENABLED)
01396       //Reverse DNS lookup?
01397       if(!mdnsCompareName(query->dnsHeader, query->length,
01398          offset, context->ipv6ReverseName, "ip6", ".arpa", 0))
01399       {
01400          //PTR query?
01401          if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY)
01402          {
01403             //Format reverse address mapping PTR record (IPv6)
01404             error = mdnsResponderAddIpv6ReversePtrRecord(interface,
01405                response, cacheFlush, ttl);
01406             //Any error to report?
01407             if(error)
01408                return error;
01409          }
01410       }
01411 #endif
01412    }
01413 
01414    //Successful processing
01415    return NO_ERROR;
01416 }
01417 
01418 
01419 /**
01420  * @brief Parse a resource record from the Known-Answer Section
01421  * @param[in] interface Underlying network interface
01422  * @param[in] query Incoming mDNS query message
01423  * @param[in] queryOffset Offset to first byte of the resource record
01424  * @param[in] queryRecord Pointer to the resource record
01425  * @param[in,out] response mDNS response message
01426  **/
01427 
01428 void mdnsResponderParseKnownAnRecord(NetInterface *interface, const MdnsMessage *query,
01429    size_t queryOffset, const DnsResourceRecord *queryRecord, MdnsMessage *response)
01430 {
01431    size_t i;
01432    size_t n;
01433    size_t responseOffset;
01434    DnsResourceRecord *responseRecord;
01435 
01436    //mDNS responses must not contain any questions in the Question Section
01437    if(response->dnsHeader->qdcount == 0)
01438    {
01439       //Point to the first resource record
01440       responseOffset = sizeof(DnsHeader);
01441 
01442       //Parse the Answer Section of the response
01443       for(i = 0; i < response->dnsHeader->ancount; i++)
01444       {
01445          //Parse resource record name
01446          n = dnsParseName(response->dnsHeader, response->length, responseOffset, NULL, 0);
01447          //Invalid name?
01448          if(!n)
01449             break;
01450 
01451          //Point to the associated resource record
01452          responseRecord = DNS_GET_RESOURCE_RECORD(response->dnsHeader, n);
01453          //Point to the resource data
01454          n += sizeof(DnsResourceRecord);
01455 
01456          //Make sure the resource record is valid
01457          if(n > response->length)
01458             break;
01459 
01460          //Point to the end of the resource record
01461          n += ntohs(responseRecord->rdlength);
01462 
01463          //Make sure the resource record is valid
01464          if(n > response->length)
01465             break;
01466 
01467          //Compare resource record names
01468          if(!dnsCompareEncodedName(query->dnsHeader, query->length, queryOffset,
01469             response->dnsHeader, response->length, responseOffset, 0))
01470          {
01471             //Compare the contents of the resource records
01472             if(!mdnsCompareRecord(query, queryOffset, queryRecord,
01473                response, responseOffset, responseRecord))
01474             {
01475                //A mDNS responder must not answer a mDNS query if the answer
01476                //it would give is already included in the Answer Section with
01477                //an RR TTL at least half the correct value
01478                if(ntohl(queryRecord->ttl) >= (ntohl(responseRecord->ttl) / 2))
01479                {
01480                   //Perform Known-Answer Suppression
01481                   memmove((uint8_t *) response->dnsHeader + responseOffset,
01482                      (uint8_t *) response->dnsHeader + n, response->length - n);
01483 
01484                   //Update the length of the mDNS response message
01485                   response->length -= (n - responseOffset);
01486                   //Update the number of resource records in the Answer Section
01487                   response->dnsHeader->ancount--;
01488 
01489                   //Keep at the same position
01490                   n = responseOffset;
01491                   i--;
01492                }
01493             }
01494          }
01495 
01496          //Point to the next resource record
01497          responseOffset = n;
01498       }
01499    }
01500 }
01501 
01502 
01503 /**
01504  * @brief Parse a resource record from the Authority Section
01505  * @param[in] interface Underlying network interface
01506  * @param[in] query Incoming mDNS query message
01507  * @param[in] offset Offset to first byte of the resource record
01508  * @param[in] record Pointer to the resource record
01509  **/
01510 
01511 void mdnsResponderParseNsRecord(NetInterface *interface,
01512    const MdnsMessage *query, size_t offset, const DnsResourceRecord *record)
01513 {
01514    bool_t tieBreakLost;
01515    uint16_t rclass;
01516    MdnsResponderContext *context;
01517 
01518    //Point to the mDNS responder context
01519    context = interface->mdnsResponderContext;
01520 
01521    //When a host that is probing for a record sees another host issue a query
01522    //for the same record, it consults the Authority Section of that query.
01523    //If it finds any resource record there which answers the query, then it
01524    //compares the data of that resource record with its own tentative data
01525    if(!mdnsCompareName(query->dnsHeader, query->length,
01526       offset, context->hostname, "", ".local", 0))
01527    {
01528       //Convert the class to host byte order
01529       rclass = ntohs(record->rclass);
01530       //Discard Cache Flush flag
01531       rclass &= ~MDNS_RCLASS_CACHE_FLUSH;
01532 
01533       //Check the class of the resource record
01534       if(rclass == DNS_RR_CLASS_IN)
01535       {
01536 #if (IPV4_SUPPORT == ENABLED)
01537          //A resource record found?
01538          if(ntohs(record->rtype) == DNS_RR_TYPE_A)
01539          {
01540             //Apply tie-breaking rules
01541             tieBreakLost = TRUE;
01542 
01543             //Verify the length of the data field
01544             if(ntohs(record->rdlength) == sizeof(Ipv4Addr))
01545             {
01546                //Valid host address?
01547                if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_VALID)
01548                {
01549                   //The two records are compared and the lexicographically
01550                   //later data wins
01551                   if(memcmp(&interface->ipv4Context.addr, record->rdata,
01552                      sizeof(Ipv4Addr)) >= 0)
01553                   {
01554                      tieBreakLost = FALSE;
01555                   }
01556                }
01557             }
01558 
01559             //Check whether the host has lost the tie-break
01560             if(tieBreakLost)
01561                context->tieBreakLost = TRUE;
01562          }
01563 #endif
01564 #if (IPV6_SUPPORT == ENABLED)
01565          //AAAA resource record found?
01566          if(ntohs(record->rtype) == DNS_RR_TYPE_AAAA)
01567          {
01568             //Apply tie-breaking rules
01569             tieBreakLost = TRUE;
01570 
01571             //Verify the length of the data field
01572             if(ntohs(record->rdlength) == sizeof(Ipv6Addr))
01573             {
01574                uint_t i;
01575                Ipv6AddrEntry *entry;
01576 
01577                //Loop through the list of IPv6 addresses assigned to the interface
01578                for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
01579                {
01580                   //Point to the current entry
01581                   entry = &interface->ipv6Context.addrList[i];
01582 
01583                   //Valid IPv6 address
01584                   if(entry->state != IPV6_ADDR_STATE_INVALID)
01585                   {
01586                      //The two records are compared and the lexicographically
01587                      //later data wins
01588                      if(memcmp(&interface->ipv6Context.addrList[i].addr,
01589                         record->rdata, sizeof(Ipv6Addr)) >= 0)
01590                      {
01591                         tieBreakLost = FALSE;
01592                      }
01593                   }
01594                }
01595             }
01596 
01597             //Check whether the host has lost the tie-break
01598             if(tieBreakLost)
01599                context->tieBreakLost = TRUE;
01600          }
01601 #endif
01602       }
01603    }
01604 }
01605 
01606 
01607 /**
01608  * @brief Parse a resource record from the Answer Section
01609  * @param[in] interface Underlying network interface
01610  * @param[in] response Incoming mDNS response message
01611  * @param[in] offset Offset to first byte of the resource record to be checked
01612  * @param[in] record Pointer to the resource record
01613  **/
01614 
01615 void mdnsResponderParseAnRecord(NetInterface *interface,
01616    const MdnsMessage *response, size_t offset, const DnsResourceRecord *record)
01617 {
01618    bool_t conflict;
01619    uint16_t rclass;
01620    MdnsResponderContext *context;
01621 
01622    //Point to the mDNS responder context
01623    context = interface->mdnsResponderContext;
01624 
01625    //Check for conflicts
01626    if(!mdnsCompareName(response->dnsHeader, response->length,
01627       offset, context->hostname, "", ".local", 0))
01628    {
01629       //Convert the class to host byte order
01630       rclass = ntohs(record->rclass);
01631       //Discard Cache Flush flag
01632       rclass &= ~MDNS_RCLASS_CACHE_FLUSH;
01633 
01634       //Check the class of the resource record
01635       if(rclass == DNS_RR_CLASS_IN)
01636       {
01637 #if (IPV4_SUPPORT == ENABLED)
01638          //A resource record found?
01639          if(ntohs(record->rtype) == DNS_RR_TYPE_A)
01640          {
01641             //A conflict occurs when a mDNS responder has a unique record for
01642             //which it is currently authoritative, and it receives a mDNS
01643             //response message containing a record with the same name, rrtype
01644             //and rrclass, but inconsistent rdata
01645             conflict = TRUE;
01646 
01647             //Verify the length of the data field
01648             if(ntohs(record->rdlength) == sizeof(Ipv4Addr))
01649             {
01650                //Valid host address?
01651                if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_VALID)
01652                {
01653                   //Check whether the rdata field is consistent
01654                   if(ipv4CompAddr(&interface->ipv4Context.addr, record->rdata))
01655                      context->conflict = FALSE;
01656                }
01657             }
01658 
01659             //Check whether the hostname is already in use by some other host
01660             if(conflict)
01661                context->conflict = TRUE;
01662          }
01663 #endif
01664 #if (IPV6_SUPPORT == ENABLED)
01665          //AAAA resource record found?
01666          if(ntohs(record->rtype) == DNS_RR_TYPE_AAAA)
01667          {
01668             //A conflict occurs when a mDNS responder has a unique record for
01669             //which it is currently authoritative, and it receives a mDNS
01670             //response message containing a record with the same name, rrtype
01671             //and rrclass, but inconsistent rdata
01672             conflict = TRUE;
01673 
01674             //Verify the length of the data field
01675             if(ntohs(record->rdlength) == sizeof(Ipv6Addr))
01676             {
01677                uint_t i;
01678                Ipv6AddrEntry *entry;
01679 
01680                //Loop through the list of IPv6 addresses assigned to the interface
01681                for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
01682                {
01683                   //Point to the current entry
01684                   entry = &interface->ipv6Context.addrList[i];
01685 
01686                   //Valid IPv6 address
01687                   if(entry->state != IPV6_ADDR_STATE_INVALID)
01688                   {
01689                      //Check whether the rdata field is consistent
01690                      if(ipv6CompAddr(&interface->ipv6Context.addrList[i].addr, record->rdata))
01691                         conflict = FALSE;
01692                   }
01693                }
01694             }
01695 
01696             //Check whether the hostname is already in use by some other host
01697             if(conflict)
01698                context->conflict = TRUE;
01699          }
01700 #endif
01701       }
01702    }
01703 }
01704 
01705 
01706 /**
01707  * @brief Additional record generation
01708  * @param[in] interface Underlying network interface
01709  * @param[in,out] response mDNS response message
01710  * @param[in] legacyUnicast This flag is set for legacy unicast responses
01711  **/
01712 
01713 void mdnsResponderGenerateAdditionalRecords(NetInterface *interface,
01714    MdnsMessage *response, bool_t legacyUnicast)
01715 {
01716    error_t error;
01717    uint_t i;
01718    uint_t k;
01719    size_t n;
01720    size_t offset;
01721    uint_t ancount;
01722    uint16_t rclass;
01723    uint32_t ttl;
01724    bool_t cacheFlush;
01725    MdnsResponderContext *context;
01726    DnsResourceRecord *record;
01727 
01728    //Point to the mDNS responder context
01729    context = interface->mdnsResponderContext;
01730 
01731    //mDNS responses must not contain any questions in the Question Section
01732    if(response->dnsHeader->qdcount != 0)
01733       return;
01734 
01735    //Get the TTL resource record
01736    ttl = context->settings.ttl;
01737 
01738    //Check whether the querier originating the query is a simple resolver
01739    if(legacyUnicast)
01740    {
01741       //The resource record TTL given in a legacy unicast response should
01742       //not be greater than ten seconds, even if the true TTL of the mDNS
01743       //resource record is higher
01744       ttl = MIN(ttl, MDNS_LEGACY_UNICAST_RR_TTL);
01745 
01746       //The cache-flush bit must not be set in legacy unicast responses
01747       cacheFlush = FALSE;
01748    }
01749    else
01750    {
01751       //The cache-bit should be set for unique resource records
01752       cacheFlush = TRUE;
01753    }
01754 
01755    //Point to the first resource record
01756    offset = sizeof(DnsHeader);
01757 
01758    //Save the number of resource records in the Answer Section
01759    ancount = response->dnsHeader->ancount;
01760 
01761    //Compute the total number of resource records
01762    k = response->dnsHeader->ancount + response->dnsHeader->nscount +
01763       response->dnsHeader->arcount;
01764 
01765    //Loop through the resource records
01766    for(i = 0; i < k; i++)
01767    {
01768       //Parse resource record name
01769       n = dnsParseName(response->dnsHeader, response->length, offset, NULL, 0);
01770       //Invalid name?
01771       if(!n)
01772          break;
01773 
01774       //Point to the associated resource record
01775       record = DNS_GET_RESOURCE_RECORD(response->dnsHeader, n);
01776       //Point to the resource data
01777       n += sizeof(DnsResourceRecord);
01778 
01779       //Make sure the resource record is valid
01780       if(n > response->length)
01781          break;
01782       if((n + ntohs(record->rdlength)) > response->length)
01783          break;
01784 
01785       //Convert the record class to host byte order
01786       rclass = ntohs(record->rclass);
01787       //Discard the cache-flush bit
01788       rclass &= ~MDNS_RCLASS_CACHE_FLUSH;
01789 
01790       //Check the class of the resource record
01791       if(rclass == DNS_RR_CLASS_IN)
01792       {
01793          //A record?
01794          if(ntohs(record->rtype) == DNS_RR_TYPE_A)
01795          {
01796 #if (IPV6_SUPPORT == ENABLED)
01797             //When a mDNS responder places an IPv4 address record into a
01798             //response message, it should also place any IPv6 address records
01799             //with the same name into the Additional Section
01800             error = mdnsResponderAddIpv6AddrRecord(interface,
01801                response, cacheFlush, ttl);
01802 #else
01803             //In the event that a device has only IPv4 addresses but no IPv6
01804             //addresses, then the appropriate NSEC record should be placed
01805             //into the Additional Section
01806             error = mdnsResponderAddNsecRecord(interface,
01807                response, cacheFlush, ttl);
01808 #endif
01809             //Any error to report?
01810             if(error)
01811                return;
01812          }
01813          //AAAA record?
01814          else if(ntohs(record->rtype) == DNS_RR_TYPE_AAAA)
01815          {
01816 #if (IPV4_SUPPORT == ENABLED)
01817             //When a mDNS responder places an IPv6 address record into a
01818             //response message, it should also place any IPv4 address records
01819             //with the same name into the Additional Section
01820             error = mdnsResponderAddIpv4AddrRecord(interface,
01821                response, cacheFlush, ttl);
01822 #else
01823             //In the event that a device has only IPv6 addresses but no IPv4
01824             //addresses, then the appropriate NSEC record should be placed
01825             //into the Additional Section
01826             error = mdnsResponderAddNsecRecord(interface,
01827                response, cacheFlush, ttl);
01828 #endif
01829             //Any error to report?
01830             if(error)
01831                return;
01832          }
01833          //SRV record?
01834          else if(ntohs(record->rtype) == DNS_RR_TYPE_SRV)
01835          {
01836             //Format A resource record
01837             error = mdnsResponderAddIpv4AddrRecord(interface,
01838                response, cacheFlush, ttl);
01839             //Any error to report?
01840             if(error)
01841                return;
01842 
01843             //Format AAAA resource record
01844             error = mdnsResponderAddIpv6AddrRecord(interface,
01845                response, cacheFlush, ttl);
01846             //Any error to report?
01847             if(error)
01848                return;
01849 
01850 #if (IPV4_SUPPORT == DISABLED || IPV6_SUPPORT == DISABLED)
01851             //In the event that a device has only IPv4 addresses but no IPv6
01852             //addresses, or vice versa, then the appropriate NSEC record should
01853             //be placed into the additional section, so that queriers can know
01854             //with certainty that the device has no addresses of that kind
01855             error = mdnsResponderAddNsecRecord(interface,
01856                response, cacheFlush, ttl);
01857             //Any error to report?
01858             if(error)
01859                return;
01860 #endif
01861          }
01862       }
01863 
01864       //Point to the next resource record
01865       offset = n + ntohs(record->rdlength);
01866    }
01867 
01868    //Number of resource records in the Additional Section
01869    response->dnsHeader->arcount += response->dnsHeader->ancount - ancount;
01870    //Number of resource records in the Answer Section
01871    response->dnsHeader->ancount = ancount;
01872 }
01873 
01874 
01875 /**
01876  * @brief Add A record to a mDNS message
01877  * @param[in] interface Underlying network interface
01878  * @param[in,out] message Pointer to the mDNS message
01879  * @param[in] cacheFlush Cache-flush bit
01880  * @param[in] ttl Resource record TTL (cache lifetime)
01881  * @return Error code
01882  **/
01883 
01884 error_t mdnsResponderAddIpv4AddrRecord(NetInterface *interface,
01885    MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
01886 {
01887 #if (IPV4_SUPPORT == ENABLED)
01888    size_t n;
01889    size_t offset;
01890    bool_t duplicate;
01891    MdnsResponderContext *context;
01892    DnsResourceRecord *record;
01893 
01894    //Point to the mDNS responder context
01895    context = interface->mdnsResponderContext;
01896 
01897    //Valid IPv4 host address?
01898    if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_VALID)
01899    {
01900       //Check whether the resource record is already present in the Answer
01901       //Section of the message
01902       duplicate = mdnsCheckDuplicateRecord(message, context->hostname,
01903          "", ".local", DNS_RR_TYPE_A);
01904 
01905       //The duplicates should be suppressed and the resource record should
01906       //appear only once in the list
01907       if(!duplicate)
01908       {
01909          //Set the position to the end of the buffer
01910          offset = message->length;
01911 
01912          //The first pass calculates the length of the DNS encoded host name
01913          n = mdnsEncodeName(context->hostname, "", ".local", NULL);
01914 
01915          //Check the length of the resulting mDNS message
01916          if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
01917             return ERROR_MESSAGE_TOO_LONG;
01918 
01919          //The second pass encodes the host name using the DNS name notation
01920          offset += mdnsEncodeName(context->hostname, "", ".local",
01921             (uint8_t *) message->dnsHeader + offset);
01922 
01923          //Consider the length of the resource record itself
01924          n = sizeof(DnsResourceRecord) + sizeof(Ipv4Addr);
01925 
01926          //Check the length of the resulting mDNS message
01927          if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
01928             return ERROR_MESSAGE_TOO_LONG;
01929 
01930          //Point to the corresponding resource record
01931          record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
01932 
01933          //Fill in resource record
01934          record->rtype = HTONS(DNS_RR_TYPE_A);
01935          record->rclass = HTONS(DNS_RR_CLASS_IN);
01936          record->ttl = htonl(ttl);
01937          record->rdlength = HTONS(sizeof(Ipv4Addr));
01938 
01939          //Check whether the cache-flush bit should be set
01940          if(cacheFlush)
01941             record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
01942 
01943          //Copy IPv4 address
01944          ipv4CopyAddr(record->rdata, &interface->ipv4Context.addr);
01945 
01946          //Number of resource records in the answer section
01947          message->dnsHeader->ancount++;
01948          //Update the length of the mDNS response message
01949          message->length = offset + n;
01950       }
01951    }
01952 #endif
01953 
01954    //Successful processing
01955    return NO_ERROR;
01956 }
01957 
01958 
01959 /**
01960  * @brief Add AAAA record to a mDNS message
01961  * @param[in] interface Underlying network interface
01962  * @param[in,out] message Pointer to the mDNS message
01963  * @param[in] cacheFlush Cache-flush bit
01964  * @param[in] ttl Resource record TTL (cache lifetime)
01965  * @return Error code
01966  **/
01967 
01968 error_t mdnsResponderAddIpv6AddrRecord(NetInterface *interface,
01969    MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
01970 {
01971 #if (IPV6_SUPPORT == ENABLED)
01972    size_t n;
01973    size_t offset;
01974    bool_t duplicate;
01975    MdnsResponderContext *context;
01976    DnsResourceRecord *record;
01977 
01978    //Point to the mDNS responder context
01979    context = interface->mdnsResponderContext;
01980 
01981    //Valid IPv6 link-local address?
01982    if(ipv6GetLinkLocalAddrState(interface) == IPV6_ADDR_STATE_PREFERRED)
01983    {
01984       //Check whether the resource record is already present in the Answer
01985       //Section of the message
01986       duplicate = mdnsCheckDuplicateRecord(message, context->hostname,
01987          "", ".local", DNS_RR_TYPE_AAAA);
01988 
01989       //The duplicates should be suppressed and the resource record should
01990       //appear only once in the list
01991       if(!duplicate)
01992       {
01993          //Set the position to the end of the buffer
01994          offset = message->length;
01995 
01996          //The first pass calculates the length of the DNS encoded host name
01997          n = mdnsEncodeName(context->hostname, "", ".local", NULL);
01998 
01999          //Check the length of the resulting mDNS message
02000          if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
02001             return ERROR_MESSAGE_TOO_LONG;
02002 
02003          //The second pass encodes the host name using the DNS name notation
02004          offset += mdnsEncodeName(context->hostname, "", ".local",
02005             (uint8_t *) message->dnsHeader + offset);
02006 
02007          //Consider the length of the resource record itself
02008          n = sizeof(DnsResourceRecord) + sizeof(Ipv6Addr);
02009 
02010          //Check the length of the resulting mDNS message
02011          if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
02012             return ERROR_MESSAGE_TOO_LONG;
02013 
02014          //Point to the corresponding resource record
02015          record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
02016 
02017          //Fill in resource record
02018          record->rtype = HTONS(DNS_RR_TYPE_AAAA);
02019          record->rclass = HTONS(DNS_RR_CLASS_IN);
02020          record->ttl = htonl(ttl);
02021          record->rdlength = HTONS(sizeof(Ipv6Addr));
02022 
02023          //Check whether the cache-flush bit should be set
02024          if(cacheFlush)
02025             record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
02026 
02027          //Copy IPv6 address
02028          ipv6CopyAddr(record->rdata, &interface->ipv6Context.addrList[0].addr);
02029 
02030          //Number of resource records in the answer section
02031          message->dnsHeader->ancount++;
02032          //Update the length of the mDNS response message
02033          message->length = offset + n;
02034       }
02035    }
02036 #endif
02037 
02038    //Successful processing
02039    return NO_ERROR;
02040 }
02041 
02042 
02043 /**
02044  * @brief Add reverse address mapping PTR record (IPv4)
02045  * @param[in] interface Underlying network interface
02046  * @param[in,out] message Pointer to the mDNS message
02047  * @param[in] cacheFlush Cache-flush bit
02048  * @param[in] ttl Resource record TTL (cache lifetime)
02049  * @return Error code
02050  **/
02051 
02052 error_t mdnsResponderAddIpv4ReversePtrRecord(NetInterface *interface,
02053    MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
02054 {
02055 #if (IPV4_SUPPORT == ENABLED)
02056    size_t n;
02057    size_t offset;
02058    bool_t duplicate;
02059    MdnsResponderContext *context;
02060    DnsResourceRecord *record;
02061 
02062    //Point to the mDNS responder context
02063    context = interface->mdnsResponderContext;
02064 
02065    //Valid reverse name?
02066    if(context->ipv4ReverseName[0] != '\0')
02067    {
02068       //Check whether the resource record is already present in the Answer
02069       //Section of the message
02070       duplicate = mdnsCheckDuplicateRecord(message, context->ipv4ReverseName,
02071          "in-addr", ".arpa", DNS_RR_TYPE_PTR);
02072 
02073       //The duplicates should be suppressed and the resource record should
02074       //appear only once in the list
02075       if(!duplicate)
02076       {
02077          //Set the position to the end of the buffer
02078          offset = message->length;
02079 
02080          //The first pass calculates the length of the DNS encoded reverse name
02081          n = mdnsEncodeName(context->ipv4ReverseName, "in-addr", ".arpa", NULL);
02082 
02083          //Check the length of the resulting mDNS message
02084          if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
02085             return ERROR_MESSAGE_TOO_LONG;
02086 
02087          //The second pass encodes the reverse name using the DNS name notation
02088          offset += mdnsEncodeName(context->ipv4ReverseName, "in-addr", ".arpa",
02089             (uint8_t *) message->dnsHeader + offset);
02090 
02091          //Consider the length of the resource record itself
02092          n = sizeof(DnsResourceRecord) + sizeof(Ipv4Addr);
02093 
02094          //Check the length of the resulting mDNS message
02095          if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
02096             return ERROR_MESSAGE_TOO_LONG;
02097 
02098          //Point to the corresponding resource record
02099          record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
02100 
02101          //Fill in resource record
02102          record->rtype = HTONS(DNS_RR_TYPE_PTR);
02103          record->rclass = HTONS(DNS_RR_CLASS_IN);
02104          record->ttl = htonl(ttl);
02105 
02106          //Check whether the cache-flush bit should be set
02107          if(cacheFlush)
02108             record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
02109 
02110          //Advance write index
02111          offset += sizeof(DnsResourceRecord);
02112 
02113          //The first pass calculates the length of the DNS encoded host name
02114          n = mdnsEncodeName("", context->hostname, ".local", NULL);
02115 
02116          //Check the length of the resulting mDNS message
02117          if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
02118             return ERROR_MESSAGE_TOO_LONG;
02119 
02120          //The second pass encodes the host name using DNS notation
02121          n = mdnsEncodeName("", context->hostname, ".local", record->rdata);
02122 
02123          //Convert length field to network byte order
02124          record->rdlength = htons(n);
02125 
02126          //Number of resource records in the answer section
02127          message->dnsHeader->ancount++;
02128          //Update the length of the mDNS response message
02129          message->length = offset + n;
02130       }
02131    }
02132 #endif
02133 
02134    //Successful processing
02135    return NO_ERROR;
02136 }
02137 
02138 
02139 /**
02140  * @brief Add reverse address mapping PTR record (IPv6)
02141  * @param[in] interface Underlying network interface
02142  * @param[in,out] message Pointer to the mDNS message
02143  * @param[in] cacheFlush Cache-flush bit
02144  * @param[in] ttl Resource record TTL (cache lifetime)
02145  * @return Error code
02146  **/
02147 
02148 error_t mdnsResponderAddIpv6ReversePtrRecord(NetInterface *interface,
02149    MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
02150 {
02151 #if (IPV6_SUPPORT == ENABLED)
02152    size_t n;
02153    size_t offset;
02154    bool_t duplicate;
02155    MdnsResponderContext *context;
02156    DnsResourceRecord *record;
02157 
02158    //Point to the mDNS responder context
02159    context = interface->mdnsResponderContext;
02160 
02161    //Valid reverse name?
02162    if(context->ipv6ReverseName[0] != '\0')
02163    {
02164       //Check whether the resource record is already present in the Answer
02165       //Section of the message
02166       duplicate = mdnsCheckDuplicateRecord(message, context->ipv6ReverseName,
02167          "ip6", ".arpa", DNS_RR_TYPE_PTR);
02168 
02169       //The duplicates should be suppressed and the resource record should
02170       //appear only once in the list
02171       if(!duplicate)
02172       {
02173          //Set the position to the end of the buffer
02174          offset = message->length;
02175 
02176          //The first pass calculates the length of the DNS encoded reverse name
02177          n = mdnsEncodeName(context->ipv6ReverseName, "ip6", ".arpa", NULL);
02178 
02179          //Check the length of the resulting mDNS message
02180          if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
02181             return ERROR_MESSAGE_TOO_LONG;
02182 
02183          //The second pass encodes the reverse name using the DNS name notation
02184          offset += mdnsEncodeName(context->ipv6ReverseName, "ip6", ".arpa",
02185             (uint8_t *) message->dnsHeader + offset);
02186 
02187          //Consider the length of the resource record itself
02188          n = sizeof(DnsResourceRecord) + sizeof(Ipv4Addr);
02189 
02190          //Check the length of the resulting mDNS message
02191          if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
02192             return ERROR_MESSAGE_TOO_LONG;
02193 
02194          //Point to the corresponding resource record
02195          record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
02196 
02197          //Fill in resource record
02198          record->rtype = HTONS(DNS_RR_TYPE_PTR);
02199          record->rclass = HTONS(DNS_RR_CLASS_IN);
02200          record->ttl = htonl(ttl);
02201 
02202          //Check whether the cache-flush bit should be set
02203          if(cacheFlush)
02204             record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
02205 
02206          //Advance write index
02207          offset += sizeof(DnsResourceRecord);
02208 
02209          //The first pass calculates the length of the DNS encoded host name
02210          n = mdnsEncodeName("", context->hostname, ".local", NULL);
02211 
02212          //Check the length of the resulting mDNS message
02213          if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
02214             return ERROR_MESSAGE_TOO_LONG;
02215 
02216          //The second pass encodes the host name using DNS notation
02217          n = mdnsEncodeName("", context->hostname, ".local", record->rdata);
02218 
02219          //Convert length field to network byte order
02220          record->rdlength = htons(n);
02221 
02222          //Number of resource records in the answer section
02223          message->dnsHeader->ancount++;
02224          //Update the length of the mDNS response message
02225          message->length = offset + n;
02226       }
02227    }
02228 #endif
02229 
02230    //Successful processing
02231    return NO_ERROR;
02232 }
02233 
02234 
02235 /**
02236  * @brief Add NSEC record to a mDNS message
02237  * @param[in] interface Underlying network interface
02238  * @param[in,out] message Pointer to the mDNS message
02239  * @param[in] cacheFlush Cache-flush bit
02240  * @param[in] ttl Resource record TTL (cache lifetime)
02241  * @return Error code
02242  **/
02243 
02244 error_t mdnsResponderAddNsecRecord(NetInterface *interface,
02245    MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
02246 {
02247    size_t n;
02248    size_t offset;
02249    bool_t duplicate;
02250    size_t bitmapLength;
02251    uint8_t bitmap[8];
02252    MdnsResponderContext *context;
02253    DnsResourceRecord *record;
02254 
02255    //Point to the mDNS responder context
02256    context = interface->mdnsResponderContext;
02257 
02258    //Check whether the resource record is already present in the Answer
02259    //Section of the message
02260    duplicate = mdnsCheckDuplicateRecord(message, context->hostname,
02261       "", ".local", DNS_RR_TYPE_NSEC);
02262 
02263    //The duplicates should be suppressed and the resource record should
02264    //appear only once in the list
02265    if(!duplicate)
02266    {
02267       //The bitmap identifies the resource record types that exist
02268       memset(bitmap, 0, sizeof(bitmap));
02269 
02270 #if (IPV4_SUPPORT == ENABLED)
02271       //A resource record is supported
02272       DNS_SET_NSEC_BITMAP(bitmap, DNS_RR_TYPE_A);
02273 #endif
02274 
02275 #if (IPV6_SUPPORT == ENABLED)
02276       //A resource record is supported
02277       DNS_SET_NSEC_BITMAP(bitmap, DNS_RR_TYPE_AAAA);
02278 #endif
02279 
02280       //Compute the length of the bitmap
02281       for(bitmapLength = sizeof(bitmap); bitmapLength > 0; bitmapLength--)
02282       {
02283          //Trailing zero octets in the bitmap must be omitted...
02284          if(bitmap[bitmapLength - 1] != 0x00)
02285             break;
02286       }
02287 
02288       //Set the position to the end of the buffer
02289       offset = message->length;
02290 
02291       //The first pass calculates the length of the DNS encoded host name
02292       n = mdnsEncodeName(context->hostname, "", ".local", NULL);
02293 
02294       //Check the length of the resulting mDNS message
02295       if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
02296          return ERROR_MESSAGE_TOO_LONG;
02297 
02298       //The second pass encodes the host name using the DNS name notation
02299       offset += mdnsEncodeName(context->hostname, "", ".local",
02300          (uint8_t *) message->dnsHeader + offset);
02301 
02302       //Consider the length of the resource record itself
02303       if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
02304          return ERROR_MESSAGE_TOO_LONG;
02305 
02306       //Point to the corresponding resource record
02307       record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
02308 
02309       //Fill in resource record
02310       record->rtype = HTONS(DNS_RR_TYPE_NSEC);
02311       record->rclass = HTONS(DNS_RR_CLASS_IN);
02312       record->ttl = htonl(ttl);
02313 
02314       //Check whether the cache-flush bit should be set
02315       if(cacheFlush)
02316          record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
02317 
02318       //Advance write index
02319       offset += sizeof(DnsResourceRecord);
02320 
02321       //Check the length of the resulting mDNS message
02322       if((offset + n + 2 + bitmapLength) > MDNS_MESSAGE_MAX_SIZE)
02323          return ERROR_MESSAGE_TOO_LONG;
02324 
02325       //The Next Domain Name field contains the record's own name
02326       mdnsEncodeName(context->hostname, "", ".local", record->rdata);
02327 
02328       //DNS NSEC record is limited to Window Block number zero
02329       record->rdata[n++] = 0;
02330       //The Bitmap Length is a value in the range 1-32
02331       record->rdata[n++] = bitmapLength;
02332 
02333       //The Bitmap data identifies the resource record types that exist
02334       memcpy(record->rdata + n, bitmap, bitmapLength);
02335 
02336       //Convert length field to network byte order
02337       record->rdlength = htons(n + bitmapLength);
02338 
02339       //Number of resource records in the answer section
02340       message->dnsHeader->ancount++;
02341       //Update the length of the DNS message
02342       message->length = offset + n + bitmapLength;
02343    }
02344 
02345    //Successful processing
02346    return NO_ERROR;
02347 }
02348 
02349 #endif
02350