Beispiel #1
0
void tcpDiscardConnectionTask(void *param)
{
   error_t error;
   size_t n;
   size_t byteCount;
   systime_t startTime;
   systime_t duration;
   DiscardServiceContext *context;

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

   //Total number of bytes received
   byteCount = 0;

   //Main loop
   while(1)
   {
      //Throw away any received datagram...
      error = socketReceive(context->socket, context->buffer, DISCARD_BUFFER_SIZE, &n, 0);
      //Any error to report?
      if(error) break;

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

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

   //Debug message
   TRACE_INFO("Discard service: %" PRIuSIZE " bytes "
      "received 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
   osFreeMem(context);

   //Kill ourselves
   osDeleteTask(NULL);
}
Beispiel #2
0
void ipv6FragTick(NetInterface *interface)
{
   error_t error;
   uint_t i;
   systime_t time;
   Ipv6HoleDesc *hole;

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

   //Get current time
   time = osGetSystemTime();

   //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
   osReleaseMutex(&interface->ipv6FragQueueMutex);
}
error_t sntpSendRequest(SntpClientContext *context)
{
   size_t length;
   NtpHeader *message;

   //Point to the buffer where to format the NTP message
   message = &context->message;

   //Clear NTP message
   memset(message, 0, sizeof(NtpHeader));

   //Format NTP request
   message->vn = NTP_VERSION_3;
   message->mode = NTP_MODE_CLIENT;

   //Time at which the NTP request was sent
   context->t1 = osGetSystemTime();

   //The Transmit Timestamp allows a simple calculation to determine the
   //propagation delay between the server and client and to align the system
   //clock generally within a few tens of milliseconds relative to the server
   message->transmitTimestamp.seconds = 0;
   message->transmitTimestamp.fraction = htonl(context->t1);

   //Length of the NTP request
   length = sizeof(NtpHeader);

   //Debug message
   TRACE_INFO("Sending NTP request message (%" PRIuSIZE " bytes)...\r\n", sizeof(NtpHeader));
   //Dump NTP message
   sntpDumpMessage(message, length);

   //Send NTP request
   return socketSend(context->socket, message, length, NULL, 0);
}
Beispiel #4
0
void chapTick(PppContext *context)
{
   //Check whether the restart timer is running
   if(context->chapFsm.localState == CHAP_STATE_2_CHALLENGE_SENT)
   {
      //Get current time
      systime_t time = osGetSystemTime();

      //Check restart timer
      if((time - context->chapFsm.timestamp) >= CHAP_RESTART_TIMER)
      {
         //Debug message
         TRACE_INFO("\r\nCHAP Timeout event\r\n");

         //Check whether the restart counter is greater than zero
         if(context->chapFsm.restartCounter > 0)
         {
            //Retransmit the Challenge packet
            chapSendChallenge(context);
         }
         else
         {
            //Abort CHAP authentication
            context->chapFsm.localState = CHAP_STATE_0_INITIAL;
            //Authentication failed
            lcpClose(context);
         }
      }
   }
}
Beispiel #5
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 = osGetSystemTime();

   //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 #6
0
error_t mib2GetSysUpTime(const MibObject *object, const uint8_t *oid,
   size_t oidLen, MibVariant *value, size_t *valueLen)
{
   //Get object value
   value->timeTicks = osGetSystemTime() / 10;
   //Successful processing
   return NO_ERROR;
}
Beispiel #7
0
void tcpTimerStart(TcpTimer *timer, systime_t delay)
{
   //Start timer
   timer->startTime = osGetSystemTime();
   timer->interval = delay;

   //The timer is now running...
   timer->running = TRUE;
}
error_t sntpWaitForResponse(SntpClientContext *context, systime_t timeout)
{
   error_t error;
   size_t length;
   systime_t elapsedTime;

   //Time elapsed since the NTP request was sent
   elapsedTime = 0;

   //Keep listening as long as the retransmission timeout has not been reached
   while(elapsedTime < timeout)
   {
      //Adjust receive timeout
      error = socketSetTimeout(context->socket, timeout - elapsedTime);
      //Any error to report?
      if(error) break;

      //Wait for a response from the NTP server
      error = socketReceive(context->socket, &context->message,
         sizeof(NtpHeader), &length, 0);

      //Any datagram received?
      if(!error)
      {
         //Time at which the response was received
         context->t4 = osGetSystemTime();

         //Parse incoming datagram
         error = sntpParseResponse(context, &context->message, length);
         //Valid NTP response message?
         if(!error) return NO_ERROR;
      }

      //Compute the time elapsed since the NTP request was sent
      elapsedTime = osGetSystemTime() - context->t1;
   }

   //The timeout period elapsed
   return ERROR_TIMEOUT;
}
Beispiel #9
0
void lcpZeroRestartCount(PppContext *context)
{
   //Debug message
   TRACE_INFO("LCP Zero-Restart-Count callback\r\n");

   //Zero restart counter
   context->lcpFsm.restartCounter = 0;

   //The receiver of a Terminate-Request should wait for the peer to
   //disconnect, and must not disconnect until at least one Restart
   //time has passed after sending a Terminate-Ack
   context->lcpFsm.timestamp = osGetSystemTime();
}
Beispiel #10
0
bool_t tcpTimerElapsed(TcpTimer *timer)
{
   systime_t time;

   //Check whether the timer is running
   if(!timer->running)
      return FALSE;

   //Get current time
   time = osGetSystemTime();

   //Check whether the specified time interval has elapsed
   if(timeCompare(time, timer->startTime + timer->interval) >= 0)
      return TRUE;
   else
      return FALSE;
}
Beispiel #11
0
void lcpTick(PppContext *context)
{
   //Check whether the restart timer is running
   if(context->lcpFsm.state >= PPP_STATE_4_CLOSING &&
      context->lcpFsm.state <= PPP_STATE_8_ACK_SENT)
   {
      //Get current time
      systime_t time = osGetSystemTime();

      //Check restart timer
      if((time - context->lcpFsm.timestamp) >= PPP_RESTART_TIMER)
      {
         //Debug message
         TRACE_INFO("\r\nLCP Timeout event\r\n");

         //The restart timer is used to restransmit Configure-Request
         //and Terminate-Request packets
         pppTimeoutEvent(context, &context->lcpFsm, &lcpCallbacks);
      }
   }
}
Beispiel #12
0
error_t lcpSendTerminateReq(PppContext *context)
{
   error_t error;

   //Debug message
   TRACE_INFO("LCP Send-Terminate-Request callback\r\n");

   //On transmission, the Identifier field must be changed
   context->lcpFsm.identifier++;

   //Send Terminate-Request packet
   error = pppSendTerminateReq(context, context->lcpFsm.identifier, PPP_PROTOCOL_LCP);

   //The restart counter is decremented each time a Terminate-Request is sent
   if(context->lcpFsm.restartCounter > 0)
      context->lcpFsm.restartCounter--;

   //Save the time at which the packet was sent
   context->lcpFsm.timestamp = osGetSystemTime();

   //Return status code
   return error;
}
Beispiel #13
0
error_t httpServerCgiCallback(HttpConnection *connection,
   const char_t *param)
{
   static uint_t pageCounter = 0;
   uint_t length;
   MacAddr macAddr;
#if (IPV4_SUPPORT == ENABLED)
   Ipv4Addr ipv4Addr;
#endif
#if (IPV6_SUPPORT == ENABLED)
   uint_t n;
   Ipv6Addr ipv6Addr;
#endif

   //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, "SAM7SE-EK");
   }
   else if(!strcasecmp(param, "SYSTEM_TIME"))
   {
      systime_t time = osGetSystemTime();
      formatSystemTime(time, connection->buffer);
   }
   else if(!strcasecmp(param, "MAC_ADDR"))
   {
      netGetMacAddr(interface, &macAddr);
      macAddrToString(&macAddr, connection->buffer);
   }
   else if(!strcasecmp(param, "IPV4_ADDR"))
   {
      ipv4GetHostAddr(interface, &ipv4Addr);
      ipv4AddrToString(ipv4Addr, connection->buffer);
   }
   else if(!strcasecmp(param, "SUBNET_MASK"))
   {
      ipv4GetSubnetMask(interface, &ipv4Addr);
      ipv4AddrToString(ipv4Addr, connection->buffer);
   }
   else if(!strcasecmp(param, "DEFAULT_GATEWAY"))
   {
      ipv4GetDefaultGateway(interface, &ipv4Addr);
      ipv4AddrToString(ipv4Addr, connection->buffer);
   }
   else if(!strcasecmp(param, "IPV4_PRIMARY_DNS"))
   {
      ipv4GetDnsServer(interface, 0, &ipv4Addr);
      ipv4AddrToString(ipv4Addr, connection->buffer);
   }
   else if(!strcasecmp(param, "IPV4_SECONDARY_DNS"))
   {
      ipv4GetDnsServer(interface, 1, &ipv4Addr);
      ipv4AddrToString(ipv4Addr, connection->buffer);
   }
#if (IPV6_SUPPORT == ENABLED)
   else if(!strcasecmp(param, "LINK_LOCAL_ADDR"))
   {
      ipv6GetLinkLocalAddr(interface, &ipv6Addr);
      ipv6AddrToString(&ipv6Addr, connection->buffer);
   }
   else if(!strcasecmp(param, "GLOBAL_ADDR"))
   {
      ipv6GetGlobalAddr(interface, 0, &ipv6Addr);
      ipv6AddrToString(&ipv6Addr, connection->buffer);
   }
   else if(!strcasecmp(param, "IPV6_PREFIX"))
   {
      ipv6GetPrefix(interface, 0, &ipv6Addr, &n);
      ipv6AddrToString(&ipv6Addr, connection->buffer);
      length = strlen(connection->buffer);
      sprintf(connection->buffer + length, "/%u", n);
   }
   else if(!strcasecmp(param, "ROUTER"))
   {
      ipv6GetDefaultRouter(interface, 0, &ipv6Addr);
      ipv6AddrToString(&ipv6Addr, connection->buffer);
   }
   else if(!strcasecmp(param, "IPV6_PRIMARY_DNS"))
   {
      ipv6GetDnsServer(interface, 0, &ipv6Addr);
      ipv6AddrToString(&ipv6Addr, connection->buffer);
   }
   else if(!strcasecmp(param, "IPV6_SECONDARY_DNS"))
   {
      ipv6GetDnsServer(interface, 1, &ipv6Addr);
      ipv6AddrToString(&ipv6Addr, 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);
}
error_t nbnsResolve(NetInterface *interface, const char_t *name, IpAddr *ipAddr)
{
   error_t error;
   DnsCacheEntry *entry;

#if (NET_RTOS_SUPPORT == ENABLED)
   systime_t delay;

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

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

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

   //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 = HOST_TYPE_IPV4;
      entry->protocol = HOST_NAME_RESOLVER_NBNS;
      entry->interface = interface;

      //Initialize retransmission counter
      entry->retransmitCount = NBNS_CLIENT_MAX_RETRIES;
      //Send NBNS query
      error = nbnsSendQuery(entry);

      //NBNS message successfully sent?
      if(!error)
      {
         //Save the time at which the query message was sent
         entry->timestamp = osGetSystemTime();
         //Set timeout value
         entry->timeout = NBNS_CLIENT_INIT_TIMEOUT;
         entry->maxTimeout = NBNS_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;
      }
   }

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

#if (NET_RTOS_SUPPORT == ENABLED)
   //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
      osDelayTask(delay);

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

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

      //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
      osReleaseMutex(&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));
   }
