Exemplo n.º 1
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);
}
Exemplo n.º 2
0
error_t mldSendListenerDone(NetInterface *interface, Ipv6Addr *ipAddr)
{
   error_t error;
   size_t offset;
   MldMessage *message;
   ChunkedBuffer *buffer;
   Ipv6PseudoHeader pseudoHeader;

   //Make sure the specified address is a valid multicast address
   if(!ipv6IsMulticastAddr(ipAddr))
      return ERROR_INVALID_ADDRESS;

   //The link-scope all-nodes address (FF02::1) is handled as a special
   //case. The host never sends a report for that address
   if(ipv6CompAddr(ipAddr, &IPV6_LINK_LOCAL_ALL_NODES_ADDR))
      return ERROR_INVALID_ADDRESS;

   //Allocate a memory buffer to hold a MLD message
   buffer = ipAllocBuffer(sizeof(MldMessage), &offset);
   //Failed to allocate memory?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Point to the beginning of the MLD message
   message = chunkedBufferAt(buffer, offset);

   //Format the Multicast Listener Done message
   message->type = ICMPV6_TYPE_MULTICAST_LISTENER_DONE_V1;
   message->code = 0;
   message->checksum = 0;
   message->maxRespDelay = 0;
   message->reserved = 0;
   message->multicastAddr = *ipAddr;

   //Format IPv6 pseudo header
   pseudoHeader.srcAddr = interface->ipv6Config.linkLocalAddr;
   pseudoHeader.destAddr = IPV6_LINK_LOCAL_ALL_ROUTERS_ADDR;
   pseudoHeader.length = HTONS(sizeof(MldMessage));
   pseudoHeader.reserved = 0;
   pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;

   //Message checksum calculation
   message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
      sizeof(Ipv6PseudoHeader), buffer, offset, sizeof(MldMessage));

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

   //The Multicast Listener Done message is sent to the all-routers multicast address
   error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, MLD_HOP_LIMIT);

   //Free previously allocated memory
   chunkedBufferFree(buffer);
   //Return status code
   return error;
}
Exemplo n.º 3
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);
}
Exemplo n.º 4
0
error_t mldStartListening(NetInterface *interface, Ipv6FilterEntry *entry)
{
   //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))
   {
      //Clear flag
      entry->flag = FALSE;
      //Enter the Idle Listener state
      entry->state = MLD_STATE_IDLE_LISTENER;
   }
   else
   {
      //Link is up?
      if(interface->linkState)
      {
         //Send a Multicast Listener Report message for the group on the interface
         mldSendListenerReport(interface, &entry->addr);

         //Set flag
         entry->flag = TRUE;
         //Start timer
         entry->timer = osGetTickCount() + MLD_UNSOLICITED_REPORT_INTERVAL;
         //Enter the Delaying Listener state
         entry->state = MLD_STATE_DELAYING_LISTENER;
      }
      //Link is down?
      else
      {
         //Clear flag
         entry->flag = FALSE;
         //Enter the Idle Listener state
         entry->state = MLD_STATE_IDLE_LISTENER;
      }
   }

   //Successful processing
   return NO_ERROR;
}
Exemplo n.º 5
0
NdpCacheEntry *ndpFindEntry(NetInterface *interface, const Ipv6Addr *ipAddr)
{
   uint_t i;
   NdpCacheEntry *entry;

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

      //Check whether the entry is currently in used
      if(entry->state != NDP_STATE_NONE)
      {
         //Current entry matches the specified address?
         if(ipv6CompAddr(&entry->ipAddr, ipAddr))
            return entry;
      }
   }

   //No matching entry in Neighbor cache...
   return NULL;
}
Exemplo n.º 6
0
void ndpProcessNeighborAdv(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
   const ChunkedBuffer *buffer, size_t offset, uint8_t hopLimit)
{
   size_t length;
   NdpNeighborAdvMessage *message;
   NdpLinkLayerAddrOption *option;
   NdpCacheEntry *entry;

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

   //Check the length of the Neighbor Advertisement message
   if(length < sizeof(NdpNeighborAdvMessage))
      return;

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

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

   //The IPv6 Hop Limit field must have a value of 255 to ensure
   //that the packet has not been forwarded by a router
   if(hopLimit != NDP_HOP_LIMIT)
      return;

   //ICMPv6 Code must be 0
   if(message->code)
      return;

   //Check whether the target address is tentative or matches
   //a unicast address assigned to the interface
   if(ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.linkLocalAddr) &&
      interface->ipv6Config.linkLocalAddrState != IPV6_ADDR_STATE_INVALID)
   {
      //Debug message
      TRACE_WARNING("The address %s is a duplicate!\r\n",
         ipv6AddrToString(&interface->ipv6Config.linkLocalAddr, NULL));

      //The address is a duplicate and should not be used
      interface->ipv6Config.linkLocalAddrDup = TRUE;
      //Exit immediately
      return;
   }
   else if(ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.globalAddr) &&
      interface->ipv6Config.globalAddrState != IPV6_ADDR_STATE_INVALID)
   {
      //Debug message
      TRACE_WARNING("The address %s is a duplicate!\r\n",
         ipv6AddrToString(&interface->ipv6Config.globalAddr, NULL));

      //The address is a duplicate and should not be used
      interface->ipv6Config.globalAddrDup = TRUE;
      //Exit immediately
      return;
   }

   //The target address must not be a multicast address
   if(ipv6IsMulticastAddr(&message->targetAddr))
   {
      //Debug message
      TRACE_WARNING("Target address must not be a multicast address!\r\n");
      //Exit immediately
      return;
   }

   //If the destination address is a multicast address
   //then the Solicited flag must be zero
   if(ipv6IsMulticastAddr(&pseudoHeader->destAddr) && message->s)
   {
      //Debug message
      TRACE_WARNING("Solicited flag must be zero!\r\n");
      //Exit immediately
      return;
   }

   //Calculate the length of the Options field
   length -= sizeof(NdpNeighborSolMessage);
   //Search for the Target Link-Layer Address option
   option = ndpGetOption(message->options, length, NDP_OPT_TARGET_LINK_LAYER_ADDR);

   //Source Link-Layer Address option found?
   if(option && option->length == 1)
   {
      //Debug message
      TRACE_DEBUG("  Target Link-Layer Address = %s\r\n",
         macAddrToString(&option->linkLayerAddr, NULL));

      //Acquire exclusive access to Neighbor cache
      osAcquireMutex(&interface->ndpCacheMutex);

      //Search the Neighbor cache for the specified target address
      entry = ndpFindEntry(interface, &message->targetAddr);

      //If no entry exists, the advertisement should be silently discarded
      if(entry)
      {
         //INCOMPLETE state?
         if(entry->state == NDP_STATE_INCOMPLETE)
         {
            //Record link-layer address
            entry->macAddr = option->linkLayerAddr;
            //Send all the packets that are pending for transmission
            ndpSendQueuedPackets(interface, entry);
            //Save current time
            entry->timestamp = osGetSystemTime();

            //Solicited flag is set?
            if(message->s)
            {
               //Computing the random ReachableTime value
               entry->timeout = NDP_REACHABLE_TIME;
               //Switch to the REACHABLE state
               entry->state = NDP_STATE_REACHABLE;
            }
            //Solicited flag is cleared?
            else
            {
               //Enter the STALE state
               entry->state = NDP_STATE_STALE;
            }
         }
         //REACHABLE, STALE, DELAY or PROBE state?
         else
         {
            //Solicited flag is set and Override flag is cleared?
            if(message->s && !message->o)
            {
               //Same link-layer address than cached?
               if(macCompAddr(&entry->macAddr, &option->linkLayerAddr))
               {
                  //Save current time
                  entry->timestamp = osGetSystemTime();
                  //Computing the random ReachableTime value
                  entry->timeout = NDP_REACHABLE_TIME;
                  //Switch to the REACHABLE state
                  entry->state = NDP_STATE_REACHABLE;
               }
               //Different link-layer address than cached?
               else
               {
                  //REACHABLE state?
                  if(entry->state == NDP_STATE_REACHABLE)
                  {
                     //Save current time
                     entry->timestamp = osGetSystemTime();
                     //Enter the STALE state
                     entry->state = NDP_STATE_STALE;
                  }
               }
            }
            //Both Solicited and Override flags are set?
            else if(message->s && message->o)
            {
               //Record link-layer address (if different)
               entry->macAddr = option->linkLayerAddr;
               //Save current time
               entry->timestamp = osGetSystemTime();
               //Computing the random ReachableTime value
               entry->timeout = NDP_REACHABLE_TIME;
               //Switch to the REACHABLE state
               entry->state = NDP_STATE_REACHABLE;
            }
            //Solicited flag is cleared and Override flag is set?
            else if(!message->s && message->o)
            {
               //Different link-layer address than cached?
               if(!macCompAddr(&entry->macAddr, &option->linkLayerAddr))
               {
                  //Record link-layer address
                  entry->macAddr = option->linkLayerAddr;
                  //Save current time
                  entry->timestamp = osGetSystemTime();
                  //Enter the STALE state
                  entry->state = NDP_STATE_STALE;
               }
            }
         }
      }
   }
   //Source Link-Layer Address option not found?
   else
   {
      //Update content of IsRouter flag
   }

   //Release exclusive access to Neighbor cache
   osReleaseMutex(&interface->ndpCacheMutex);
}
Exemplo n.º 7
0
void ndpProcessNeighborSol(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
   const ChunkedBuffer *buffer, size_t offset, uint8_t hopLimit)
{
   size_t length;
   NdpNeighborSolMessage *message;
   NdpLinkLayerAddrOption *option;
   NdpCacheEntry *entry;

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

   //Check the length of the Neighbor Solicitation message
   if(length < sizeof(NdpNeighborSolMessage))
      return;

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

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

   //The IPv6 Hop Limit field must have a value of 255 to ensure
   //that the packet has not been forwarded by a router
   if(hopLimit != NDP_HOP_LIMIT)
      return;

   //ICMPv6 Code must be 0
   if(message->code)
      return;

   //The target address must a valid unicast address assigned to the interface
   //or a tentative address on which DAD is being performed
   if(ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.linkLocalAddr))
   {
      //Check whether the target address is tentative
      if(interface->ipv6Config.linkLocalAddrState == IPV6_ADDR_STATE_TENTATIVE)
      {
         //If the source address of the Neighbor Solicitation is the unspecified
         //address, the solicitation is from a node performing Duplicate Address
         //Detection
         if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR))
         {
            //Debug message
            TRACE_WARNING("The tentative address %s is a duplicate!\r\n",
               ipv6AddrToString(&interface->ipv6Config.linkLocalAddr, NULL));

            //The tentative address is a duplicate and should not be used
            interface->ipv6Config.linkLocalAddrDup = TRUE;
         }

         //In all cases, a node must not respond to a Neighbor Solicitation
         //for a tentative address
         return;
      }
   }
   else if(ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.globalAddr))
   {
      //Check whether the target address is tentative
      if(interface->ipv6Config.globalAddrState == IPV6_ADDR_STATE_TENTATIVE)
      {
         //If the source address of the Neighbor Solicitation is the unspecified
         //address, the solicitation is from a node performing Duplicate Address
         //Detection
         if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR))
         {
            //Debug message
            TRACE_WARNING("The tentative address %s is a duplicate!\r\n",
               ipv6AddrToString(&interface->ipv6Config.globalAddr, NULL));

            //The tentative address is a duplicate and should not be used
            interface->ipv6Config.globalAddrDup = TRUE;
         }

         //In all cases, a node must not respond to a Neighbor Solicitation
         //for a tentative address
         return;
      }
   }
   else
   {
      //Debug message
      TRACE_WARNING("Wrong target address!\r\n");
      //Exit immediately
      return;
   }

   //If the IP source address is the unspecified address, the IP
   //destination address must be a solicited-node multicast address
   if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR) &&
      !ipv6IsSolicitedNodeAddr(&pseudoHeader->destAddr))
   {
      //Debug message
      TRACE_WARNING("Destination address must be a solicited-node address!\r\n");
      //Exit immediately
      return;
   }

   //Calculate the length of the Options field
   length -= sizeof(NdpNeighborSolMessage);
   //Search for the Source Link-Layer Address option
   option = ndpGetOption(message->options, length, NDP_OPT_SOURCE_LINK_LAYER_ADDR);

   //Source Link-Layer Address option found?
   if(option && option->length == 1)
   {
      //Debug message
      TRACE_DEBUG("  Source Link-Layer Address = %s\r\n",
         macAddrToString(&option->linkLayerAddr, NULL));

      //If the Source Address is not the unspecified address, then the Neighbor
      //cache should be updated for the IP source address of the solicitation
      if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR))
         return;

      //Acquire exclusive access to Neighbor cache
      osAcquireMutex(&interface->ndpCacheMutex);

      //Search the Neighbor cache for the source address of the solicitation
      entry = ndpFindEntry(interface, &pseudoHeader->srcAddr);

      //No matching entry has been found?
      if(!entry)
      {
         //Create an entry
         entry = ndpCreateEntry(interface);

         //Neighbor cache entry successfully created?
         if(entry)
         {
            //Record the IPv6 and the corresponding MAC address
            entry->ipAddr = pseudoHeader->srcAddr;
            entry->macAddr = option->linkLayerAddr;
            //Save current time
            entry->timestamp = osGetSystemTime();
            //Enter the STALE state
            entry->state = NDP_STATE_STALE;
         }
      }
      else
      {
         //INCOMPLETE state?
         if(entry->state == NDP_STATE_INCOMPLETE)
         {
            //Record link-layer address
            entry->macAddr = option->linkLayerAddr;
            //Send all the packets that are pending for transmission
            ndpSendQueuedPackets(interface, entry);
            //Save current time
            entry->timestamp = osGetSystemTime();
            //Enter the STALE state
            entry->state = NDP_STATE_STALE;
         }
         //REACHABLE, STALE, DELAY or PROBE state?
         else
         {
            //Different link-layer address than cached?
            if(!macCompAddr(&entry->macAddr, &option->linkLayerAddr))
            {
               //Update link-layer address
               entry->macAddr = option->linkLayerAddr;
               //Save current time
               entry->timestamp = osGetSystemTime();
               //Enter the STALE state
               entry->state = NDP_STATE_STALE;
            }
         }
      }

      //Release exclusive access to Neighbor cache
      osReleaseMutex(&interface->ndpCacheMutex);
   }
   //Source Link-Layer Address option not found?
   else
   {
      //This option must be included in multicast solicitations
      if(ipv6IsMulticastAddr(&pseudoHeader->destAddr))
      {
         //Debug message
         TRACE_WARNING("The Source Link-Layer Address must be included!\r\n");
         //Exit immediately
         return;
      }
   }

   //After any updates to the Neighbor cache, the node sends a Neighbor
   //Advertisement response as described in RFC 4861 7.2.4
   ndpSendNeighborAdv(interface, &message->targetAddr, &pseudoHeader->srcAddr);
}
Exemplo n.º 8
0
error_t ndpSendNeighborAdv(NetInterface *interface,
   const Ipv6Addr *targetIpAddr, const Ipv6Addr *destIpAddr)
{
   error_t error;
   size_t offset;
   size_t length;
   ChunkedBuffer *buffer;
   NdpNeighborAdvMessage *message;
   Ipv6PseudoHeader pseudoHeader;

   //Allocate a memory buffer to hold the Neighbor Advertisement
   //message and the Target Link-Layer Address option
   buffer = ipAllocBuffer(sizeof(NdpNeighborAdvMessage) +
      sizeof(NdpLinkLayerAddrOption), &offset);

   //Failed to allocate memory?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Point to the beginning of the message
   message = chunkedBufferAt(buffer, offset);

   //Format Neighbor Advertisement message
   message->type = ICMPV6_TYPE_NEIGHBOR_ADV;
   message->code = 0;
   message->checksum = 0;
   message->reserved1 = 0;
   message->o = TRUE;
   message->s = FALSE;
   message->r = FALSE;
   message->reserved2 = 0;
   message->targetAddr = *targetIpAddr;

   //Length of the message, excluding any option
   length = sizeof(NdpNeighborAdvMessage);

   //Add Target Link-Layer Address option
   ndpAddOption(message, &length, NDP_OPT_TARGET_LINK_LAYER_ADDR,
      &interface->macAddr, sizeof(MacAddr));

   //Adjust the length of the multi-part buffer
   chunkedBufferSetLength(buffer, offset + length);

   //Format IPv6 pseudo header
   pseudoHeader.srcAddr = *targetIpAddr;
   pseudoHeader.destAddr = *destIpAddr;
   pseudoHeader.length = htonl(length);
   pseudoHeader.reserved = 0;
   pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;

   //Destination IP address is the unspecified address?
   if(ipv6CompAddr(destIpAddr, &IPV6_UNSPECIFIED_ADDR))
   {
      //If the destination is the unspecified address, the node
      //must set the Solicited flag to zero and multicast the
      //advertisement to the all-nodes address
      pseudoHeader.destAddr = IPV6_LINK_LOCAL_ALL_NODES_ADDR;
   }
   else
   {
      //Otherwise, the node must set the Solicited flag to one and
      //unicast the advertisement to the destination IP address
      message->s = TRUE;
   }

   //Calculate ICMPv6 header checksum
   message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
      sizeof(Ipv6PseudoHeader), buffer, offset, length);

   //Debug message
   TRACE_INFO("Sending Neighbor Advertisement message (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump message contents for debugging purpose
   ndpDumpNeighborAdvMessage(message);

   //Send Neighbor Advertisement message
   error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, NDP_HOP_LIMIT);

   //Free previously allocated memory
   chunkedBufferFree(buffer);
   //Return status code
   return error;
}
Exemplo n.º 9
0
error_t ndpSendNeighborSol(NetInterface *interface, const Ipv6Addr *targetIpAddr)
{
   error_t error;
   size_t offset;
   size_t length;
   ChunkedBuffer *buffer;
   NdpNeighborSolMessage *message;
   Ipv6PseudoHeader pseudoHeader;

   //Allocate a memory buffer to hold the Neighbor Solicitation
   //message and the Source Link-Layer Address option
   buffer = ipAllocBuffer(sizeof(NdpNeighborSolMessage) +
      sizeof(NdpLinkLayerAddrOption), &offset);

   //Failed to allocate memory?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Point to the beginning of the message
   message = chunkedBufferAt(buffer, offset);

   //Format Neighbor Solicitation message
   message->type = ICMPV6_TYPE_NEIGHBOR_SOL;
   message->code = 0;
   message->checksum = 0;
   message->reserved = 0;
   message->targetAddr = *targetIpAddr;

   //Length of the message, excluding any option
   length = sizeof(NdpNeighborSolMessage);

   //Check whether the target address is a tentative address
   if(ipv6IsTentativeAddr(interface, targetIpAddr))
   {
      //The IPv6 source is set to the unspecified address
      pseudoHeader.srcAddr = IPV6_UNSPECIFIED_ADDR;
   }
   else
   {
      //The Source Link-Layer Address option must not be included
      //when the host IPv6 address is unspecified
      if(!ipv6CompAddr(&interface->ipv6Config.linkLocalAddr, &IPV6_UNSPECIFIED_ADDR))
      {
         //Add Source Link-Layer Address option
         ndpAddOption(message, &length, NDP_OPT_SOURCE_LINK_LAYER_ADDR,
            &interface->macAddr, sizeof(MacAddr));
      }

      //Set the IPv6 source address
      pseudoHeader.srcAddr = interface->ipv6Config.linkLocalAddr;
   }

   //Adjust the length of the multi-part buffer
   chunkedBufferSetLength(buffer, offset + length);

   //Compute the solicited-node multicast address that
   //corresponds to the target IPv6 address
   ipv6ComputeSolicitedNodeAddr(targetIpAddr, &pseudoHeader.destAddr);

   //Format IPv6 pseudo header
   pseudoHeader.length = htonl(length);
   pseudoHeader.reserved = 0;
   pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;

   //Calculate ICMPv6 header checksum
   message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
      sizeof(Ipv6PseudoHeader), buffer, offset, length);

   //Debug message
   TRACE_INFO("Sending Neighbor Solicitation message (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump message contents for debugging purpose
   ndpDumpNeighborSolMessage(message);

   //Send Neighbor Solicitation message
   error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, NDP_HOP_LIMIT);

   //Free previously allocated memory
   chunkedBufferFree(buffer);
   //Return status code
   return error;
}
Exemplo n.º 10
0
Ipv6FragDesc *ipv6SearchFragQueue(NetInterface *interface,
   Ipv6Header *packet, Ipv6FragmentHeader *header)
{
   error_t error;
   uint_t i;
   Ipv6Header *datagram;
   Ipv6FragDesc *frag;
   Ipv6HoleDesc *hole;

   //Search for a matching IP datagram being reassembled
   for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++)
   {
      //Point to the current entry in the reassembly queue
      frag = &interface->ipv6FragQueue[i];

      //Check whether the current entry is used?
      if(frag->buffer.chunkCount > 0)
      {
         //Point to the corresponding datagram
         datagram = chunkedBufferAt((ChunkedBuffer *) &frag->buffer, 0);

         //Check source and destination addresses
         if(!ipv6CompAddr(&datagram->srcAddr, &packet->srcAddr))
            continue;
         if(!ipv6CompAddr(&datagram->destAddr, &packet->destAddr))
            continue;
         //Compare fragment identification fields
         if(frag->identification != header->identification)
            continue;

         //A matching entry has been found in the reassembly queue
         return frag;
      }
   }

   //If the current packet does not match an existing entry
   //in the reassembly queue, then create a new entry
   for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++)
   {
      //Point to the current entry in the reassembly queue
      frag = &interface->ipv6FragQueue[i];

      //The current entry is free?
      if(!frag->buffer.chunkCount)
      {
         //Number of chunks that comprise the reassembly buffer
         frag->buffer.maxChunkCount = arraysize(frag->buffer.chunk);

         //Allocate sufficient memory to hold the IPv6 header and
         //the first hole descriptor
         error = chunkedBufferSetLength((ChunkedBuffer *) &frag->buffer,
            MEM_POOL_BUFFER_SIZE + sizeof(Ipv6HoleDesc));

         //Failed to allocate memory?
         if(error)
         {
            //Clean up side effects
            chunkedBufferSetLength((ChunkedBuffer *) &frag->buffer, 0);
            //Exit immediately
            return NULL;
         }

         //Initial length of the reconstructed datagram
         frag->unfragPartLength = sizeof(Ipv6Header);
         frag->fragPartLength = 0;

         //Fix the length of the first chunk
         frag->buffer.chunk[0].length = frag->unfragPartLength;
         //Copy IPv6 header from the incoming fragment
         chunkedBufferWrite((ChunkedBuffer *) &frag->buffer, 0, packet, frag->unfragPartLength);

         //Save current time
         frag->timestamp = osGetSystemTime();
         //Record fragment identification field
         frag->identification = header->identification;
         //Create a new entry in the hole descriptor list
         frag->firstHole = 0;

         //Point to first hole descriptor
         hole = ipv6FindHole(frag, frag->firstHole);
         //The entry describes the datagram  as  being completely missing
         hole->first = 0;
         hole->last = IPV6_INFINITY;
         hole->next = IPV6_INFINITY;

         //Dump hole descriptor list
         ipv6DumpHoleList(frag);

         //Return the matching fragment descriptor
         return frag;
      }
   }

   //The reassembly queue is full
   return NULL;
}
Exemplo n.º 11
0
error_t dnsSendQuery(DnsCacheEntry *entry)
{
   error_t error;
   size_t length;
   size_t offset;
   ChunkedBuffer *buffer;
   DnsHeader *message;
   DnsQuestion *dnsQuestion;
   IpAddr destIpAddr;

#if (IPV4_SUPPORT == ENABLED)
   //An IPv4 address is expected?
   if(entry->type == HOST_TYPE_IPV4)
   {
      //Select the relevant DNS server
      destIpAddr.length = sizeof(Ipv4Addr);
      ipv4GetDnsServer(entry->interface, entry->dnsServerNum, &destIpAddr.ipv4Addr);

      //Make sure the IP address is valid
      if(destIpAddr.ipv4Addr == IPV4_UNSPECIFIED_ADDR)
         return ERROR_NO_DNS_SERVER;
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   //An IPv6 address is expected?
   if(entry->type == HOST_TYPE_IPV6)
   {
      //Select the relevant DNS server
      destIpAddr.length = sizeof(Ipv6Addr);
      ipv6GetDnsServer(entry->interface, entry->dnsServerNum, &destIpAddr.ipv6Addr);

      //Make sure the IP address is valid
      if(ipv6CompAddr(&destIpAddr.ipv6Addr, &IPV6_UNSPECIFIED_ADDR))
         return ERROR_NO_DNS_SERVER;
   }
   else
#endif
   //Invalid host type?
   {
      //Report an error
      return ERROR_INVALID_PARAMETER;
   }

   //Allocate a memory buffer to hold the DNS query message
   buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset);
   //Failed to allocate buffer?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Point to the DNS header
   message = chunkedBufferAt(buffer, offset);

   //Format DNS query message
   message->id = htons(entry->id);
   message->qr = 0;
   message->opcode = DNS_OPCODE_QUERY;
   message->aa = 0;
   message->tc = 0;
   message->rd = 1;
   message->ra = 0;
   message->z = 0;
   message->rcode = DNS_RCODE_NO_ERROR;

   //The DNS query contains one question
   message->qdcount = HTONS(1);
   message->ancount = 0;
   message->nscount = 0;
   message->arcount = 0;

   //Length of the DNS query message
   length = sizeof(DnsHeader);

   //Encode the host name using the DNS name notation
   length += dnsEncodeName(entry->name, message->questions);

   //Point to the corresponding question structure
   dnsQuestion = DNS_GET_QUESTION(message, length);

#if (IPV4_SUPPORT == ENABLED)
   //An IPv4 address is expected?
   if(entry->type == HOST_TYPE_IPV4)
   {
      //Fill in question structure
      dnsQuestion->qtype = HTONS(DNS_RR_TYPE_A);
      dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN);
   }
