Пример #1
0
error_t udpInvokeRxCallback(NetInterface *interface, const IpPseudoHeader *pseudoHeader,
   const UdpHeader *header, const ChunkedBuffer *buffer, size_t offset)
{
   uint_t i;
   void *params;
   UdpRxCallbackDesc *entry;

   //This flag tells whether a matching entry has been found
   bool_t found = FALSE;

   //Acquire exclusive access to the callback table
   osMutexAcquire(udpCallbackMutex);

   //Loop through the table
   for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++)
   {
      //Point to the current entry
      entry = &udpCallbackTable[i];

      //Check whether the entry is currently in used
      if(entry->callback != NULL)
      {
         //Bound to a particular interface?
         if(entry->interface == NULL || entry->interface == interface)
         {
            //Does the specified port number match the current entry?
            if(entry->port == ntohs(header->destPort))
            {
               //Retrieve callback parameters
               params = entry->params;

               //Release mutex to prevent any deadlock
               if(params == NULL)
                  osMutexRelease(udpCallbackMutex);

               //Invoke user callback function
               entry->callback(interface, pseudoHeader,
                  header, buffer, offset, params);

               //Acquire mutex
               if(params == NULL)
                  osMutexAcquire(udpCallbackMutex);

               //A matching entry was found
               found = TRUE;
            }
         }
      }
   }

   //Release exclusive access to the callback table
   osMutexRelease(udpCallbackMutex);

   //Return status code
   return found ? NO_ERROR : ERROR_PORT_UNREACHABLE;
}
Пример #2
0
error_t udpReceiveDatagram(Socket *socket, IpAddr *srcIpAddr, uint16_t *srcPort,
   IpAddr *destIpAddr, void *data, size_t size, size_t *received, uint_t flags)
{
   SocketQueueItem *queueItem;

   //The receive queue is empty?
   if(!socket->receiveQueue)
   {
      //Set the events the application is interested in
      socket->eventMask = SOCKET_EVENT_RX_READY;
      //Reset the event object
      osEventReset(socket->event);
      //Leave critical section
      osMutexRelease(socketMutex);
      //Wait until an event is triggered
      osEventWait(socket->event, socket->timeout);
      //Enter critical section
      osMutexAcquire(socketMutex);
   }

   //Check whether the read operation timed out
   if(!socket->receiveQueue)
   {
      //No data can be read
      *received = 0;
      //Report a timeout error
      return ERROR_TIMEOUT;
   }

   //Point to the first item in the receive queue
   queueItem = socket->receiveQueue;
   //Copy data to user buffer
   *received = chunkedBufferRead(data, queueItem->buffer, queueItem->offset, size);

   //Save the source IP address
   if(srcIpAddr)
      *srcIpAddr = queueItem->srcIpAddr;
   //Save the source port number
   if(srcPort)
      *srcPort = queueItem->srcPort;
   //Save the destination IP address
   if(destIpAddr)
      *destIpAddr = queueItem->destIpAddr;

   //If the SOCKET_FLAG_PEEK flag is set, the data is copied
   //into the buffer but is not removed from the input queue
   if(!(flags & SOCKET_FLAG_PEEK))
   {
      //Remove the item from the receive queue
      socket->receiveQueue = queueItem->next;
      //Deallocate memory buffer
      chunkedBufferFree(queueItem->buffer);
   }

   //Update the state of events
   udpUpdateEvents(socket);

   //Successful read operation
   return NO_ERROR;
}
Пример #3
0
void memPoolFree(void *p)
{
//Use fixed-size blocks allocation?
#if (MEM_POOL_SUPPORT == ENABLED)
   uint_t i;

   //Acquire exclusive access to the memory pool
   osMutexAcquire(memPoolMutex);

   //Loop through allocation table
   for(i = 0; i < MEM_POOL_BUFFER_COUNT; i++)
   {
      if(memPool[i] == p)
      {
         //Mark the current block as free
         memPoolAllocTable[i] = FALSE;
         //Exit immediately
         break;
      }
   }

   //Release exclusive access to the memory pool
   osMutexRelease(memPoolMutex);
#else
   //Release memory block
   osMemFree(p);
#endif
}
Пример #4
0
void tcpIpStackRxTask(void *param)
{
   //Point to the structure describing the network interface
   NetInterface *interface = (NetInterface *) param;

   //Main loop
   while(1)
   {
      //Receive notifications when a Ethernet frame has been received,
      //or the link status has changed
      osEventWait(interface->nicRxEvent, INFINITE_DELAY);

      //Get exclusive access to the device
      osMutexAcquire(interface->nicDriverMutex);
      //Disable Ethernet controller interrupts
      interface->nicDriver->disableIrq(interface);

      //Handle incoming packets and link state changes
      interface->nicDriver->rxEventHandler(interface);

      //Re-enable Ethernet controller interrupts
      interface->nicDriver->enableIrq(interface);
      //Release exclusive access to the device
      osMutexRelease(interface->nicDriverMutex);
   }
}
Пример #5
0
void ipv6FragTick(NetInterface *interface)
{
   error_t error;
   uint_t i;
   time_t time;
   Ipv6HoleDesc *hole;

   //Acquire exclusive access to the reassembly queue
   osMutexAcquire(interface->ipv6FragQueueMutex);

   //Get current time
   time = osGetTickCount();

   //Loop through the reassembly queue
   for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++)
   {
      //Point to the current entry in the reassembly queue
      Ipv6FragDesc *frag = &interface->ipv6FragQueue[i];

      //Make sure the entry is currently in use
      if(frag->buffer.chunkCount > 0)
      {
         //If the timer runs out, the partially-reassembled datagram must be
         //discarded and ICMPv6 Time Exceeded message sent to the source host
         if((time - frag->timestamp) >= IPV6_FRAG_TIME_TO_LIVE)
         {
            //Debug message
            TRACE_INFO("IPv6 fragment reassembly timeout...\r\n");
            //Dump IP header contents for debugging purpose
            ipv6DumpHeader(frag->buffer.chunk[0].address);

            //Point to the first hole descriptor
            hole = ipv6FindHole(frag, frag->firstHole);

            //Make sure the fragment zero has been received
            //before sending an ICMPv6 message
            if(hole != NULL && hole->first > 0)
            {
               //Fix the size of the reconstructed datagram
               error = chunkedBufferSetLength((ChunkedBuffer *) &frag->buffer,
                  frag->unfragPartLength + hole->first);

               //Check status code
               if(!error)
               {
                  //Send an ICMPv6 Time Exceeded message
                  icmpv6SendErrorMessage(interface, ICMPV6_TYPE_TIME_EXCEEDED,
                     ICMPV6_CODE_REASSEMBLY_TIME_EXCEEDED, 0, (ChunkedBuffer *) &frag->buffer);
               }
            }

            //Drop the partially reconstructed datagram
            chunkedBufferSetLength((ChunkedBuffer *) &frag->buffer, 0);
         }
      }
   }

   //Release exclusive access to the reassembly queue
   osMutexRelease(interface->ipv6FragQueueMutex);
}
Пример #6
0
void mldProcessListenerReport(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
   const ChunkedBuffer *buffer, size_t offset, uint8_t hopLimit)
{
   uint_t i;
   size_t length;
   MldMessage *message;
   Ipv6FilterEntry *entry;

   //Retrieve the length of the MLD message
   length = chunkedBufferGetLength(buffer) - offset;

   //The message must be at least 24 octets long
   if(length < sizeof(MldMessage))
      return;

   //Point to the beginning of the MLD message
   message = chunkedBufferAt(buffer, offset);
   //Sanity check
   if(!message) return;

   //Debug message
   TRACE_INFO("MLD message received (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump message contents for debugging purpose
   mldDumpMessage(message);

   //Make sure the source address of the message is a valid link-local address
   if(!ipv6IsLinkLocalUnicastAddr(&pseudoHeader->srcAddr))
      return;
   //Check the Hop Limit field
   if(hopLimit != MLD_HOP_LIMIT)
      return;

   //Acquire exclusive access to the IPv6 filter table
   osMutexAcquire(interface->ipv6FilterMutex);

   //Loop through filter table entries
   for(i = 0; i < interface->ipv6FilterSize; i++)
   {
      //Point to the current entry
      entry = &interface->ipv6Filter[i];

      //Report messages are ignored for multicast addresses
      //in the Non-Listener or Idle Listener state
      if(entry->state == MLD_STATE_DELAYING_LISTENER)
      {
         //The Multicast Listener Report message matches the current entry?
         if(ipv6CompAddr(&message->multicastAddr, &entry->addr))
         {
            //Clear flag
            entry->flag = FALSE;
            //Switch to the Idle Listener state
            entry->state = MLD_STATE_IDLE_LISTENER;
         }
      }
   }

   //Release exclusive access to the IPv6 filter table
   osMutexRelease(interface->ipv6FilterMutex);
}
Пример #7
0
void *memPoolAlloc(size_t size)
{
#if (MEM_POOL_SUPPORT == ENABLED)
   uint_t i;
#endif

   //Pointer to the allocated memory block
   void *p = NULL;

   //Debug message
   TRACE_DEBUG("Allocating %" PRIuSIZE " bytes...\r\n", size);

//Use fixed-size blocks allocation?
#if (MEM_POOL_SUPPORT == ENABLED)
   //Acquire exclusive access to the memory pool
   osMutexAcquire(memPoolMutex);

   //Enforce block size
   if(size <= MEM_POOL_BUFFER_SIZE)
   {
      //Loop through allocation table
      for(i = 0; i < MEM_POOL_BUFFER_COUNT; i++)
      {
         //Check whether the current block is free
         if(!memPoolAllocTable[i])
         {
            //Mark the current entry as used
            memPoolAllocTable[i] = TRUE;
            //Point to the corresponding memory block
            p = memPool[i];

            //Update statistics
            memPoolCurrentUsage++;
            //Maximum number of buffers that have been allocated so far
            memPoolMaxUsage = max(memPoolCurrentUsage, memPoolMaxUsage);

            //Exit immediately
            break;
         }
      }
   }

   //Release exclusive access to the memory pool
   osMutexRelease(memPoolMutex);
#else
   //Allocate a memory block
   p = osMemAlloc(size);
#endif

   //Failed to allocate memory?
   if(!p)
   {
      //Debug message
      TRACE_WARNING("Memory allocation failed!\r\n");
   }

   //Return a pointer to the allocated memory block
   return p;
}
Пример #8
0
void eventOS_scheduler_mutex_wait(void)
{
    osMutexAcquire(event_mutex_id, osWaitForever);
    if (0 == owner_count) {
        event_mutex_owner_id = osThreadGetId();
    }
    owner_count++;
}
Пример #9
0
void mldLinkChangeEvent(NetInterface *interface)
{
   uint_t i;
   systime_t time;
   Ipv6FilterEntry *entry;

   //Get current time
   time = osGetTickCount();

   //Acquire exclusive access to the IPv6 filter table
   osMutexAcquire(interface->ipv6FilterMutex);

   //Link up event?
   if(interface->linkState)
   {
      //Loop through filter table entries
      for(i = 0; i < interface->ipv6FilterSize; i++)
      {
         //Point to the current entry
         entry = &interface->ipv6Filter[i];

         //The link-scope all-nodes address (FF02::1) is handled as a special
         //case. The host starts in Idle Listener state for that address on
         //every interface and never transitions to another state
         if(ipv6CompAddr(&entry->addr, &IPV6_LINK_LOCAL_ALL_NODES_ADDR))
            continue;

         //Send an unsolicited Multicast Listener Report message for that group
         mldSendListenerReport(interface, &entry->addr);

         //Set flag
         entry->flag = TRUE;
         //Start timer
         entry->timer = time + MLD_UNSOLICITED_REPORT_INTERVAL;
         //Enter the Delaying Listener state
         entry->state = MLD_STATE_DELAYING_LISTENER;
      }
   }
   //Link down event?
   else
   {
      //Loop through filter table entries
      for(i = 0; i < interface->ipv6FilterSize; i++)
      {
         //Point to the current entry
         entry = &interface->ipv6Filter[i];

         //Clear flag
         entry->flag = FALSE;
         //Enter the Idle Listener state
         entry->state = MLD_STATE_IDLE_LISTENER;
      }
   }

   //Release exclusive access to the IPv6 filter table
   osMutexRelease(interface->ipv6FilterMutex);
}
Пример #10
0
error_t ipv4LeaveMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr)
{
    uint_t i;
    uint_t j;
    MacAddr macAddr;

    //Ensure the specified IPv4 address is a multicast address
    if(!ipv4IsMulticastAddr(groupAddr))
        return ERROR_INVALID_ADDRESS;

    //Acquire exclusive access to the IPv4 filter table
    osMutexAcquire(interface->ipv4FilterMutex);

    //Loop through filter table entries
    for(i = 0; i < interface->ipv4FilterSize; i++)
    {
        //Specified IPv4 address found?
        if(interface->ipv4Filter[i].addr == groupAddr)
        {
            //Decrement the reference count
            interface->ipv4Filter[i].refCount--;

            //Remove the entry if the reference count drops to zero
            if(interface->ipv4Filter[i].refCount < 1)
            {
#if (IGMP_SUPPORT == ENABLED)
                //Report group membership termination
                igmpLeaveGroup(interface, &interface->ipv4Filter[i]);
#endif
                //Map the multicast IPv4 address to a MAC-layer address
                ipv4MapMulticastAddrToMac(groupAddr, &macAddr);
                //Drop the corresponding address from the MAC filter table
                ethDropMulticastAddr(interface, &macAddr);

                //Adjust the size of the IPv4 filter table
                interface->ipv4FilterSize--;

                //Remove the corresponding entry
                for(j = i; j < interface->ipv4FilterSize; j++)
                    interface->ipv4Filter[j] = interface->ipv4Filter[j + 1];
            }

            //Release exclusive access to the IPv4 filter table
            osMutexRelease(interface->ipv4FilterMutex);
            //No error to report
            return NO_ERROR;
        }
    }

    //Release exclusive access to the IPv4 filter table
    osMutexRelease(interface->ipv4FilterMutex);
    //The specified IPv4 address does not exist
    return ERROR_FAILURE;
}
Пример #11
0
TcpState tcpGetState(Socket *socket)
{
   TcpState state;

   //Enter critical section
   osMutexAcquire(socketMutex);
   //Get TCP FSM current state
   state = socket->state;
   //Leave critical section
   osMutexRelease(socketMutex);

   //Return current state
   return state;
}
Пример #12
0
void ipv6FlushFragQueue(NetInterface *interface)
{
   uint_t i;

   //Acquire exclusive access to the reassembly queue
   osMutexAcquire(interface->ipv6FragQueueMutex);

   //Loop through the reassembly queue
   for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++)
   {
      //Drop any partially reconstructed datagram
      chunkedBufferSetLength((ChunkedBuffer *) &interface->ipv6FragQueue[i].buffer, 0);
   }

   //Release exclusive access to the reassembly queue
   osMutexRelease(interface->ipv6FragQueueMutex);
}
Пример #13
0
error_t icecastClientReadMetadata(IcecastClientContext *context,
   char_t *metadata, size_t size, size_t *length)
{
   //Ensure the parameters are valid
   if(!context || !metadata)
      return ERROR_INVALID_PARAMETER;

   //Enter critical section
   osMutexAcquire(context->mutex);

   //Limit the number of data to read
   *length = min(size, context->metadataLength);
   //Save metadata information
   memcpy(metadata, context->metadata, *length);

   //Leave critical section
   osMutexRelease(context->mutex);

   //Successful read operation
   return NO_ERROR;
}
Пример #14
0
void mldTick(NetInterface *interface)
{
   uint_t i;
   systime_t time;
   Ipv6FilterEntry *entry;

   //Get current time
   time = osGetTickCount();

   //Acquire exclusive access to the IPv6 filter table
   osMutexAcquire(interface->ipv6FilterMutex);

   //Loop through filter table entries
   for(i = 0; i < interface->ipv6FilterSize; i++)
   {
      //Point to the current entry
      entry = &interface->ipv6Filter[i];

      //Delaying Listener state?
      if(entry->state == MLD_STATE_DELAYING_LISTENER)
      {
         //Timer expired?
         if(timeCompare(time, entry->timer) >= 0)
         {
            //Send a Multicast Listener Report message
            mldSendListenerReport(interface, &entry->addr);

            //Set flag
            entry->flag = TRUE;
            //Switch to the Idle Listener state
            entry->state = MLD_STATE_IDLE_LISTENER;
         }
      }
   }

   //Release exclusive access to the IPv6 filter table
   osMutexRelease(interface->ipv6FilterMutex);
}
Пример #15
0
error_t udpAttachRxCallback(NetInterface *interface,
   uint16_t port, UdpRxCallback callback, void *params)
{
   uint_t i;
   UdpRxCallbackDesc *entry;

   //Acquire exclusive access to the callback table
   osMutexAcquire(udpCallbackMutex);

   //Loop through the table
   for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++)
   {
      //Point to the current entry
      entry = &udpCallbackTable[i];

      //Check whether the entry is currently in used
      if(entry->callback == NULL)
      {
         //Create a new entry
         entry->interface = interface;
         entry->port = port;
         entry->callback = callback;
         entry->params = params;
         //We are done
         break;
      }
   }

   //Release exclusive access to the callback table
   osMutexRelease(udpCallbackMutex);

   //Failed to attach the specified user callback?
   if(i >= UDP_CALLBACK_TABLE_SIZE)
      return ERROR_OUT_OF_RESOURCES;

   //Successful processing
   return NO_ERROR;
}
Пример #16
0
void arpFlushCache(NetInterface *interface)
{
   uint_t i;
   ArpCacheEntry *entry;

   //Acquire exclusive access to ARP cache
   osMutexAcquire(interface->arpCacheMutex);

   //Loop through ARP cache entries
   for(i = 0; i < ARP_CACHE_SIZE; i++)
   {
      //Point to the current entry
      entry = &interface->arpCache[i];

      //Drop packets that are waiting for address resolution
      arpFlushQueuedPackets(interface, entry);
      //Release ARP entry
      entry->state = ARP_STATE_NONE;
   }

   //Release exclusive access to ARP cache
   osMutexRelease(interface->arpCacheMutex);
}
Пример #17
0
error_t udpDetachRxCallback(NetInterface *interface, uint16_t port)
{
   uint_t i;
   UdpRxCallbackDesc *entry;

   //This flag tells whether an entry has been found
   bool_t found = FALSE;

   //Acquire exclusive access to the callback table
   osMutexAcquire(udpCallbackMutex);

   //Loop through the table
   for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++)
   {
      //Point to the current entry
      entry = &udpCallbackTable[i];

      //Check whether the entry is currently in used
      if(entry->callback != NULL)
      {
         //Does the specified port number match the current entry?
         if(entry->port == port && entry->interface == interface)
         {
            //Unregister user callback
            entry->callback = NULL;
            //A matching entry was found
            found = TRUE;
         }
      }
   }

   //Release exclusive access to the callback table
   osMutexRelease(udpCallbackMutex);

   //Check whether the specified callback has been successfully unregistered
   return found ? NO_ERROR : ERROR_FAILURE;
}
Пример #18
0
void arpProcessReply(NetInterface *interface, ArpPacket *arpReply)
{
   ArpCacheEntry *entry;

   //Debug message
   TRACE_INFO("ARP Reply received...\r\n");

   //Check sender protocol address
   if(arpReply->spa == IPV4_UNSPECIFIED_ADDR)
      return;
   if(ipv4IsMulticastAddr(arpReply->spa))
      return;
   if(ipv4IsBroadcastAddr(interface, arpReply->spa))
      return;

   //Check sender hardware address
   if(macCompAddr(&arpReply->sha, &MAC_UNSPECIFIED_ADDR))
      return;
   if(macCompAddr(&arpReply->sha, &MAC_BROADCAST_ADDR))
      return;

   //Acquire exclusive access to ARP cache
   osMutexAcquire(interface->arpCacheMutex);

   //Search the ARP cache for the specified IPv4 address
   entry = arpFindEntry(interface, arpReply->spa);

   //A matching ARP entry has been found
   if(entry)
   {
      //Check current state
      if(entry->state == ARP_STATE_INCOMPLETE)
      {
         //Record the corresponding MAC address
         entry->macAddr = arpReply->sha;

         //Send all the packets that are pending for transmission
         arpSendQueuedPackets(interface, entry);

         //Save current time
         entry->timestamp = osGetTickCount();
         //The validity of the ARP entry is limited in time
         entry->timeout = ARP_REACHABLE_TIME;
         //Switch to the REACHABLE state
         entry->state = ARP_STATE_REACHABLE;
      }
      else if(entry->state == ARP_STATE_REACHABLE)
      {
         //Different link-layer address than cached?
         if(!macCompAddr(&arpReply->sha, &entry->macAddr))
         {
            //Enter STALE state
            entry->state = ARP_STATE_STALE;
         }
      }
      else if(entry->state == ARP_STATE_PROBE)
      {
         //Record IPv4/MAC address pair
         entry->ipAddr = arpReply->spa;
         entry->macAddr = arpReply->sha;

         //Save current time
         entry->timestamp = osGetTickCount();
         //The validity of the ARP entry is limited in time
         entry->timeout = ARP_REACHABLE_TIME;
         //Switch to the REACHABLE state
         entry->state = ARP_STATE_REACHABLE;
      }
   }

   //Release exclusive access to ARP cache
   osMutexRelease(interface->arpCacheMutex);
}
Пример #19
0
void arpTick(NetInterface *interface)
{
   uint_t i;
   time_t time;
   ArpCacheEntry *entry;

   //Get current time
   time = osGetTickCount();

   //Acquire exclusive access to ARP cache
   osMutexAcquire(interface->arpCacheMutex);

   //Go through ARP cache
   for(i = 0; i < ARP_CACHE_SIZE; i++)
   {
      //Point to the current entry
      entry = &interface->arpCache[i];

      //INCOMPLETE state?
      if(entry->state == ARP_STATE_INCOMPLETE)
      {
         //The request timed out?
         if((time - entry->timestamp) >= entry->timeout)
         {
            //Increment retransmission counter
            entry->retransmitCount++;

            //Check whether the maximum number of retransmissions has been exceeded
            if(entry->retransmitCount < ARP_MAX_REQUESTS)
            {
               //Retransmit ARP request
               arpSendRequest(interface, interface->ipv4Config.addr,
                  entry->ipAddr, &MAC_BROADCAST_ADDR);

               //Save the time at which the packet was sent
               entry->timestamp = time;
               //Set timeout value
               entry->timeout = ARP_REQUEST_TIMEOUT;
            }
            else
            {
               //Drop packets that are waiting for address resolution
               arpFlushQueuedPackets(interface, entry);
               //The entry should be deleted since address resolution has failed
               entry->state = ARP_STATE_NONE;
            }
         }
      }
      //REACHABLE state?
      else if(entry->state == ARP_STATE_REACHABLE)
      {
         //Periodically time out ARP cache entries
         if((time - entry->timestamp) >= entry->timeout)
         {
            //Save current time
            entry->timestamp = osGetTickCount();
            //Enter STALE state
            entry->state = ARP_STATE_STALE;
         }
      }
      //DELAY state?
      else if(entry->state == ARP_STATE_DELAY)
      {
         //Wait for the specified delay before sending the first probe
         if((time - entry->timestamp) >= entry->timeout)
         {
            //Send a point-to-point ARP request to the host
            arpSendRequest(interface, interface->ipv4Config.addr,
               entry->ipAddr, &entry->macAddr);

            //Save the time at which the packet was sent
            entry->timestamp = time;
            //Set timeout value
            entry->timeout = ARP_PROBE_TIMEOUT;
            //Switch to the PROBE state
            entry->state = ARP_STATE_PROBE;
         }
      }
      //PROBE state?
      else if(entry->state == ARP_STATE_PROBE)
      {
         //The request timed out?
         if((time - entry->timestamp) >= entry->timeout)
         {
            //Increment retransmission counter
            entry->retransmitCount++;

            //Check whether the maximum number of retransmissions has been exceeded
            if(entry->retransmitCount < ARP_MAX_PROBES)
            {
               //Send a point-to-point ARP request to the host
               arpSendRequest(interface, interface->ipv4Config.addr,
                  entry->ipAddr, &entry->macAddr);

               //Save the time at which the packet was sent
               entry->timestamp = time;
               //Set timeout value
               entry->timeout = ARP_PROBE_TIMEOUT;
            }
            else
            {
               //The entry should be deleted since the host is not reachable anymore
               entry->state = ARP_STATE_NONE;
            }
         }
      }
   }

   //Release exclusive access to ARP cache
   osMutexRelease(interface->arpCacheMutex);
}
Пример #20
0
error_t arpEnqueuePacket(NetInterface *interface,
   Ipv4Addr ipAddr, ChunkedBuffer *buffer, size_t offset)
{
   error_t error;
   uint_t i;
   size_t length;
   ArpCacheEntry *entry;

   //Retrieve the length of the multi-part buffer
   length = chunkedBufferGetLength(buffer);

   //Acquire exclusive access to ARP cache
   osMutexAcquire(interface->arpCacheMutex);

   //Search the ARP cache for the specified Ipv4 address
   entry = arpFindEntry(interface, ipAddr);

   //No matching entry in ARP cache?
   if(!entry)
   {
      //Release exclusive access to ARP cache
      osMutexRelease(interface->arpCacheMutex);
      //Report an error to the calling function
      return ERROR_FAILURE;
   }

   //Check current state
   if(entry->state == ARP_STATE_INCOMPLETE)
   {
      //Check whether the packet queue is full
      if(entry->queueSize >= ARP_MAX_PENDING_PACKETS)
      {
         //When the queue overflows, the new arrival should replace the oldest entry
         chunkedBufferFree(entry->queue[0].buffer);

         //Make room for the new packet
         for(i = 1; i < ARP_MAX_PENDING_PACKETS; i++)
            entry->queue[i - 1] = entry->queue[i];

         //Adjust the number of pending packets
         entry->queueSize--;
      }

      //Index of the entry to be filled in
      i = entry->queueSize;
      //Allocate a memory buffer to store the packet
      entry->queue[i].buffer = chunkedBufferAlloc(length);

      //Failed to allocate memory?
      if(!entry->queue[i].buffer)
      {
         //Release exclusive access to ARP cache
         osMutexRelease(interface->arpCacheMutex);
         //Report an error to the calling function
         return ERROR_OUT_OF_MEMORY;
      }

      //Copy packet contents
      chunkedBufferCopy(entry->queue[i].buffer, 0, buffer, 0, length);
      //Offset to the first byte of the IPv4 header
      entry->queue[i].offset = offset;

      //Increment the number of queued packets
      entry->queueSize++;
      //The packet was successfully enqueued
      error = NO_ERROR;
   }
   else
   {
      //Send immediately the packet since the address is already resolved
      error = ethSendFrame(interface, &entry->macAddr, buffer, offset, ETH_TYPE_IPV4);
   }

   //Release exclusive access to ARP cache
   osMutexRelease(interface->arpCacheMutex);
   //Return status code
   return error;
}
Пример #21
0
error_t arpResolve(NetInterface *interface, Ipv4Addr ipAddr, MacAddr *macAddr)
{
   ArpCacheEntry *entry;

   //Acquire exclusive access to ARP cache
   osMutexAcquire(interface->arpCacheMutex);

   //Search the ARP cache for the specified IPv4 address
   entry = arpFindEntry(interface, ipAddr);

   //Check whether a matching entry has been found
   if(entry)
   {
      //Check the state of the ARP entry
      if(entry->state == ARP_STATE_INCOMPLETE)
      {
         //Release exclusive access to ARP cache
         osMutexRelease(interface->arpCacheMutex);
         //The address resolution is already in progress
         return ERROR_IN_PROGRESS;
      }
      else if(entry->state == ARP_STATE_STALE)
      {
         //Copy the MAC address associated with the specified IPv4 address
         *macAddr = entry->macAddr;

         //Start delay timer
         entry->timestamp = osGetTickCount();
         //Delay before sending the first probe
         entry->timeout = ARP_DELAY_FIRST_PROBE_TIME;
         //Switch to the DELAY state
         entry->state = ARP_STATE_DELAY;

         //Release exclusive access to ARP cache
         osMutexRelease(interface->arpCacheMutex);
         //Successful address resolution
         return NO_ERROR;
      }
      else
      {
         //Copy the MAC address associated with the specified IPv4 address
         *macAddr = entry->macAddr;

         //Release exclusive access to ARP cache
         osMutexRelease(interface->arpCacheMutex);
         //Successful address resolution
         return NO_ERROR;
      }
   }

   //If no entry exists, then create a new one
   entry = arpCreateEntry(interface);

   //Any error to report?
   if(!entry)
   {
      //Release exclusive access to ARP cache
      osMutexRelease(interface->arpCacheMutex);
      //Report an error to the calling function
      return ERROR_OUT_OF_RESOURCES;
   }

   //Record the IPv4 address whose MAC address is unknown
   entry->ipAddr = ipAddr;
   entry->macAddr = MAC_UNSPECIFIED_ADDR;

   //Reset retransmission counter
   entry->retransmitCount = 0;
   //No packet are pending in the transmit queue
   entry->queueSize = 0;

   //Send an ARP request
   arpSendRequest(interface, interface->ipv4Config.addr,
      entry->ipAddr, &MAC_BROADCAST_ADDR);

   //Save the time at which the packet was sent
   entry->timestamp = osGetTickCount();
   //Set timeout value
   entry->timeout = ARP_REQUEST_TIMEOUT;
   //Enter INCOMPLETE state
   entry->state = ARP_STATE_INCOMPLETE;

   //Release exclusive access to ARP cache
   osMutexRelease(interface->arpCacheMutex);

   //The address resolution is in progress
   return ERROR_IN_PROGRESS;
}
Пример #22
0
void mldProcessListenerQuery(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
   const ChunkedBuffer *buffer, size_t offset, uint8_t hopLimit)
{
   uint_t i;
   size_t length;
   systime_t time;
   systime_t maxRespDelay;
   MldMessage *message;
   Ipv6FilterEntry *entry;

   //Retrieve the length of the MLD message
   length = chunkedBufferGetLength(buffer) - offset;

   //The message must be at least 24 octets long
   if(length < sizeof(MldMessage))
      return;

   //Point to the beginning of the MLD message
   message = chunkedBufferAt(buffer, offset);
   //Sanity check
   if(!message) return;

   //Debug message
   TRACE_INFO("MLD message received (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump message contents for debugging purpose
   mldDumpMessage(message);

   //Make sure the source address of the message is a valid link-local address
   if(!ipv6IsLinkLocalUnicastAddr(&pseudoHeader->srcAddr))
      return;
   //Check the Hop Limit field
   if(hopLimit != MLD_HOP_LIMIT)
      return;

   //Get current time
   time = osGetTickCount();

   //The Max Resp Delay field specifies the maximum time allowed
   //before sending a responding report
   maxRespDelay = message->maxRespDelay * 10;

   //Acquire exclusive access to the IPv6 filter table
   osMutexAcquire(interface->ipv6FilterMutex);

   //Loop through filter table entries
   for(i = 0; i < interface->ipv6FilterSize; i++)
   {
      //Point to the current entry
      entry = &interface->ipv6Filter[i];

      //The link-scope all-nodes address (FF02::1) is handled as a special
      //case. The host starts in Idle Listener state for that address on
      //every interface and never transitions to another state
      if(ipv6CompAddr(&entry->addr, &IPV6_LINK_LOCAL_ALL_NODES_ADDR))
         continue;

      //A General Query is used to learn which multicast addresses have listeners
      //on an attached link. A Multicast-Address-Specific Query is used to learn
      //if a particular multicast address has any listeners on an attached link
      if(ipv6CompAddr(&message->multicastAddr, &IPV6_UNSPECIFIED_ADDR) ||
         ipv6CompAddr(&message->multicastAddr, &entry->addr))
      {
         //Delaying Listener state?
         if(entry->state == MLD_STATE_DELAYING_LISTENER)
         {
            //The timer has not yet expired?
            if(timeCompare(time, entry->timer) < 0)
            {
               //If a timer for the address is already running, it is reset to
               //the new random value only if the requested Max Response Delay
               //is less than the remaining value of the running timer
               if(maxRespDelay < (entry->timer - time))
               {
                  //Restart delay timer
                  entry->timer = time + mldRand(maxRespDelay);
               }
            }
         }
         //Idle Listener state?
         else if(entry->state == MLD_STATE_IDLE_LISTENER)
         {
            //Switch to the Delaying Listener state
            entry->state = MLD_STATE_DELAYING_LISTENER;
            //Delay the response by a random amount of time
            entry->timer = time + mldRand(maxRespDelay);
         }
      }
   }

   //Release exclusive access to the IPv6 filter table
   osMutexRelease(interface->ipv6FilterMutex);
}
Пример #23
0
void __rtos_env_lock(struct _reent *_r)
{
    osMutexAcquire(env_mutex_id, osWaitForever);
}
Пример #24
0
error_t dnsResolve(NetInterface *interface,
   const char_t *name, HostType type, IpAddr *ipAddr)
{
   error_t error;
   systime_t delay;
   DnsCacheEntry *entry;

   //Debug message
   TRACE_INFO("Resolving host name %s (DNS resolver)...\r\n", name);

   //Acquire exclusive access to the DNS cache
   osMutexAcquire(dnsCacheMutex);

   //Search the DNS cache for the specified host name
   entry = dnsFindEntry(interface, name, type, HOST_NAME_RESOLVER_DNS);

   //Check whether a matching entry has been found
   if(entry)
   {
      //Host name already resolved?
      if(entry->state == DNS_STATE_RESOLVED ||
         entry->state == DNS_STATE_PERMANENT)
      {
         //Return the corresponding IP address
         *ipAddr = entry->ipAddr;
         //Successful host name resolution
         error = NO_ERROR;
      }
      else
      {
         //Host name resolution is in progress...
         error = ERROR_IN_PROGRESS;
      }
   }
   else
   {
      //If no entry exists, then create a new one
      entry = dnsCreateEntry();

      //Record the host name whose IP address is unknown
      strcpy(entry->name, name);

      //Initialize DNS cache entry
      entry->type = type;
      entry->protocol = HOST_NAME_RESOLVER_DNS;
      entry->interface = interface;
      //Select primary DNS server
      entry->dnsServerNum = 0;
      //Get an ephemeral port number
      entry->port = socketGetEphemeralPort();

      //An identifier is used by the DNS client to match replies
      //with corresponding requests
      entry->id = tcpIpStackGetRand();

      //Callback function to be called when a DNS response is received
      error = udpAttachRxCallback(interface, entry->port, dnsProcessResponse, NULL);

      //Check status code
      if(!error)
      {
         //Initialize retransmission counter
         entry->retransmitCount = DNS_CLIENT_MAX_RETRIES;
         //Send DNS query
         error = dnsSendQuery(entry);

         //DNS message successfully sent?
         if(!error)
         {
            //Save the time at which the query message was sent
            entry->timestamp = osGetTickCount();
            //Set timeout value
            entry->timeout = DNS_CLIENT_INIT_TIMEOUT;
            entry->maxTimeout = DNS_CLIENT_MAX_TIMEOUT;
            //Decrement retransmission counter
            entry->retransmitCount--;

            //Switch state
            entry->state = DNS_STATE_IN_PROGRESS;
            //Host name resolution is in progress
            error = ERROR_IN_PROGRESS;
         }
         else
         {
            //Unregister callback function
            udpDetachRxCallback(interface, entry->port);
         }
      }
   }

   //Release exclusive access to the DNS cache
   osMutexRelease(dnsCacheMutex);

   //Set default polling interval
   delay = DNS_CACHE_INIT_POLLING_INTERVAL;

   //Wait the host name resolution to complete
   while(error == ERROR_IN_PROGRESS)
   {
      //Wait until the next polling period
      osDelay(delay);

      //Acquire exclusive access to the DNS cache
      osMutexAcquire(dnsCacheMutex);

      //Search the DNS cache for the specified host name
      entry = dnsFindEntry(interface, name, type, HOST_NAME_RESOLVER_DNS);

      //Check whether a matching entry has been found
      if(entry)
      {
         //Host name successfully resolved?
         if(entry->state == DNS_STATE_RESOLVED)
         {
            //Return the corresponding IP address
            *ipAddr = entry->ipAddr;
            //Successful host name resolution
            error = NO_ERROR;
         }
      }
      else
      {
         //Host name resolution failed
         error = ERROR_FAILURE;
      }

      //Release exclusive access to the DNS cache
      osMutexRelease(dnsCacheMutex);

      //Backoff support for less aggressive polling
      delay = min(delay * 2, DNS_CACHE_MAX_POLLING_INTERVAL);
   }

   //Check status code
   if(error)
   {
      //Failed to resolve host name
      TRACE_INFO("Host name resolution failed!\r\n");
   }
   else
   {
      //Successful host name resolution
      TRACE_INFO("Host name resolved to %s...\r\n", ipAddrToString(ipAddr, NULL));
   }

   //Return status code
   return error;
}
Пример #25
0
void __iar_file_Mtxlock(__iar_Rmtx *mutex) /* Lock a file lock */
{
    osMutexAcquire(*(osMutexId_t *)*mutex, osWaitForever);
}
Пример #26
0
void __rtos_malloc_lock(struct _reent *_r)
{
    osMutexAcquire(malloc_mutex_id, osWaitForever);
}
Пример #27
0
void __iar_system_Mtxlock(__iar_Rmtx *mutex) /* Lock a system lock */
{
    osMutexAcquire(*(osMutexId_t *)*mutex, osWaitForever);
}
Пример #28
0
error_t udpProcessDatagram(NetInterface *interface,
   IpPseudoHeader *pseudoHeader, const ChunkedBuffer *buffer, size_t offset)
{
   error_t error;
   uint_t i;
   size_t length;
   UdpHeader *header;
   Socket *socket;
   SocketQueueItem *queueItem;
   ChunkedBuffer *p;

   //Retrieve the length of the UDP datagram
   length = chunkedBufferGetLength(buffer) - offset;

   //Ensure the UDP header is valid
   if(length < sizeof(UdpHeader))
   {
      //Debug message
      TRACE_WARNING("UDP datagram length is invalid!\r\n");
      //Report an error
      return ERROR_INVALID_HEADER;
   }

   //Point to the UDP header
   header = chunkedBufferAt(buffer, offset);
   //Sanity check
   if(!header) return ERROR_FAILURE;

   //Debug message
   TRACE_INFO("UDP datagram received (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump UDP header contents for debugging purpose
   udpDumpHeader(header);

   //When UDP runs over IPv6, the checksum is mandatory
   if(header->checksum || pseudoHeader->length == sizeof(Ipv6PseudoHeader))
   {
      //Verify UDP checksum
      if(ipCalcUpperLayerChecksumEx(pseudoHeader->data,
         pseudoHeader->length, buffer, offset, length) != 0xFFFF)
      {
         //Debug message
         TRACE_WARNING("Wrong UDP header checksum!\r\n");
         //Report an error
         return ERROR_WRONG_CHECKSUM;
      }
   }

   //Enter critical section
   osMutexAcquire(socketMutex);

   //Loop through opened sockets
   for(i = 0; i < SOCKET_MAX_COUNT; i++)
   {
      //Point to the current socket
      socket = socketTable + i;

      //UDP socket found?
      if(socket->type != SOCKET_TYPE_DGRAM)
         continue;
      //Check whether the socket is bound to a particular interface
      if(socket->interface && socket->interface != interface)
         continue;
      //Check destination port number
      if(socket->localPort != ntohs(header->destPort))
         continue;
      //Source port number filtering
      if(socket->remotePort && socket->remotePort != ntohs(header->srcPort))
         continue;

#if (IPV4_SUPPORT == ENABLED)
      //An IPv4 packet was received?
      if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
      {
         //Destination IP address filtering
         if(socket->localIpAddr.length)
         {
            //An IPv4 address is expected
            if(socket->localIpAddr.length != sizeof(Ipv4Addr))
               continue;
            //Filter out non-matching addresses
            if(socket->localIpAddr.ipv4Addr != pseudoHeader->ipv4Data.destAddr)
               continue;
         }
         //Source IP address filtering
         if(socket->remoteIpAddr.length)
         {
            //An IPv4 address is expected
            if(socket->remoteIpAddr.length != sizeof(Ipv4Addr))
               continue;
            //Filter out non-matching addresses
            if(socket->remoteIpAddr.ipv4Addr != pseudoHeader->ipv4Data.srcAddr)
               continue;
         }
      }
      else
#endif
#if (IPV6_SUPPORT == ENABLED)
      //An IPv6 packet was received?
      if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
      {
         //Destination IP address filtering
         if(socket->localIpAddr.length)
         {
            //An IPv6 address is expected
            if(socket->localIpAddr.length != sizeof(Ipv6Addr))
               continue;
            //Filter out non-matching addresses
            if(!ipv6CompAddr(&socket->localIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.destAddr))
               continue;
         }
         //Source IP address filtering
         if(socket->remoteIpAddr.length)
         {
            //An IPv6 address is expected
            if(socket->remoteIpAddr.length != sizeof(Ipv6Addr))
               continue;
            //Filter out non-matching addresses
            if(!ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.srcAddr))
               continue;
         }
      }
      else
#endif
      //An invalid packet was received?
      {
         //This should never occur...
         continue;
      }

      //The current socket meets all the criteria
      break;
   }

   //Point to the payload
   offset += sizeof(UdpHeader);
   length -= sizeof(UdpHeader);

   //No matching socket found?
   if(i >= SOCKET_MAX_COUNT)
   {
      //Leave critical section
      osMutexRelease(socketMutex);
      //Invoke user callback, if any
      error = udpInvokeRxCallback(interface, pseudoHeader, header, buffer, offset);
      //Return status code
      return error;
   }

   //Empty receive queue?
   if(!socket->receiveQueue)
   {
      //Allocate a memory buffer to hold the data and the associated descriptor
      p = chunkedBufferAlloc(sizeof(SocketQueueItem) + length);

      //Successful memory allocation?
      if(p != NULL)
      {
         //Point to the newly created item
         queueItem = chunkedBufferAt(p, 0);
         queueItem->buffer = p;
         //Add the newly created item to the queue
         socket->receiveQueue = queueItem;
      }
      else
      {
         //Memory allocation failed
         queueItem = NULL;
      }
   }
   else
   {
      //Point to the very first item
      queueItem = socket->receiveQueue;
      //Reach the last item in the receive queue
      for(i = 1; queueItem->next; i++)
         queueItem = queueItem->next;

      //Make sure the receive queue is not full
      if(i >= UDP_RX_QUEUE_SIZE)
      {
         //Leave critical section
         osMutexRelease(socketMutex);
         //Notify the calling function that the queue is full
         return ERROR_RECEIVE_QUEUE_FULL;
      }

      //Allocate a memory buffer to hold the data and the associated descriptor
      p = chunkedBufferAlloc(sizeof(SocketQueueItem) + length);

      //Successful memory allocation?
      if(p != NULL)
      {
         //Add the newly created item to the queue
         queueItem->next = chunkedBufferAt(p, 0);
         //Point to the newly created item
         queueItem = queueItem->next;
         queueItem->buffer = p;
      }
      else
      {
         //Memory allocation failed
         queueItem = NULL;
      }
   }

   //Failed to allocate memory?
   if(!queueItem)
   {
      //Leave critical section
      osMutexRelease(socketMutex);
      //Return error code
      return ERROR_OUT_OF_MEMORY;
   }

   //Initialize next field
   queueItem->next = NULL;
   //Record the source port number
   queueItem->srcPort = ntohs(header->srcPort);

#if (IPV4_SUPPORT == ENABLED)
   //IPv4 remote address?
   if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
   {
      //Save the source IPv4 address
      queueItem->srcIpAddr.length = sizeof(Ipv4Addr);
      queueItem->srcIpAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr;
      //Save the destination IPv4 address
      queueItem->destIpAddr.length = sizeof(Ipv4Addr);
      queueItem->destIpAddr.ipv4Addr = pseudoHeader->ipv4Data.destAddr;
   }
#endif
#if (IPV6_SUPPORT == ENABLED)
   //IPv6 remote address?
   if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
   {
      //Save the source IPv6 address
      queueItem->srcIpAddr.length = sizeof(Ipv6Addr);
      queueItem->srcIpAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr;
      //Save the destination IPv6 address
      queueItem->destIpAddr.length = sizeof(Ipv6Addr);
      queueItem->destIpAddr.ipv6Addr = pseudoHeader->ipv6Data.destAddr;
   }
#endif

   //Offset to the payload
   queueItem->offset = sizeof(SocketQueueItem);
   //Copy the payload
   chunkedBufferCopy(queueItem->buffer, queueItem->offset, buffer, offset, length);

   //Notify user that data is available
   udpUpdateEvents(socket);

   //Leave critical section
   osMutexRelease(socketMutex);
   //Successful processing
   return NO_ERROR;
}
Пример #29
0
error_t ipv4JoinMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr)
{
    error_t error;
    uint_t i;
    MacAddr macAddr;

    //Ensure the specified IPv4 address is a multicast address
    if(!ipv4IsMulticastAddr(groupAddr))
        return ERROR_INVALID_ADDRESS;

    //Acquire exclusive access to the IPv4 filter table
    osMutexAcquire(interface->ipv4FilterMutex);

    //Loop through filter table entries
    for(i = 0; i < interface->ipv4FilterSize; i++)
    {
        //Check whether the table already contains the specified IPv4 address
        if(interface->ipv4Filter[i].addr == groupAddr)
        {
            //Increment the reference count
            interface->ipv4Filter[i].refCount++;
            //Release exclusive access to the IPv4 filter table
            osMutexRelease(interface->ipv4FilterMutex);
            //No error to report
            return NO_ERROR;
        }
    }

    //The IPv4 filter table is full ?
    if(i >= IPV4_FILTER_MAX_SIZE)
    {
        //Release exclusive access to the IPv4 filter table
        osMutexRelease(interface->ipv4FilterMutex);
        //A new entry cannot be added
        return ERROR_FAILURE;
    }

    //Map the multicast IPv4 address to a MAC-layer address
    ipv4MapMulticastAddrToMac(groupAddr, &macAddr);
    //Add the corresponding address to the MAC filter table
    error = ethAcceptMulticastAddr(interface, &macAddr);

    //Ensure the MAC filter table was successfully updated
    if(!error)
    {
        //Now we can safely add a new entry to the table
        interface->ipv4Filter[i].addr = groupAddr;
        //Initialize the reference count
        interface->ipv4Filter[i].refCount = 1;
        //Adjust the size of the IPv4 filter table
        interface->ipv4FilterSize++;

#if (IGMP_SUPPORT == ENABLED)
        //Report multicast group membership to the router
        igmpJoinGroup(interface, &interface->ipv4Filter[i]);
#endif
    }

    //Release exclusive access to the IPv4 filter table
    osMutexRelease(interface->ipv4FilterMutex);
    //Return status code
    return error;
}
Пример #30
0
void dnsProcessResponse(NetInterface *interface, const IpPseudoHeader *pseudoHeader,
   const UdpHeader *udpHeader, const ChunkedBuffer *buffer, size_t offset, void *params)
{
   uint_t i;
   uint_t j;
   size_t n;
   size_t pos;
   size_t length;
   DnsHeader *message;
   DnsQuestion *question;
   DnsResourceRecord *resourceRecord;
   DnsCacheEntry *entry;

   //Retrieve the length of the DNS message
   length = chunkedBufferGetLength(buffer) - offset;

   //Ensure the DNS message is valid
   if(length < sizeof(DnsHeader))
      return;
   if(length > DNS_MESSAGE_MAX_SIZE)
      return;

   //Point to the DNS message header
   message = chunkedBufferAt(buffer, offset);
   //Sanity check
   if(!message) return;

   //Debug message
   TRACE_INFO("DNS message received (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump message
   dnsDumpMessage(message, length);

   //Acquire exclusive access to the DNS cache
   osMutexAcquire(dnsCacheMutex);

   //Loop through DNS cache entries
   for(i = 0; i < DNS_CACHE_SIZE; i++)
   {
      //Point to the current entry
      entry = &dnsCache[i];

      //DNS name resolution in progress?
      if(entry->state == DNS_STATE_IN_PROGRESS &&
         entry->protocol == HOST_NAME_RESOLVER_DNS)
      {
         //Check destination port number
         if(entry->port == ntohs(udpHeader->destPort))
         {
            //Compare identifier against expected one
            if(ntohs(message->id) != entry->id)
               break;
            //Check message type
            if(!message->qr)
               break;
            //The DNS message shall contain one question
            if(ntohs(message->qdcount) != 1)
               break;

            //Point to the first question
            pos = sizeof(DnsHeader);

            //Parse domain name
            n = dnsParseName(message, length, pos, NULL, 0);

            //Invalid name?
            if(!n)
               break;
            //Malformed mDNS message?
            if((n + sizeof(DnsQuestion)) > length)
               break;

            //Compare domain name
            if(!dnsCompareName(message, length, pos, entry->name, 0))
               break;

            //Point to the corresponding entry
            question = DNS_GET_QUESTION(message, n);

            //Check the class of the query
            if(ntohs(question->qclass) != DNS_RR_CLASS_IN)
               break;
            //Check the type of the query
            if(entry->type == HOST_TYPE_IPV4 && ntohs(question->qtype) != DNS_RR_TYPE_A)
               break;
            if(entry->type == HOST_TYPE_IPV6 && ntohs(question->qtype) != DNS_RR_TYPE_AAAA)
               break;

            //Make sure recursion is available
            if(!message->ra)
            {
               //The entry should be deleted since name resolution has failed
               dnsDeleteEntry(entry);
               //Exit immediately
               break;
            }

            //Check return code
            if(message->rcode != DNS_RCODE_NO_ERROR)
            {
               //The entry should be deleted since name resolution has failed
               dnsDeleteEntry(entry);
               //Exit immediately
               break;
            }

            //Point to the first answer
            pos = n + sizeof(DnsQuestion);

            //Parse answer resource records
            for(j = 0; j < ntohs(message->ancount); j++)
            {
               //Parse domain name
               pos = dnsParseName(message, length, pos, NULL, 0);
               //Invalid name?
               if(!pos) break;

               //Point to the associated resource record
               resourceRecord = DNS_GET_RESOURCE_RECORD(message, pos);
               //Point to the resource data
               pos += sizeof(DnsResourceRecord);

               //Make sure the resource record is valid
               if(pos >= length)
                  break;
               if((pos + ntohs(resourceRecord->rdlength)) > length)
                  break;

#if (IPV4_SUPPORT == ENABLED)
               //IPv4 address expected?
               if(entry->type == HOST_TYPE_IPV4)
               {
                  //A resource record found?
                  if(ntohs(resourceRecord->rtype) == DNS_RR_TYPE_A)
                  {
                     //Verify the length of the data field
                     if(ntohs(resourceRecord->rdlength) == sizeof(Ipv4Addr))
                     {
                        //Copy the IPv4 address
                        entry->ipAddr.length = sizeof(Ipv4Addr);
                        ipv4CopyAddr(&entry->ipAddr.ipv4Addr, resourceRecord->rdata);

                        //Save current time
                        entry->timestamp = osGetTickCount();
                        //Save TTL value
                        entry->timeout = ntohl(resourceRecord->ttl) * 1000;
                        //Limit the lifetime of the DNS cache entries
                        entry->timeout = min(entry->timeout, DNS_MAX_LIFETIME);

                        //Unregister UDP callback function
                        udpDetachRxCallback(interface, entry->port);
                        //Host name successfully resolved
                        entry->state = DNS_STATE_RESOLVED;
                        //Exit immediately
                        break;
                     }
                  }
               }
#endif
#if (IPV6_SUPPORT == ENABLED)
               //IPv6 address expected?
               if(entry->type == HOST_TYPE_IPV6)
               {
                  //AAAA resource record found?
                  if(ntohs(resourceRecord->rtype) == DNS_RR_TYPE_AAAA)
                  {
                     //Verify the length of the data field
                     if(ntohs(resourceRecord->rdlength) == sizeof(Ipv6Addr))
                     {
                        //Copy the IPv6 address
                        entry->ipAddr.length = sizeof(Ipv6Addr);
                        ipv6CopyAddr(&entry->ipAddr.ipv6Addr, resourceRecord->rdata);

                        //Save current time
                        entry->timestamp = osGetTickCount();
                        //Save TTL value
                        entry->timeout = ntohl(resourceRecord->ttl) * 1000;
                        //Limit the lifetime of the DNS cache entries
                        entry->timeout = min(entry->timeout, DNS_MAX_LIFETIME);

                        //Unregister UDP callback function
                        udpDetachRxCallback(interface, entry->port);
                        //Host name successfully resolved
                        entry->state = DNS_STATE_RESOLVED;
                        //Exit immediately
                        break;
                     }
                  }
               }
#endif
               //Point to the next resource record
               pos += ntohs(resourceRecord->rdlength);
            }

            //We are done
            break;
         }
      }
   }

   //Release exclusive access to the DNS cache
   osMutexRelease(dnsCacheMutex);
}