#endif

   //Return status code
   return error;
}
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;

   //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);
}
Beispiel #16
0
void ndpTick(NetInterface *interface)
{
   uint_t i;
   systime_t time;
   NdpCacheEntry *entry;

   //Get current time
   time = osGetSystemTime();

   //Acquire exclusive access to Neighbor cache
   osAcquireMutex(&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 = osGetSystemTime();
            //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
   osReleaseMutex(&interface->ndpCacheMutex);
}
error_t httpVerifyNonce(HttpServerContext *context,
   const char_t *nonce, const char_t *nc)
{
#if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
   error_t error;
   uint_t i;
   uint32_t count;
   systime_t time;
   HttpNonceCacheEntry *entry;

   //Check parameters
   if(nonce == NULL || nc == NULL)
      return ERROR_INVALID_PARAMETER;

   //Convert the nonce count to integer
   count = strtoul(nc, NULL, 16);
   //Get current time
   time = osGetSystemTime();

   //Acquire exclusive access to the nonce cache
   osAcquireMutex(&context->nonceCacheMutex);

   //Loop through nonce cache entries
   for(i = 0; i < HTTP_SERVER_NONCE_CACHE_SIZE; i++)
   {
      //Point to the current entry
      entry = &context->nonceCache[i];

      //Check nonce value
      if(!strcasecmp(entry->nonce, nonce))
      {
         //Make sure the nonce timestamp has not expired
         if((time - entry->timestamp) < HTTP_SERVER_NONCE_LIFETIME)
         {
            //Check nonce count to prevent replay attacks
            if(count >= entry->count)
            {
               //Update nonce count to the next expected value
               entry->count = count + 1;
               //We are done
               break;
            }
         }
      }
   }

   //Check whether the nonce is valid
   if(i < HTTP_SERVER_NONCE_CACHE_SIZE)
      error = NO_ERROR;
   else
      error = ERROR_NOT_FOUND;

   //Release exclusive access to the nonce cache
   osReleaseMutex(&context->nonceCacheMutex);
   //Return status code
   return error;

#else
   //Not implemented
   return ERROR_NOT_IMPLEMENTED;
#endif
}
Beispiel #18
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;
   }
}
Beispiel #19
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, "STM32F4-Discovery");
   }
   else if(!strcasecmp(param, "SYSTEM_TIME"))
   {
      systime_t time = osGetSystemTime();
      formatSystemTime(time, connection->buffer);
   }
   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);
}
Beispiel #20
0
void mdnsTick(NetInterface *interface)
{
   error_t error;
   systime_t time;
   MdnsContext *context;

   //Get current time
   time = osGetSystemTime();
   //Point to the mDNS context
   context = &interface->mdnsContext;

   //Check current state
   if(context->state == MDNS_STATE_INIT)
   {
      //Make sure that the link is up
      if(interface->linkState)
      {
#if (IPV4_SUPPORT == ENABLED)
         //Check whether the IPv4 host address is valid
         if(interface->ipv4Config.addrState == IPV4_ADDR_STATE_VALID)
            context->state = MDNS_STATE_PROBING;
#endif
#if (IPV6_SUPPORT == ENABLED)
         //Check whether the IPv6 link-local address is valid
         if(interface->ipv6Config.linkLocalAddrState == IPV6_ADDR_STATE_PREFERRED)
            context->state = MDNS_STATE_PROBING;
#endif
         //Start probing?
         if(context->state == MDNS_STATE_PROBING)
         {
            //Clear conflict flag
            context->conflict = FALSE;
            //Set time stamp
            context->timestamp = time;
            //Initial random delay
            context->timeout = netGetRandRange(0, MDNS_INIT_DELAY);
            //Reset probe counter
            context->counter = 0;
         }
      }
   }
   else if(context->state == MDNS_STATE_PROBING)
   {
      //Check current time
      if((time - context->timestamp) >= context->timeout)
      {
         //Any conflict detected?
         if(context->conflict)
         {
            //Programmatically change the host name
            error = mdnsGenerateHostname(interface);

            //Failed to change host name?
            if(error)
            {
               //Report an error
               context->state = MDNS_STATE_ERROR;
            }
            else
            {
               //Restart probing
               context->state = MDNS_STATE_INIT;
            }
         }
         //Probing is on-going?
         else if(context->counter < MDNS_PROBE_NUM)
         {
            //Send probe packet
            mdnsSendProbe(interface);

            //Save the time at which the packet was sent
            context->timestamp = time;
            //Time interval between subsequent probe packets
            context->timeout = MDNS_PROBE_DELAY;
            //Increment packet counter
            context->counter++;
         }
         else
         {
            //Set time stamp
            context->timestamp = time;
            //Reset timeout value
            context->timeout = 0;
            //Reset probe counter
            context->counter = 0;

            //Move to the next step (announcing)
            context->state = MDNS_STATE_ANNOUNCING;
         }
      }
   }
   else if(context->state == MDNS_STATE_ANNOUNCING)
   {
      //Check current time
      if((time - context->timestamp) >= context->timeout)
      {
         //Send announcement packet
         mdnsSendAnnouncement(interface);

         //Save the time at which the packet was sent
         context->timestamp = time;
         //Time interval between subsequent announcement packets
         context->timeout = MDNS_ANNOUNCE_DELAY;
         //Increment packet counter
         context->counter++;

         //Announcing is complete?
         if(context->counter >= MDNS_ANNOUNCE_NUM)
         {
            //Probing and announcing steps are complete
            context->state = MDNS_STATE_DONE;
         }
      }
   }
   else if(context->state == MDNS_STATE_DONE)
   {
      if(interface->nicDriver->type == NIC_TYPE_ETHERNET)
      {
         //Any conflict detected?
         if(context->conflict)
         {
            //Programmatically change the host name
            error = mdnsGenerateHostname(interface);

            //Failed to change host name?
            if(error)
            {
               //Report an error
               context->state = MDNS_STATE_ERROR;
            }
            else
            {
               //Restart probing
               context->state = MDNS_STATE_INIT;
            }
         }
      }
   }
}
Beispiel #21
0
void tcpTick(void)
{
   error_t error;
   uint_t i;
   uint_t n;
   uint_t u;

   //Enter critical section
   osAcquireMutex(&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(tcpTimerElapsed(&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",
                  formatSystemTime(osGetSystemTime(), NULL), 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
               tcpTimerStart(&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
               tcpTimerStop(&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(tcpTimerElapsed(&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",
                  formatSystemTime(osGetSystemTime(), NULL), 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
               tcpTimerStart(&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 && tcpTimerElapsed(&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)
               tcpTimerStart(&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(tcpTimerElapsed(&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(tcpTimerElapsed(&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
   osReleaseMutex(&socketMutex);
}
Beispiel #22
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;
}
error_t httpGenerateNonce(HttpServerContext *context,
   char_t *output, size_t *length)
{
#if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
   error_t error;
   uint_t i;
   HttpNonceCacheEntry *entry;
   HttpNonceCacheEntry *oldestEntry;
   uint8_t nonce[HTTP_SERVER_NONCE_SIZE];

   //Acquire exclusive access to the nonce cache
   osAcquireMutex(&context->nonceCacheMutex);

   //Keep track of the oldest entry
   oldestEntry = &context->nonceCache[0];

   //Loop through nonce cache entries
   for(i = 0; i < HTTP_SERVER_NONCE_CACHE_SIZE; i++)
   {
      //Point to the current entry
      entry = &context->nonceCache[i];

      //Check whether the entry is currently in used or not
      if(!entry->count)
         break;

      //Keep track of the oldest entry in the table
      if(timeCompare(entry->timestamp, oldestEntry->timestamp) < 0)
         oldestEntry = entry;
   }

   //The oldest entry is removed whenever the table runs out of space
   if(i >= HTTP_SERVER_NONCE_CACHE_SIZE)
      entry = oldestEntry;

   //Generate a new nonce
   error = context->settings.prngAlgo->read(context->settings.prngContext,
      nonce, HTTP_SERVER_NONCE_SIZE);

   //Check status code
   if(!error)
   {
      //Convert the byte array to hex string
      httpConvertArrayToHexString(nonce, HTTP_SERVER_NONCE_SIZE, entry->nonce);
      //Clear nonce count
      entry->count = 1;
      //Save the time at which the nonce was generated
      entry->timestamp = osGetSystemTime();

      //Copy the nonce to the output buffer
      strcpy(output, entry->nonce);
      //Return the length of the nonce excluding the NULL character
      *length = HTTP_SERVER_NONCE_SIZE * 2;
   }
   else
   {
      //Random number generation failed
      memset(entry, 0, sizeof(HttpNonceCacheEntry));
   }

   //Release exclusive access to the nonce cache
   osReleaseMutex(&context->nonceCacheMutex);
   //Return status code
   return error;

#else
   //Not implemented
   return ERROR_NOT_IMPLEMENTED;
#endif
}
Beispiel #24
0
void slaacProcessRouterAdv(SlaacContext *context,
   const Ipv6Addr *srcAddr, NdpRouterAdvMessage *message, size_t length)
{
   uint_t i;
   uint_t n;
   NdpPrefixInfoOption *prefixInfoOption;
   NdpRdnssOption *rdnssOption;
   Eui64 interfaceId;
   Ipv6Addr globalAddr;

   //Check current state
   if(context->state != SLAAC_STATE_ROUTER_SOLICIT)
      return;

   //Save router address
   ipv6SetRouter(context->interface, srcAddr);

   //Calculate the length of the Options field
   length -= sizeof(NdpRouterAdvMessage);

   //Search for the Prefix Information option
   prefixInfoOption = ndpGetOption(message->options, length, NDP_OPT_PREFIX_INFORMATION);

   //Prefix Information option not found?
   if(prefixInfoOption == NULL || prefixInfoOption->length != 4)
      return;

   //If the Autonomous flag is not set, silently ignore the Prefix
   //Information option
   if(!prefixInfoOption->a)
      return;

   //If the prefix is the link-local prefix, silently ignore the
   //Prefix Information option
   if(ipv6CompPrefix(&prefixInfoOption->prefix, &IPV6_LINK_LOCAL_ADDR_PREFIX, 64))
      return;

   //If the preferred lifetime is greater than the valid lifetime,
   //silently ignore the Prefix Information option
   if(prefixInfoOption->preferredLifetime > prefixInfoOption->validLifetime)
      return;

   //If the sum of the prefix length and interface identifier length does
   //not equal 128 bits, the Prefix Information option must be ignored
   if(prefixInfoOption->prefixLength != 64)
      return;

   //Save IPv6 prefix
   ipv6SetPrefix(context->interface, &prefixInfoOption->prefix,
      prefixInfoOption->prefixLength);

   //Generate the 64-bit interface identifier
   macAddrToEui64(&context->interface->macAddr, &interfaceId);

   //Form an address by combining the advertised prefix
   //with the interface identifier
   globalAddr.w[0] = prefixInfoOption->prefix.w[0];
   globalAddr.w[1] = prefixInfoOption->prefix.w[1];
   globalAddr.w[2] = prefixInfoOption->prefix.w[2];
   globalAddr.w[3] = prefixInfoOption->prefix.w[3];
   globalAddr.w[4] = interfaceId.w[0];
   globalAddr.w[5] = interfaceId.w[1];
   globalAddr.w[6] = interfaceId.w[2];
   globalAddr.w[7] = interfaceId.w[3];

   //Use the global address as a tentative address
   ipv6SetGlobalAddr(context->interface, &globalAddr, IPV6_ADDR_STATE_TENTATIVE);

   //Use the DNS servers provided by the router?
   if(!context->manualDnsConfig)
   {
      //Search for the Recursive DNS Server (RDNSS) option
      rdnssOption = ndpGetOption(message->options, length, NDP_OPT_RECURSIVE_DNS_SERVER);

      //RDNSS option found?
      if(rdnssOption != NULL && rdnssOption->length >= 1)
      {
         //Retrieve the number of addresses
         n = (rdnssOption->length - 1) / 2;

         //Save DNS servers
         for(i = 0; i < n; i++)
            ipv6SetDnsServer(context->interface, i, &rdnssOption->address[i]);
      }
   }

   //Set time stamp
   context->timestamp = osGetSystemTime();
   //Reset timeout value
   context->timeout = 0;
   //Reset retransmission counter
   context->retransmitCount = 0;

   //Verify the uniqueness of the global address
   context->state = SLAAC_STATE_GLOBAL_ADDR_DAD;
}
Beispiel #25
0
error_t ndpResolve(NetInterface *interface, const Ipv6Addr *ipAddr, MacAddr *macAddr)
{
   NdpCacheEntry *entry;

   //Acquire exclusive access to Neighbor cache
   osAcquireMutex(&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
         osReleaseMutex(&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 = osGetSystemTime();
         //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
         osReleaseMutex(&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
         osReleaseMutex(&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
      osReleaseMutex(&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 = osGetSystemTime();
   //Set timeout value
   entry->timeout = NDP_RETRANS_TIMER;
   //Enter INCOMPLETE state
   entry->state = NDP_STATE_INCOMPLETE;

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

   //The address resolution is in progress
   return ERROR_IN_PROGRESS;
}
void dnsTick(void)
{
   error_t error;
   uint_t i;
   systime_t time;
   DnsCacheEntry *entry;

   //Get current time
   time = osGetSystemTime();

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

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

      //Name resolution in progress?
      if(entry->state == DNS_STATE_IN_PROGRESS)
      {
         //The request timed out?
         if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
         {
            //Check whether the maximum number of retransmissions has been exceeded
            if(entry->retransmitCount > 0)
            {
#if (DNS_CLIENT_SUPPORT == ENABLED)
               //DNS resolver?
               if(entry->protocol == HOST_NAME_RESOLVER_DNS)
               {
                  //Retransmit DNS query
                  error = dnsSendQuery(entry);
               }
               else
#endif
#if (MDNS_CLIENT_SUPPORT == ENABLED)
               //mDNS resolver?
               if(entry->protocol == HOST_NAME_RESOLVER_MDNS)
               {
                  //Retransmit mDNS query
                  error = mdnsSendQuery(entry);
               }
               else
#endif
#if (NBNS_CLIENT_SUPPORT == ENABLED && IPV4_SUPPORT == ENABLED)
               //NetBIOS Name Service resolver?
               if(entry->protocol == HOST_NAME_RESOLVER_NBNS)
               {
                  //Retransmit NBNS query
                  error = nbnsSendQuery(entry);
               }
               else
#endif
               //Unknown protocol?
               {
                  error = ERROR_FAILURE;
               }

               //Query message successfully sent?
               if(!error)
               {
                  //Save the time at which the query message was sent
                  entry->timestamp = time;
                  //The timeout value is doubled for each subsequent retransmission
                  entry->timeout = MIN(entry->timeout * 2, entry->maxTimeout);
                  //Decrement retransmission counter
                  entry->retransmitCount--;
               }
               else
               {
                  //The entry should be deleted since name resolution has failed
                  dnsDeleteEntry(entry);
               }
            }
#if (DNS_CLIENT_SUPPORT == ENABLED)
            //DNS resolver?
            else if(entry->protocol == HOST_NAME_RESOLVER_DNS)
            {
               //Select the next DNS server
               entry->dnsServerNum++;
               //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 = time;
                  //Set timeout value
                  entry->timeout = DNS_CLIENT_INIT_TIMEOUT;
                  //Decrement retransmission counter
                  entry->retransmitCount--;
               }
               else
               {
                  //The entry should be deleted since name resolution has failed
                  dnsDeleteEntry(entry);
               }
            }
#endif
            else
            {
               //The maximum number of retransmissions has been exceeded
               dnsDeleteEntry(entry);
            }
         }
      }
      //Name successfully resolved?
      else if(entry->state == DNS_STATE_RESOLVED)
      {
         //Check the lifetime of the current DNS cache entry
         if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
         {
            //Periodically time out DNS cache entries
            dnsDeleteEntry(entry);
         }
      }
   }

   //Release exclusive access to the DNS cache
   osReleaseMutex(&dnsCacheMutex);
}
Beispiel #27
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);
}
void nbnsProcessResponse(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader,
   const UdpHeader *udpHeader, const NbnsHeader *message, size_t length)
{
   uint_t i;
   size_t pos;
   DnsCacheEntry *entry;
   DnsResourceRecord *resourceRecord;
   NbnsAddrEntry *addrEntry;

   //The NBNS response shall contain one answer
   if(ntohs(message->qdcount) != 0 && ntohs(message->ancount) != 1)
      return;

   //Parse NetBIOS name
   pos = nbnsParseName(message, length, sizeof(DnsHeader), NULL);
   //Invalid name?
   if(!pos) return;

   //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)
      return;
   if((pos + ntohs(resourceRecord->rdlength)) > length)
      return;

   //Check the class and the type of the resource record
   if(ntohs(resourceRecord->rclass) != DNS_RR_CLASS_IN)
      return;
   if(ntohs(resourceRecord->rtype) != DNS_RR_TYPE_NB)
      return;

   //Verify the length of the data field
   if(ntohs(resourceRecord->rdlength) < sizeof(NbnsAddrEntry))
      return;

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

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

      //NBNS name resolution in progress?
      if(entry->state == DNS_STATE_IN_PROGRESS &&
         entry->protocol == HOST_NAME_RESOLVER_NBNS &&
         entry->type == HOST_TYPE_IPV4)
      {
         //Compare identifiers
         if(entry->id == ntohs(message->id))
         {
            //Compare NetBIOS names
            if(nbnsCompareName(message, length, sizeof(DnsHeader), entry->name))
            {
               //Point to the address entry array
               addrEntry = (NbnsAddrEntry *) resourceRecord->rdata;
               //Copy the IPv4 address
               entry->ipAddr.length = sizeof(Ipv4Addr);
               entry->ipAddr.ipv4Addr = addrEntry->addr;

               //Save current time
               entry->timestamp = osGetSystemTime();
               //Save TTL value
               entry->timeout = ntohl(resourceRecord->ttl) * 1000;
               //Limit the lifetime of the NBNS cache entries
               entry->timeout = MIN(entry->timeout, NBNS_MAX_LIFETIME);

               //Host name successfully resolved
               entry->state = DNS_STATE_RESOLVED;
            }
         }
      }
   }

   //Release exclusive access to the DNS cache
   osReleaseMutex(&dnsCacheMutex);
}
Beispiel #29
0
void slaacTick(SlaacContext *context)
{
   systime_t time;

   //Get current time
   time = osGetSystemTime();

   //Enter critical section
   osAcquireMutex(&context->mutex);

   //Check current state
   if(context->state == SLAAC_STATE_INIT)
   {
      //Check link state
      if(context->running && context->interface->linkState)
      {
         Eui64 interfaceId;
         Ipv6Addr linkLocalAddr;

         //Generate the 64-bit interface identifier
         macAddrToEui64(&context->interface->macAddr, &interfaceId);

         //A link-local address is formed by combining the well-known
         //link-local prefix fe80::0 with the interface identifier
         linkLocalAddr.w[0] = htons(0xFE80);
         linkLocalAddr.w[1] = htons(0x0000);
         linkLocalAddr.w[2] = htons(0x0000);
         linkLocalAddr.w[3] = htons(0x0000);
         linkLocalAddr.w[4] = interfaceId.w[0];
         linkLocalAddr.w[5] = interfaceId.w[1];
         linkLocalAddr.w[6] = interfaceId.w[2];
         linkLocalAddr.w[7] = interfaceId.w[3];

         //Use the link-local address as a tentative address
         ipv6SetLinkLocalAddr(context->interface,
            &linkLocalAddr, IPV6_ADDR_STATE_TENTATIVE);

         //Set time stamp
         context->timestamp = time;
         //Reset timeout value
         context->timeout = 0;
         //Reset retransmission counter
         context->retransmitCount = 0;

         //Verify the uniqueness of the link-local address
         context->state = SLAAC_STATE_LINK_LOCAL_ADDR_DAD;
      }
   }
   else if(context->state == SLAAC_STATE_LINK_LOCAL_ADDR_DAD)
   {
      //Check current time
      if((time - context->timestamp) >= context->timeout)
      {
         //Duplicate Address Detection failed?
         if(context->interface->ipv6Config.linkLocalAddrDup)
         {
            //A tentative address that is determined to be a duplicate
            //must not be assigned to an interface
            ipv6SetLinkLocalAddr(context->interface,
               &IPV6_UNSPECIFIED_ADDR, IPV6_ADDR_STATE_INVALID);

            //Address autoconfiguration failed
            context->state = SLAAC_STATE_ERROR;

            //Dump current IPv6 configuration for debugging purpose
            slaacDumpConfig(context);
         }
#if (NDP_DUP_ADDR_DETECT_TRANSMITS > 0)
         //Duplicate Address Detection is on-going?
         else if(context->retransmitCount < NDP_DUP_ADDR_DETECT_TRANSMITS)
         {
            //Send Neighbor Solicitation message
            ndpSendNeighborSol(context->interface, &context->interface->ipv6Config.linkLocalAddr);

            //Save the time at which the message was sent
            context->timestamp = time;
            //Set timeout value
            context->timeout = NDP_RETRANS_TIMER;
            //Increment retransmission counter
            context->retransmitCount++;
         }
#endif
         //Duplicate Address Detection is complete?
         else
         {
            //The use of the link-local address is now unrestricted
            context->interface->ipv6Config.linkLocalAddrState = IPV6_ADDR_STATE_PREFERRED;

            //Set time stamp
            context->timestamp = time;
            //Delay before transmitting the first Router Solicitation message
            context->timeout = tcpIpStackGetRandRange(0, NDP_MAX_RTR_SOLICITATION_DELAY);
            //Reset retransmission counter
            context->retransmitCount = 0;

            //To obtain an advertisement quickly, a host sends out Router Solicitations
            context->state = SLAAC_STATE_ROUTER_SOLICIT;
         }
      }
   }
   else if(context->state == SLAAC_STATE_ROUTER_SOLICIT)
   {
      //Check current time
      if((time - context->timestamp) >= context->timeout)
      {
         //Check retransmission counter
         if(context->retransmitCount < NDP_MAX_RTR_SOLICITATIONS)
         {
            //Send Router Solicitation message
            ndpSendRouterSol(context->interface);

            //Save the time at which the message was sent
            context->timestamp = time;
            //Set timeout value
            context->timeout = NDP_RTR_SOLICITATION_INTERVAL;
            //Increment retransmission counter
            context->retransmitCount++;
         }
         else
         {
            //A link has no routers if no Router Advertisements are received
            //after having sent a small number of Router Solicitations
            context->state = SLAAC_STATE_ERROR;

            //Dump current IPv6 configuration for debugging purpose
            slaacDumpConfig(context);
         }
      }
   }
   else if(context->state == SLAAC_STATE_GLOBAL_ADDR_DAD)
   {
      //Check current time
      if((time - context->timestamp) >= context->timeout)
      {
         //Duplicate Address Detection failed?
         if(context->interface->ipv6Config.globalAddrDup)
         {
            //A tentative address that is determined to be a duplicate
            //must not be assigned to an interface
            ipv6SetGlobalAddr(context->interface,
               &IPV6_UNSPECIFIED_ADDR, IPV6_ADDR_STATE_INVALID);

            //Address autoconfiguration failed
            context->state = SLAAC_STATE_ERROR;

            //Dump current IPv6 configuration for debugging purpose
            slaacDumpConfig(context);
         }
#if (NDP_DUP_ADDR_DETECT_TRANSMITS > 0)
         //Duplicate Address Detection is on-going?
         else if(context->retransmitCount < NDP_DUP_ADDR_DETECT_TRANSMITS)
         {
            //Send Neighbor Solicitation message
            ndpSendNeighborSol(context->interface, &context->interface->ipv6Config.globalAddr);

            //Save the time at which the message was sent
            context->timestamp = time;
            //Set timeout value
            context->timeout = NDP_RETRANS_TIMER;
            //Increment retransmission counter
            context->retransmitCount++;
         }
#endif
         //Duplicate Address Detection is complete?
         else
         {
            //The use of the global address is now unrestricted
            context->interface->ipv6Config.globalAddrState = IPV6_ADDR_STATE_PREFERRED;
            //Successful address autoconfiguration
            context->state = SLAAC_STATE_CONFIGURED;

            //Dump current IPv6 configuration for debugging purpose
            slaacDumpConfig(context);
         }
      }
   }

   //Leave critical section
   osReleaseMutex(&context->mutex);
}
Beispiel #30
0
error_t lcpSendConfigureReq(PppContext *context)
{
   error_t error;
   size_t length;
   size_t offset;
   NetBuffer *buffer;
   PppConfigurePacket *configureReqPacket;

   //Debug message
   TRACE_INFO("LCP Send-Configure-Request callback\r\n");

   //Calculate the maximum size of the Configure-Request packet
   length = sizeof(PppConfigurePacket) +
      sizeof(LcpMruOption) + sizeof(LcpAccmOption);

   //Allocate a buffer memory to hold the packet
   buffer = pppAllocBuffer(length, &offset);
   //Failed to allocate memory?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Point to the Configure-Request packet
   configureReqPacket = netBufferAt(buffer, offset);

   //Format packet header
   configureReqPacket->code = PPP_CODE_CONFIGURE_REQ;
   configureReqPacket->identifier = ++context->lcpFsm.identifier;
   configureReqPacket->length = sizeof(PppConfigurePacket);

   //Make sure the Maximum-Receive-Unit option has not been previously rejected
   if(!context->localConfig.mruRejected)
   {
      //Convert MRU to network byte order
      uint16_t value = htons(context->localConfig.mru);
      //Add option
      pppAddOption(configureReqPacket, LCP_OPTION_MRU, &value, sizeof(uint16_t));
   }

   //Make sure the Async-Control-Character-Map option has not been previously rejected
   if(!context->localConfig.accmRejected)
   {
      //Convert ACCM to network byte order
      uint32_t value = htonl(context->localConfig.accm);
      //Add option
      pppAddOption(configureReqPacket, LCP_OPTION_ACCM, &value, sizeof(uint32_t));
   }

   //Save packet length
   length = configureReqPacket->length;
   //Convert length field to network byte order
   configureReqPacket->length = htons(length);

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

   //Debug message
   TRACE_INFO("Sending Configure-Request packet (%" PRIuSIZE " bytes)...\r\n", length);
   //Dump packet contents for debugging purpose
   pppDumpPacket((PppPacket *) configureReqPacket, length, PPP_PROTOCOL_LCP);

   //Send PPP frame
   error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_LCP);

   //The restart counter is decremented each time a Configure-Request is sent
   if(context->lcpFsm.restartCounter > 0)
      context->lcpFsm.restartCounter--;

   //Save the time at which the packet was sent
   context->lcpFsm.timestamp = osGetSystemTime();

   //Free previously allocated memory block
   netBufferFree(buffer);
   //Return status code
   return error;
}