#endif
#if (IPV6_SUPPORT == ENABLED)
   //An IPv6 address is expected?
   if(entry->type == HOST_TYPE_IPV6)
   {
      //Fill in question structure
      dnsQuestion->qtype = HTONS(DNS_RR_TYPE_AAAA);
      dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN);
   }
#endif

   //Update the length of the DNS query message
   length += sizeof(DnsQuestion);

   //Adjust the length of the multi-part buffer
   chunkedBufferSetLength(buffer, offset + length);

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

   //Send DNS query message
   error = udpSendDatagramEx(entry->interface, entry->port,
      &destIpAddr, DNS_PORT, buffer, offset, 0);

   //Free previously allocated memory
   chunkedBufferFree(buffer);
   //Return status code
   return error;
}
Exemplo n.º 12
0
void tcpProcessSegment(NetInterface *interface,
   IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
{
   uint_t i;
   size_t length;
   Socket *socket;
   Socket *passiveSocket;
   TcpHeader *segment;

   //Total number of segments received, including those received in error
   MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInSegs, 1);
   MIB2_INC_COUNTER64(mib2Base.tcpGroup.tcpHCInSegs, 1);

   //A TCP implementation must silently discard an incoming
   //segment that is addressed to a broadcast or multicast
   //address (see RFC 1122 4.2.3.10)
#if (IPV4_SUPPORT == ENABLED)
   if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
   {
      //Ensure the destination address is not a broadcast address
      if(ipv4IsBroadcastAddr(interface, pseudoHeader->ipv4Data.destAddr))
         return;
      //Ensure the destination address is not a multicast address
      if(ipv4IsMulticastAddr(pseudoHeader->ipv4Data.destAddr))
         return;
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
   {
      //Ensure the destination address is not a multicast address
      if(ipv6IsMulticastAddr(&pseudoHeader->ipv6Data.destAddr))
         return;
   }
   else
#endif
   {
      //This should never occur...
      return;
   }

   //Retrieve the length of the TCP segment
   length = netBufferGetLength(buffer) - offset;

   //Point to the TCP header
   segment = netBufferAt(buffer, offset);
   //Sanity check
   if(segment == NULL)
      return;

   //Ensure the TCP header is valid
   if(length < sizeof(TcpHeader))
   {
      //Debug message
      TRACE_WARNING("TCP segment length is invalid!\r\n");
      //Total number of segments received in error
      MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInErrs, 1);
      //Exit immediately
      return;
   }

   //Check header length
   if(segment->dataOffset < 5 || (segment->dataOffset * 4) > length)
   {
      //Debug message
      TRACE_WARNING("TCP header length is invalid!\r\n");
      //Total number of segments received in error
      MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInErrs, 1);
      //Exit immediately
      return;
   }

   //Verify TCP checksum
   if(ipCalcUpperLayerChecksumEx(pseudoHeader->data,
      pseudoHeader->length, buffer, offset, length) != 0x0000)
   {
      //Debug message
      TRACE_WARNING("Wrong TCP header checksum!\r\n");
      //Total number of segments received in error
      MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpInErrs, 1);
      //Exit immediately
      return;
   }

   //No matching socket in the LISTEN state for the moment
   passiveSocket = NULL;

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

      //TCP socket found?
      if(socket->type != SOCKET_TYPE_STREAM)
         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(segment->destPort))
         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;
      }

      //Keep track of the first matching socket in the LISTEN state
      if(socket->state == TCP_STATE_LISTEN && !passiveSocket)
         passiveSocket = socket;
      //Source port filtering
      if(socket->remotePort != ntohs(segment->srcPort))
         continue;

      //A matching socket has been found
      break;
   }

   //If no matching socket has been found then try to
   //use the first matching socket in the LISTEN state
   if(i >= SOCKET_MAX_COUNT) socket = passiveSocket;

   //Offset to the first data byte
   offset += segment->dataOffset * 4;
   //Calculate the length of the data
   length -= segment->dataOffset * 4;

   //Debug message
   TRACE_DEBUG("%s: TCP segment received (%" PRIuSIZE " data bytes)...\r\n",
      formatSystemTime(osGetSystemTime(), NULL), length);

   //Dump TCP header contents for debugging purpose
   if(!socket)
      tcpDumpHeader(segment, length, 0, 0);
   else
      tcpDumpHeader(segment, length, socket->irs, socket->iss);

   //Convert from network byte order to host byte order
   segment->srcPort = ntohs(segment->srcPort);
   segment->destPort = ntohs(segment->destPort);
   segment->seqNum = ntohl(segment->seqNum);
   segment->ackNum = ntohl(segment->ackNum);
   segment->window = ntohs(segment->window);
   segment->urgentPointer = ntohs(segment->urgentPointer);

   //Specified port is unreachable?
   if(!socket)
   {
      //An incoming segment not containing a RST causes
      //a reset to be sent in response
      if(!(segment->flags & TCP_FLAG_RST))
         tcpSendResetSegment(interface, pseudoHeader, segment, length);

      //Return immediately
      return;
   }

   //Check current state
   switch(socket->state)
   {
   //Process CLOSED state
   case TCP_STATE_CLOSED:
      //This is the default state that each connection starts in before
      //the process of establishing it begins
      tcpStateClosed(interface, pseudoHeader, segment, length);
      break;
   //Process LISTEN state
   case TCP_STATE_LISTEN:
      //A device (normally a server) is waiting to receive a synchronize (SYN)
      //message from a client. It has not yet sent its own SYN message
      tcpStateListen(socket, interface, pseudoHeader, segment, length);
      break;
   //Process SYN_SENT state
   case TCP_STATE_SYN_SENT:
      //The device (normally a client) has sent a synchronize (SYN) message and
      //is waiting for a matching SYN from the other device (usually a server)
      tcpStateSynSent(socket, segment, length);
      break;
   //Process SYN_RECEIVED state
   case TCP_STATE_SYN_RECEIVED:
      //The device has both received a SYN from its partner and sent its own SYN.
      //It is now waiting for an ACK to its SYN to finish connection setup
      tcpStateSynReceived(socket, segment, buffer, offset, length);
      break;
   //Process ESTABLISHED state
   case TCP_STATE_ESTABLISHED:
      //Data can be exchanged freely once both devices in the connection enter
      //this state. This will continue until the connection is closed
      tcpStateEstablished(socket, segment, buffer, offset, length);
      break;
   //Process CLOSE_WAIT state
   case TCP_STATE_CLOSE_WAIT:
      //The device has received a close request (FIN) from the other device. It
      //must now wait for the application to acknowledge this request and
      //generate a matching request
      tcpStateCloseWait(socket, segment, length);
      break;
   //Process LAST_ACK state
   case TCP_STATE_LAST_ACK:
      //A device that has already received a close request and acknowledged it,
      //has sent its own FIN and is waiting for an ACK to this request
      tcpStateLastAck(socket, segment, length);
      break;
   //Process FIN_WAIT_1 state
   case TCP_STATE_FIN_WAIT_1:
      //A device in this state is waiting for an ACK for a FIN it has sent, or
      //is waiting for a connection termination request from the other device
      tcpStateFinWait1(socket, segment, buffer, offset, length);
      break;
   //Process FIN_WAIT_2 state
   case TCP_STATE_FIN_WAIT_2:
      //A device in this state has received an ACK for its request to terminate the
      //connection and is now waiting for a matching FIN from the other device
      tcpStateFinWait2(socket, segment, buffer, offset, length);
      break;
   //Process CLOSING state
   case TCP_STATE_CLOSING:
      //The device has received a FIN from the other device and sent an ACK for
      //it, but not yet received an ACK for its own FIN message
      tcpStateClosing(socket, segment, length);
      break;
   //Process TIME_WAIT state
   case TCP_STATE_TIME_WAIT:
      //The device has now received a FIN from the other device and acknowledged
      //it, and sent its own FIN and received an ACK for it. We are done, except
      //for waiting to ensure the ACK is received and prevent potential overlap
      //with new connections
      tcpStateTimeWait(socket, segment, length);
      break;
   //Invalid state...
   default:
      //Back to the CLOSED state
      tcpChangeState(socket, TCP_STATE_CLOSED);
      //Silently discard incoming packet
      break;
   }
}
Exemplo n.º 13
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);
}
Exemplo n.º 14
0
error_t udpProcessDatagram(NetInterface *interface,
                           IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
{
    error_t error;
    uint_t i;
    size_t length;
    UdpHeader *header;
    Socket *socket;
    SocketQueueItem *queueItem;
    NetBuffer *p;

    //Retrieve the length of the UDP datagram
    length = netBufferGetLength(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 = netBufferAt(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
    osAcquireMutex(&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
        osReleaseMutex(&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 = netBufferAlloc(sizeof(SocketQueueItem) + length);

        //Successful memory allocation?
        if(p != NULL)
        {
            //Point to the newly created item
            queueItem = netBufferAt(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
            osReleaseMutex(&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 = netBufferAlloc(sizeof(SocketQueueItem) + length);

        //Successful memory allocation?
        if(p != NULL)
        {
            //Add the newly created item to the queue
            queueItem->next = netBufferAt(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
        osReleaseMutex(&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
    netBufferCopy(queueItem->buffer, queueItem->offset, buffer, offset, length);

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

    //Leave critical section
    osReleaseMutex(&socketMutex);
    //Successful processing
    return NO_ERROR;
}
Exemplo n.º 15
0
error_t rawSocketProcessIpPacket(NetInterface *interface,
   IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
{
   uint_t i;
   size_t length;
   Socket *socket;
   SocketQueueItem *queueItem;
   NetBuffer *p;

   //Retrieve the length of the raw IP packet
   length = netBufferGetLength(buffer) - offset;

   //Enter critical section
   osAcquireMutex(&socketMutex);

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

      //Raw socket found?
      if(socket->type != SOCKET_TYPE_RAW_IP)
         continue;
      //Check whether the socket is bound to a particular interface
      if(socket->interface && socket->interface != interface)
         continue;

#if (IPV4_SUPPORT == ENABLED)
      //An IPv4 packet was received?
      if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
      {
         //Check protocol field
         if(socket->protocol != pseudoHeader->ipv4Data.protocol)
            continue;
         //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))
      {
         //Check protocol field
         if(socket->protocol != pseudoHeader->ipv6Data.nextHeader)
            continue;
         //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;
   }

   //Drop incoming packet if no matching socket was found
   if(i >= SOCKET_MAX_COUNT)
   {
      //Leave critical section
      osReleaseMutex(&socketMutex);
      //Unreachable protocol...
      return ERROR_PROTOCOL_UNREACHABLE;
   }

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

      //Successful memory allocation?
      if(p != NULL)
      {
         //Point to the newly created item
         queueItem = netBufferAt(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 >= RAW_SOCKET_RX_QUEUE_SIZE)
      {
         //Leave critical section
         osReleaseMutex(&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 = netBufferAlloc(sizeof(SocketQueueItem) + length);

      //Successful memory allocation?
      if(p != NULL)
      {
         //Add the newly created item to the queue
         queueItem->next = netBufferAt(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
      osReleaseMutex(&socketMutex);
      //Return error code
      return ERROR_OUT_OF_MEMORY;
   }

   //Initialize next field
   queueItem->next = NULL;
   //Port number is unused
   queueItem->srcPort = 0;

#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 raw IP packet
   queueItem->offset = sizeof(SocketQueueItem);
   //Copy the raw data
   netBufferCopy(queueItem->buffer, queueItem->offset, buffer, offset, length);

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

   //Leave critical section
   osReleaseMutex(&socketMutex);
   //Successful processing
   return NO_ERROR;
}
Exemplo n.º 16
0
int_t bind(int_t s, const sockaddr *addr, int_t addrlen)
{
   error_t error;
   uint16_t port;
   IpAddr ipAddr;
   Socket *socket;

   //Make sure the socket descriptor is valid
   if(s < 0 || s >= SOCKET_MAX_COUNT)
   {
      socketError(NULL, ERROR_INVALID_SOCKET);
      return SOCKET_ERROR;
   }

   //Point to the socket structure
   socket = &socketTable[s];

   //Check the length of the address
   if(addrlen < sizeof(sockaddr))
   {
      //Report an error
      socketError(socket, ERROR_INVALID_PARAMETER);
      return SOCKET_ERROR;
   }

#if (IPV4_SUPPORT == ENABLED)
   //IPv4 address?
   if(addr->sa_family == AF_INET && addrlen >= sizeof(sockaddr_in))
   {
      //Point to the IPv4 address information
      sockaddr_in *sa = (sockaddr_in *) addr;
      //Get port number
      port = ntohs(sa->sin_port);

      //Copy IPv4 address
      if(sa->sin_addr.s_addr == INADDR_ANY)
      {
         ipAddr.length = 0;
         ipAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
      }
      else
      {
         ipAddr.length = sizeof(Ipv4Addr);
         ipAddr.ipv4Addr = sa->sin_addr.s_addr;
      }
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   //IPv6 address?
   if(addr->sa_family == AF_INET6 && addrlen >= sizeof(sockaddr_in6))
   {
      //Point to the IPv6 address information
      sockaddr_in6 *sa = (sockaddr_in6 *) addr;
      //Get port number
      port = ntohs(sa->sin6_port);

      //Copy IPv6 address
      if(ipv6CompAddr(sa->sin6_addr.s6_addr, &in6addr_any))
      {
         ipAddr.length = 0;
         ipAddr.ipv6Addr = IPV6_UNSPECIFIED_ADDR;
      }
      else
      {
         ipAddr.length = sizeof(Ipv6Addr);
         ipv6CopyAddr(&ipAddr.ipv6Addr, sa->sin6_addr.s6_addr);
      }
   }
   else
#endif
   //Invalid address?
   {
      //Report an error
      socketError(socket, ERROR_INVALID_PARAMETER);
      return SOCKET_ERROR;
   }

   //Associate the local address with the socket
   error = socketBind(socket, &ipAddr, port);

   //Any error to report?
   if(error)
   {
      socketError(socket, error);
      return SOCKET_ERROR;
   }

   //Successful processing
   return SOCKET_SUCCESS;
}
Exemplo n.º 17
0
error_t dhcpv6RelayStart(Dhcpv6RelayCtx *context, const Dhcpv6RelaySettings *settings)
{
   error_t error;
   uint_t i;
   OsTask *task;

   //Debug message
   TRACE_INFO("Starting DHCPv6 relay agent...\r\n");

   //Ensure the parameters are valid
   if(!context || !settings)
      return ERROR_INVALID_PARAMETER;
   //The pointer to the network-facing interface shall be valid
   if(!settings->serverInterface)
      return ERROR_INVALID_INTERFACE;
   //Check the number of client-facing interfaces
   if(!settings->clientInterfaceCount)
      return ERROR_INVALID_PARAMETER;
   if(settings->clientInterfaceCount >= DHCPV6_RELAY_MAX_CLIENT_IF)
      return ERROR_INVALID_PARAMETER;

   //Loop through the client-facing interfaces
   for(i = 0; i < settings->clientInterfaceCount; i++)
   {
      //A valid pointer is required for each interface
      if(!settings->clientInterface[i])
         return ERROR_INVALID_INTERFACE;
   }

   //Check the address to be used when forwarding messages to the server
   if(ipv6CompAddr(&settings->serverAddress, &IPV6_UNSPECIFIED_ADDR))
      return ERROR_INVALID_ADDRESS;

   //Clear the DHCPv6 relay agent context
   memset(context, 0, sizeof(Dhcpv6RelayCtx));

   //Save the network-facing interface
   context->serverInterface = settings->serverInterface;
   //Save the number of client-facing interfaces
   context->clientInterfaceCount = settings->clientInterfaceCount;
   //Save all the client-facing interfaces
   for(i = 0; i < context->clientInterfaceCount; i++)
      context->clientInterface[i] = settings->clientInterface[i];

   //Save the address to be used when relaying client messages to the server
   context->serverAddress = settings->serverAddress;

   //Join the All_DHCP_Relay_Agents_and_Servers multicast group
   //for each client-facing interface
   error = dhcpv6RelayJoinMulticastGroup(context);
   //Any error to report?
   if(error) return error;

   //Start of exception handling block
   do
   {
      //Open a UDP socket to handle the network-facing interface
      context->serverSocket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP);
      //Failed to open socket?
      if(!context->serverSocket)
      {
         //Report an error
         error = ERROR_OPEN_FAILED;
         //Stop processing
         break;
      }

      //Explicitly associate the socket with the relevant interface
      error = socketBindToInterface(context->serverSocket, context->serverInterface);
      //Unable to bind the socket to the desired interface?
      if(error) break;

      //Relay agents listen for DHCPv6 messages on UDP port 547
      error = socketBind(context->serverSocket, &IP_ADDR_ANY, DHCPV6_SERVER_PORT);
      //Unable to bind the socket to the desired port?
      if(error) break;

      //Only accept datagrams with source port number 547
      error = socketConnect(context->serverSocket, &IP_ADDR_ANY, DHCPV6_SERVER_PORT);
      //Any error to report?
      if(error) break;

      //If the relay agent relays messages to the All_DHCP_Servers address
      //or other multicast addresses, it sets the Hop Limit field to 32

      //Loop through the client-facing interfaces
      for(i = 0; i < context->clientInterfaceCount; i++)
      {
         //Open a UDP socket to handle the current interface
         context->clientSocket[i] = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP);
         //Failed to open socket?
         if(!context->clientSocket[i])
         {
            //Report an error
            error = ERROR_OPEN_FAILED;
            //Stop processing
            break;
         }

         //Explicitly associate the socket with the relevant interface
         error = socketBindToInterface(context->clientSocket[i], context->clientInterface[i]);
         //Unable to bind the socket to the desired interface?
         if(error) break;

         //Relay agents listen for DHCPv6 messages on UDP port 547
         error = socketBind(context->clientSocket[i], &IP_ADDR_ANY, DHCPV6_SERVER_PORT);
         //Unable to bind the socket to the desired port?
         if(error) break;

         //Only accept datagrams with source port number 546
         error = socketConnect(context->clientSocket[i], &IP_ADDR_ANY, DHCPV6_CLIENT_PORT);
         //Any error to report?
         if(error) break;
      }

      //Propagate exception if necessary...
      if(error) break;

      //Create event objects
      context->event = osEventCreate(FALSE);
      context->ackEvent = osEventCreate(FALSE);

      //Out of resources?
      if(context->event == OS_INVALID_HANDLE ||
         context->ackEvent == OS_INVALID_HANDLE)
      {
         //Report an error
         error = ERROR_OUT_OF_RESOURCES;
         //Stop processing
         break;
      }

      //The DHCPv6 relay agent is now running
      context->running = TRUE;

      //Start the DHCPv6 relay agent service
      task = osTaskCreate("DHCPv6 Relay", dhcpv6RelayTask,
         context, DHCPV6_RELAY_STACK_SIZE, DHCPV6_RELAY_PRIORITY);

      //Unable to create the task?
      if(task == OS_INVALID_HANDLE)
         error = ERROR_OUT_OF_RESOURCES;

      //End of exception handling block
   } while(0);

   //Did we encounter an error?
   if(error)
   {
      //Close the socket associated with the network-facing interface
      socketClose(context->serverSocket);

      //Close the socket associated with each client-facing interface
      for(i = 0; i < context->clientInterfaceCount; i++)
         socketClose(context->clientSocket[i]);

      //Leave the All_DHCP_Relay_Agents_and_Servers multicast group
      //for each client-facing interface
      dhcpv6RelayLeaveMulticastGroup(context);

      //Close event objects
      osEventClose(context->event);
      osEventClose(context->ackEvent);
   }

   //Return status code
   return error;
}