Beispiel #1
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);
}
Beispiel #2
0
error_t tlsSaveSession(const TlsContext *context, TlsSession *session)
{
   //Check parameters
   if(context == NULL || session == NULL)
      return ERROR_INVALID_PARAMETER;

   //Invalid session parameters?
   if(!context->sessionIdLength || !context->cipherSuite)
      return ERROR_FAILURE;

   //Save session identifier
   memcpy(session->id, context->sessionId, context->sessionIdLength);
   session->idLength = context->sessionIdLength;

   //Get current time
   session->timestamp = osGetTickCount();

   //Negotiated cipher suite and compression method
   session->cipherSuite = context->cipherSuite;
   session->compressionMethod = context->compressionMethod;

   //Save master secret
   memcpy(session->masterSecret, context->masterSecret, 48);

   //Successful processing
   return NO_ERROR;
}
Beispiel #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);
}
Beispiel #4
0
bool_t osTimerElapsed(OsTimer *timer)
{
   if(!timer->running)
      return FALSE;

   if(timeCompare(osGetTickCount(), timer->startTime + timer->interval) >= 0)
      return TRUE;
   else
      return FALSE;
}
Beispiel #5
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;
}
Beispiel #6
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);
}
Beispiel #7
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);
}
Beispiel #8
0
error_t ndpResolve(NetInterface *interface, const Ipv6Addr *ipAddr, MacAddr *macAddr)
{
   NdpCacheEntry *entry;

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

   //Search the ndpCacheMutex cache for the specified IPv6 address
   entry = ndpFindEntry(interface, ipAddr);

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

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

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

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

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

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

   //Record the IPv6 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 a multicast Neighbor Solicitation message
   ndpSendNeighborSol(interface, ipAddr);

   //Save the time at which the message was sent
   entry->timestamp = osGetTickCount();
   //Set timeout value
   entry->timeout = NDP_RETRANS_TIMER;
   //Enter INCOMPLETE state
   entry->state = NDP_STATE_INCOMPLETE;

   //Release exclusive access to Neighbor cache
   osMutexRelease(interface->ndpCacheMutex);

   //The address resolution is in progress
   return ERROR_IN_PROGRESS;
}
Beispiel #9
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);
}
Beispiel #10
0
void tcpChargenConnectionTask(void *param)
{
   error_t error;
   //size_t i;
   size_t n;
   //size_t offset;
   size_t byteCount;
   systime_t startTime;
   systime_t duration;
   ChargenServiceContext *context;

   //Get a pointer to the context
   context = (ChargenServiceContext *) param;
   //Get current time
   startTime = osGetTickCount();

   //Initialize counters
   byteCount = 0;
   //offset = 0;

   //Once a connection is established a stream of data is sent out
   //the connection (and any data received is thrown away). This
   //continues until the calling user terminates the connection
   while(1)
   {
      //Format output data
      /*for(i = 0; i < CHARGEN_BUFFER_SIZE; i += 95)
      {
         //Calculate the length of the current line
         n = min(CHARGEN_BUFFER_SIZE - i, 95);
         //Copy character pattern
         memcpy(context->buffer + i, pattern + offset, n);
      }

      //Update offset
      offset += CHARGEN_BUFFER_SIZE + 95 - i;
      //Wrap around if necessary
      if(offset >= 95) offset = 0;*/

      //Send data
      error = socketSend(context->socket, context->buffer, CHARGEN_BUFFER_SIZE, &n, 0);
      //Any error to report?
      if(error) break;

      //Total number of bytes sent
      byteCount += n;
   }

   //Graceful shutdown
   socketShutdown(context->socket, SOCKET_SD_BOTH);
   //Compute total duration
   duration = osGetTickCount() - startTime;
   //Avoid division by zero...
   if(!duration) duration = 1;

   //Debug message
   TRACE_INFO("Chargen service: %" PRIuSIZE " bytes "
      "sent in %" PRIu32 " ms (%" PRIu32 " kBps, %" PRIu32 " kbps)\r\n",
      byteCount, duration, byteCount / duration, (byteCount * 8) / duration);

   //Close socket
   socketClose(context->socket);
   //Release previously allocated memory
   osMemFree(context);

   //Kill ourselves
   osTaskDelete(NULL);
}
Beispiel #11
0
//The following functions are deprecated
void osTimerStart(OsTimer *timer, systime_t delay)
{
   timer->startTime = osGetTickCount();
   timer->interval = delay;
   timer->running = TRUE;
}
Beispiel #12
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 = osGetTickCount();
         //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;
}
Beispiel #13
0
error_t ping(NetInterface *interface, const IpAddr *ipAddr, time_t timeout, time_t *rtt)
{
   error_t error;
   uint_t i;
   size_t length;
   uint16_t identifier;
   uint16_t sequenceNumber;
   time_t startTime;
   time_t roundTripTime;
   Socket *socket;
   IcmpEchoMessage *message;

   //Debug message
   TRACE_INFO("Pinging %s with 64 bytes of data...\r\n", ipAddrToString(ipAddr, NULL));

   //Length of the complete ICMP message including header and data
   length = sizeof(IcmpEchoMessage) + PING_DATA_SIZE;

   //Allocate memory buffer to hold an ICMP message
   message = osMemAlloc(length);
   //Failed to allocate memory?
   if(!message) return ERROR_OUT_OF_MEMORY;

   //Identifier field is used to help matching requests and replies
   identifier = rand();
   //Sequence Number field is increment each time an Echo Request is sent
   sequenceNumber = osAtomicInc16(&pingSequenceNumber);

   //Format ICMP Echo Request message
   message->type = ICMP_TYPE_ECHO_REQUEST;
   message->code = 0;
   message->checksum = 0;
   message->identifier = identifier;
   message->sequenceNumber = sequenceNumber;

   //Copy data
   for(i = 0; i < PING_DATA_SIZE; i++)
      message->data[i] = i;

#if (IPV4_SUPPORT == ENABLED)
   //Target address is an IPv4 address?
   if(ipAddr->length == sizeof(Ipv4Addr))
   {
      Ipv4Addr srcIpAddr;

      //Select the source IPv4 address and the relevant network
      //interface to use when pinging the specified host
      error = ipv4SelectSourceAddr(&interface, ipAddr->ipv4Addr, &srcIpAddr);

      //Any error to report?
      if(error)
      {
         //Free previously allocated memory
         osMemFree(message);
         //Return the corresponding error code
         return error;
      }

      //ICMP Echo Request message
      message->type = ICMP_TYPE_ECHO_REQUEST;
      //Message checksum calculation
      message->checksum = ipCalcChecksum(message, length);

      //Open a raw socket
      socket = socketOpen(SOCKET_TYPE_RAW, SOCKET_PROTOCOL_ICMP);
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   //Target address is an IPv6 address?
   if(ipAddr->length == sizeof(Ipv6Addr))
   {
      Ipv6PseudoHeader pseudoHeader;

      //Select the source IPv6 address and the relevant network
      //interface to use when pinging the specified host
      error = ipv6SelectSourceAddr(&interface, &ipAddr->ipv6Addr, &pseudoHeader.srcAddr);

      //Any error to report?
      if(error)
      {
         //Free previously allocated memory
         osMemFree(message);
         //Return the corresponding error code
         return error;
      }

      //ICMPv6 Echo Request message
      message->type = ICMPV6_TYPE_ECHO_REQUEST;
      //Format IPv6 pseudo header
      pseudoHeader.destAddr = ipAddr->ipv6Addr;
      pseudoHeader.length = htonl(length);
      pseudoHeader.reserved = 0;
      pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;

      //Message checksum calculation
      message->checksum = ipCalcUpperLayerChecksum(
         &pseudoHeader, sizeof(Ipv6PseudoHeader), message, length);

      //Open a raw socket
      socket = socketOpen(SOCKET_TYPE_RAW, SOCKET_PROTOCOL_ICMPV6);
   }
   else
#endif
   //Target address is not valid?
   {
      //Free previously allocated memory
      osMemFree(message);
      //Report an error
      return ERROR_INVALID_ADDRESS;
   }

   //Failed to open socket?
   if(!socket)
   {
      //Free previously allocated memory
      osMemFree(message);
      //Report an error
      return ERROR_OPEN_FAILED;
   }

   //Associate the newly created socket with the relevant interface
   error = socketBindToInterface(socket, interface);

   //Unable to bind the socket to the desired interface?
   if(error)
   {
      //Free previously allocated memory
      osMemFree(message);
      //Close socket
      socketClose(socket);
      //Return status code
      return error;
   }

   //Connect the socket to the target host
   error = socketConnect(socket, ipAddr, 0);

   //Any error to report?
   if(error)
   {
      //Free previously allocated memory
      osMemFree(message);
      //Close socket
      socketClose(socket);
      //Return status code
      return error;
   }

   //Send Echo Request message
   error = socketSend(socket, message, length, NULL, 0);

   //Failed to send message ?
   if(error)
   {
      //Free previously allocated memory
      osMemFree(message);
      //Close socket
      socketClose(socket);
      //Return status code
      return error;
   }

   //Save the time at which the request was sent
   startTime = osGetTickCount();

   //Timeout value exceeded?
   while((osGetTickCount() - startTime) < timeout)
   {
      //Adjust receive timeout
      error = socketSetTimeout(socket, timeout);
      //Any error to report?
      if(error) break;

      //Wait for an incoming ICMP message
      error = socketReceive(socket, message,
         sizeof(IcmpEchoMessage) + PING_DATA_SIZE, &length, 0);
      //Any error to report?
      if(error) break;

      //Check message length
      if(length != (sizeof(IcmpEchoMessage) + PING_DATA_SIZE))
         continue;
      //Verify message type
      if(ipAddr->length == sizeof(Ipv4Addr) && message->type != ICMP_TYPE_ECHO_REPLY)
         continue;
      if(ipAddr->length == sizeof(Ipv6Addr) && message->type != ICMPV6_TYPE_ECHO_REPLY)
         continue;
      //Response identifier matches request identifier?
      if(message->identifier != identifier)
         continue;
      //Make sure the sequence number is correct
      if(message->sequenceNumber != sequenceNumber)
         continue;

      //Loop through data field
      for(i = 0; i < PING_DATA_SIZE; i++)
      {
         //Compare received data against expected data
         if(message->data[i] != i) break;
      }

      //Valid Echo Reply message received?
      if(i == PING_DATA_SIZE)
      {
         //Calculate round-trip time
         roundTripTime = osGetTickCount() - startTime;
         //Debug message
         TRACE_INFO("Echo received (round-trip time = %ums)...\r\n", roundTripTime);

         //Free previously allocated memory
         osMemFree(message);
         //Close socket
         socketClose(socket);

         //Return round-trip time
         if(rtt) *rtt = roundTripTime;

         //No error to report
         return NO_ERROR;
      }
   }

   //Debug message
   TRACE_INFO("No echo received!\r\n");
   //Free previously allocated memory
   osMemFree(message);
   //Close socket
   socketClose(socket);

   //No Echo Reply received from host...
   return ERROR_NO_RESPONSE;
}
Beispiel #14
0
void tcpTick(void)
{
   error_t error;
   uint_t i;
   uint_t n;
   uint_t u;

   //Enter critical section
   osMutexAcquire(socketMutex);

   //Loop through opened sockets
   for(i = 0; i < SOCKET_MAX_COUNT; i++)
   {
      //Shortcut to the current socket
      Socket *socket = socketTable + i;
      //Check socket type
      if(socket->type != SOCKET_TYPE_STREAM)
         continue;
      //Check the current state of the TCP state machine
      if(socket->state == TCP_STATE_CLOSED)
         continue;

      //Is there any packet in the retransmission queue?
      if(socket->retransmitQueue != NULL)
      {
         //Retransmission timeout?
         if(osTimerElapsed(&socket->retransmitTimer))
         {
            //When a TCP sender detects segment loss using the retransmission
            //timer and the given segment has not yet been resent by way of
            //the retransmission timer, the value of ssthresh must be updated
            if(!socket->retransmitCount)
            {
               //Amount of data that has been sent but not yet acknowledged
               uint_t flightSize = socket->sndNxt - socket->sndUna;
               //Adjust ssthresh value
               socket->ssthresh = max(flightSize / 2, 2 * socket->mss);
            }

            //Furthermore, upon a timeout cwnd must be set to no more than
            //the loss window, LW, which equals 1 full-sized segment
            socket->cwnd = min(TCP_LOSS_WINDOW * socket->mss, socket->txBufferSize);

            //Make sure the maximum number of retransmissions has not been reached
            if(socket->retransmitCount < TCP_MAX_RETRIES)
            {
               //Debug message
               TRACE_INFO("%s: TCP segment retransmission #%u (%u data bytes)...\r\n",
                  timeFormat(osGetTickCount()), socket->retransmitCount + 1, socket->retransmitQueue->length);

               //Retransmit the earliest segment that has not been
               //acknowledged by the TCP receiver
               tcpRetransmitSegment(socket);

               //Use exponential back-off algorithm to calculate the new RTO
               socket->rto = min(socket->rto * 2, TCP_MAX_RTO);
               //Restart retransmission timer
               osTimerStart(&socket->retransmitTimer, socket->rto);
               //Increment retransmission counter
               socket->retransmitCount++;
            }
            else
            {
               //The maximum number of retransmissions has been exceeded
               tcpChangeState(socket, TCP_STATE_CLOSED);
               //Turn off the retransmission timer
               osTimerStop(&socket->retransmitTimer);
            }

            //TCP must use Karn's algorithm for taking RTT samples. That is, RTT
            //samples must not be made using segments that were retransmitted
            socket->rttBusy = FALSE;
         }
      }

      //Check the current state of the TCP state machine
      if(socket->state == TCP_STATE_CLOSED)
         continue;

      //The persist timer is used when the remote host advertises
      //a window size of zero
      if(!socket->sndWnd && socket->wndProbeInterval)
      {
         //Time to send a new probe?
         if(osTimerElapsed(&socket->persistTimer))
         {
            //Make sure the maximum number of retransmissions has not been reached
            if(socket->wndProbeCount < TCP_MAX_RETRIES)
            {
               //Debug message
               TRACE_INFO("%s: TCP zero window probe #%u...\r\n",
                  timeFormat(osGetTickCount()), socket->wndProbeCount + 1);

               //Zero window probes usually have the sequence number one less than expected
               tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt - 1, socket->rcvNxt, 0, FALSE);
               //The interval between successive probes should be increased exponentially
               socket->wndProbeInterval = min(socket->wndProbeInterval * 2, TCP_MAX_PROBE_INTERVAL);
               //Restart the persist timer
               osTimerStart(&socket->persistTimer, socket->wndProbeInterval);
               //Increment window probe counter
               socket->wndProbeCount++;
            }
            else
            {
               //Enter CLOSED state
               tcpChangeState(socket, TCP_STATE_CLOSED);
            }
         }
      }

      //To avoid a deadlock, it is necessary to have a timeout to force
      //transmission of data, overriding the SWS avoidance algorithm. In
      //practice, this timeout should seldom occur (see RFC 1122 4.2.3.4)
      if(socket->state == TCP_STATE_ESTABLISHED || socket->state == TCP_STATE_CLOSE_WAIT)
      {
         //The override timeout occurred?
         if(socket->sndUser && osTimerElapsed(&socket->overrideTimer))
         {
            //The amount of data that can be sent at any given time is
            //limited by the receiver window and the congestion window
            n = min(socket->sndWnd, socket->cwnd);
            n = min(n, socket->txBufferSize);

            //Retrieve the size of the usable window
            u = n - (socket->sndNxt - socket->sndUna);

            //Send as much data as possible
            while(socket->sndUser > 0)
            {
               //The usable window size may become zero or negative,
               //preventing packet transmission
               if((int_t) u <= 0) break;

               //Calculate the number of bytes to send at a time
               n = min(u, socket->sndUser);
               n = min(n, socket->mss);

               //Send TCP segment
               error = tcpSendSegment(socket, TCP_FLAG_PSH | TCP_FLAG_ACK,
                  socket->sndNxt, socket->rcvNxt, n, TRUE);
               //Failed to send TCP segment?
               if(error) break;

               //Advance SND.NXT pointer
               socket->sndNxt += n;
               //Adjust the number of bytes buffered but not yet sent
               socket->sndUser -= n;
            }

            //Check whether the transmitter can accept more data
            tcpUpdateEvents(socket);

            //Restart override timer if necessary
            if(socket->sndUser > 0)
               osTimerStart(&socket->overrideTimer, TCP_OVERRIDE_TIMEOUT);
         }
      }

      //The FIN-WAIT-2 timer prevents the connection
      //from staying in the FIN-WAIT-2 state forever
      if(socket->state == TCP_STATE_FIN_WAIT_2)
      {
         //Maximum FIN-WAIT-2 time has elapsed?
         if(osTimerElapsed(&socket->finWait2Timer))
         {
            //Debug message
            TRACE_WARNING("TCP FIN-WAIT-2 timer elapsed...\r\n");
            //Enter CLOSED state
            tcpChangeState(socket, TCP_STATE_CLOSED);
         }
      }

      //TIME-WAIT timer
      if(socket->state == TCP_STATE_TIME_WAIT)
      {
         //2MSL time has elapsed?
         if(osTimerElapsed(&socket->timeWaitTimer))
         {
            //Debug message
            TRACE_WARNING("TCP 2MSL timer elapsed (socket %u)...\r\n", i);
            //Enter CLOSED state
            tcpChangeState(socket, TCP_STATE_CLOSED);

            //Dispose the socket if the user does not have the ownership anymore
            if(!socket->ownedFlag)
            {
               //Delete the TCB
               tcpDeleteControlBlock(socket);
               //Mark the socket as closed
               socket->type = SOCKET_TYPE_UNUSED;
            }
         }
      }
   }

   //Leave critical section
   osMutexRelease(socketMutex);
}
Beispiel #15
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;

   //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
      osMutexAcquire(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 = osGetTickCount();

            //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 = osGetTickCount();
                  //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 = osGetTickCount();
                     //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 = osGetTickCount();
               //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 = osGetTickCount();
                  //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
   osMutexRelease(interface->ndpCacheMutex);
}
Beispiel #16
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) &&
      !ipv6CompAddr(&message->targetAddr, &interface->ipv6Config.globalAddr))
   {
      //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
      osMutexAcquire(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 = osGetTickCount();
            //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 = osGetTickCount();
            //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 = osGetTickCount();
               //Enter the STALE state
               entry->state = NDP_STATE_STALE;
            }
         }
      }

      //Release exclusive access to Neighbor cache
      osMutexRelease(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);
}
Beispiel #17
0
void ndpTick(NetInterface *interface)
{
   uint_t i;
   systime_t time;
   NdpCacheEntry *entry;

   //Get current time
   time = osGetTickCount();

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

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

      //INCOMPLETE state?
      if(entry->state == NDP_STATE_INCOMPLETE)
      {
         //The Neighbor Solicitation 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 < NDP_MAX_MULTICAST_SOLICIT)
            {
               //Retransmit a multicast Neighbor Solicitation message
               ndpSendNeighborSol(interface, &entry->ipAddr);

               //Save the time at which the message was sent
               entry->timestamp = time;
               //Set timeout value
               entry->timeout = NDP_RETRANS_TIMER;
            }
            else
            {
               //Drop packets that are waiting for address resolution
               ndpFlushQueuedPackets(interface, entry);
               //The entry should be deleted since address resolution has failed
               entry->state = NDP_STATE_NONE;
            }
         }
      }
      //REACHABLE state?
      else if(entry->state == NDP_STATE_REACHABLE)
      {
         //Periodically time out Neighbor cache entries
         if((time - entry->timestamp) >= entry->timeout)
         {
            //Save current time
            entry->timestamp = osGetTickCount();
            //Enter STALE state
            entry->state = NDP_STATE_STALE;
         }
      }
      //DELAY state?
      else if(entry->state == NDP_STATE_DELAY)
      {
         //Wait for the specified delay before sending the first probe
         if((time - entry->timestamp) >= entry->timeout)
         {
            //Send a unicast Neighbor Solicitation message
            ndpSendNeighborSol(interface, &entry->ipAddr);

            //Save the time at which the message was sent
            entry->timestamp = time;
            //Set timeout value
            entry->timeout = NDP_RETRANS_TIMER;
            //Switch to the PROBE state
            entry->state = NDP_STATE_PROBE;
         }
      }
      //PROBE state?
      else if(entry->state == NDP_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 < NDP_MAX_UNICAST_SOLICIT)
            {
               //Send a unicast Neighbor Solicitation message
               ndpSendNeighborSol(interface, &entry->ipAddr);

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

   //Release exclusive access to Neighbor cache
   osMutexRelease(interface->ndpCacheMutex);
}
Beispiel #18
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;
}
Beispiel #19
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);
}
Beispiel #20
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);
}
Beispiel #21
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;
}
Beispiel #22
0
void tcpEchoConnectionTask(void *param)
{
   error_t error;
   uint_t n;
   uint_t writeIndex;
   uint_t readIndex;
   uint_t bufferLength;
   uint_t rxByteCount;
   uint_t txByteCount;
   time_t startTime;
   time_t duration;
   SocketEventDesc eventDesc;
   EchoServiceContext *context;

   //Get a pointer to the context
   context = (EchoServiceContext *) param;
   //Get current time
   startTime = osGetTickCount();

   //Initialize variables
   writeIndex = 0;
   readIndex = 0;
   bufferLength = 0;
   rxByteCount = 0;
   txByteCount = 0;

   //Main loop
   while(1)
   {
      //Buffer is empty?
      if(!bufferLength)
      {
         //Get notified when the socket is readable
         eventDesc.socket = context->socket;
         eventDesc.eventMask = SOCKET_EVENT_RX_READY;
      }
      //Buffer is not empty of full?
      else if(bufferLength < ECHO_BUFFER_SIZE)
      {
         //Get notified when the socket is readable or writable
         eventDesc.socket = context->socket;
         eventDesc.eventMask = SOCKET_EVENT_RX_READY | SOCKET_EVENT_TX_READY;
      }
      //Buffer is full?
      else
      {
         //Get notified when the socket is writable
         eventDesc.socket = context->socket;
         eventDesc.eventMask = SOCKET_EVENT_TX_READY;
      }

      //Wait for an event to be fired
      error = socketPoll(&eventDesc, 1, NULL, ECHO_TIMEOUT);
      //Timeout error or any other exception to report?
      if(error) break;

      //The socket is available for reading
      if(eventDesc.eventFlags & SOCKET_EVENT_RX_READY)
      {
         //Read as much data as possible
         n = min(ECHO_BUFFER_SIZE - writeIndex, ECHO_BUFFER_SIZE - bufferLength);

         //Read incoming data
         error = socketReceive(context->socket, context->buffer + writeIndex, n, &n, 0);
         //Any error to report?
         if(error) break;

         //Increment write index
         writeIndex += n;
         //Wrap around if necessary
         if(writeIndex >= ECHO_BUFFER_SIZE)
            writeIndex = 0;

         //Increment buffer length
         bufferLength += n;
         //Total number of bytes received
         rxByteCount += n;
      }

      //The socket is available for writing?
      if(eventDesc.eventFlags & SOCKET_EVENT_TX_READY)
      {
         //Write as much data as possible
         n = min(ECHO_BUFFER_SIZE - readIndex, bufferLength);

         //Send data back to the client
         error = socketSend(context->socket, context->buffer + readIndex, n, &n, 0);
         //Any error to report?
         if(error && error != ERROR_TIMEOUT) break;

         //Increment read index
         readIndex += n;
         //Wrap around if necessary
         if(readIndex >= ECHO_BUFFER_SIZE)
            readIndex = 0;

         //Update buffer length
         bufferLength -= n;
         //Total number of bytes sent
         txByteCount += n;
      }
   }

   //Adjust timeout value
   socketSetTimeout(context->socket, ECHO_TIMEOUT);
   //Graceful shutdown
   socketShutdown(context->socket, SOCKET_SD_BOTH);
   //Compute total duration
   duration = osGetTickCount() - startTime;

   //Debug message
   TRACE_INFO("Echo service: %u bytes received, %u bytes sent in %lu ms\r\n",
      rxByteCount, txByteCount, duration);

   //Close socket
   socketClose(context->socket);
   //Release previously allocated memory
   osMemFree(context);

   //Kill ourselves
   osTaskDelete(NULL);
}
Beispiel #23
0
error_t httpServerCgiCallback(HttpConnection *connection, const char_t *param)
{
   static uint_t pageCounter = 0;
   uint_t length;

   //Underlying network interface
   NetInterface *interface = connection->socket->interface;

   //Check parameter name
   if(!strcasecmp(param, "PAGE_COUNTER"))
   {
      pageCounter++;
      sprintf(connection->buffer, "%u time%s", pageCounter, (pageCounter >= 2) ? "s" : "");
   }
   else if(!strcasecmp(param, "BOARD_NAME"))
   {
      strcpy(connection->buffer, "STM3240G-EVAL");
   }
   else if(!strcasecmp(param, "SYSTEM_TIME"))
   {
      time_t time = osGetTickCount();
      sprintf(connection->buffer, "%lus %03lums", time / 1000, time % 1000);
   }
   else if(!strcasecmp(param, "MAC_ADDR"))
   {
      macAddrToString(&interface->macAddr, connection->buffer);
   }
   else if(!strcasecmp(param, "IPV4_ADDR"))
   {
      ipv4AddrToString(interface->ipv4Config.addr, connection->buffer);
   }
   else if(!strcasecmp(param, "SUBNET_MASK"))
   {
      ipv4AddrToString(interface->ipv4Config.subnetMask, connection->buffer);
   }
   else if(!strcasecmp(param, "DEFAULT_GATEWAY"))
   {
      ipv4AddrToString(interface->ipv4Config.defaultGateway, connection->buffer);
   }
   else if(!strcasecmp(param, "IPV4_PRIMARY_DNS"))
   {
      ipv4AddrToString(interface->ipv4Config.dnsServer[0], connection->buffer);
   }
   else if(!strcasecmp(param, "IPV4_SECONDARY_DNS"))
   {
      ipv4AddrToString(interface->ipv4Config.dnsServer[1], connection->buffer);
   }
#if (IPV6_SUPPORT == ENABLED)
   else if(!strcasecmp(param, "LINK_LOCAL_ADDR"))
   {
      ipv6AddrToString(&interface->ipv6Config.linkLocalAddr, connection->buffer);
   }
   else if(!strcasecmp(param, "GLOBAL_ADDR"))
   {
      ipv6AddrToString(&interface->ipv6Config.globalAddr, connection->buffer);
   }
   else if(!strcasecmp(param, "IPV6_PREFIX"))
   {
      ipv6AddrToString(&interface->ipv6Config.prefix, connection->buffer);
      length = strlen(connection->buffer);
      sprintf(connection->buffer + length, "/%u", interface->ipv6Config.prefixLength);
   }
   else if(!strcasecmp(param, "ROUTER"))
   {
      ipv6AddrToString(&interface->ipv6Config.router, connection->buffer);
   }
   else if(!strcasecmp(param, "IPV6_PRIMARY_DNS"))
   {
      ipv6AddrToString(&interface->ipv6Config.dnsServer[0], connection->buffer);
   }
   else if(!strcasecmp(param, "IPV6_SECONDARY_DNS"))
   {
      ipv6AddrToString(&interface->ipv6Config.dnsServer[1], connection->buffer);
   }
#endif
   else
   {
      return ERROR_INVALID_TAG;
   }

   //Get the length of the resulting string
   length = strlen(connection->buffer);

   //Send the contents of the specified environment variable
   return httpWriteStream(connection, connection->buffer, length);
}