Exemplo n.º 1
0
error_t socketRegisterEvents(Socket *socket, OsEvent *event, uint_t eventMask)
{
   //Make sure the socket handle is valid
   if(!socket)
      return ERROR_INVALID_PARAMETER;

   //Enter critical section
   osAcquireMutex(&socketMutex);

   //An user event may have been previously registered...
   if(socket->userEvent != NULL)
      socket->eventMask |= eventMask;
   else
      socket->eventMask = eventMask;

   //Suscribe to get notified of events
   socket->userEvent = event;

#if (TCP_SUPPORT == ENABLED)
   //Handle TCP specific events
   if(socket->type == SOCKET_TYPE_STREAM)
   {
      tcpUpdateEvents(socket);
   }
#endif
#if (UDP_SUPPORT == ENABLED)
   //Handle UDP specific events
   if(socket->type == SOCKET_TYPE_DGRAM)
   {
      udpUpdateEvents(socket);
   }
#endif
#if (RAW_SOCKET_SUPPORT == ENABLED)
   //Handle events that are specific to raw sockets
   if(socket->type == SOCKET_TYPE_RAW_IP ||
      socket->type == SOCKET_TYPE_RAW_ETH)
   {
      rawSocketUpdateEvents(socket);
   }
#endif

   //Leave critical section
   osReleaseMutex(&socketMutex);
   //Successful processing
   return NO_ERROR;
}
Exemplo n.º 2
0
void tcpStateListen(Socket *socket, NetInterface *interface,
   IpPseudoHeader *pseudoHeader, TcpHeader *segment, size_t length)
{
   uint_t i;
   TcpOption *option;
   TcpSynQueueItem *queueItem;

   //Debug message
   TRACE_DEBUG("TCP FSM: LISTEN state\r\n");

   //An incoming RST should be ignored
   if(segment->flags & TCP_FLAG_RST)
      return;

   //Any acknowledgment is bad if it arrives on a connection
   //still in the LISTEN state
   if(segment->flags & TCP_FLAG_ACK)
   {
      //A reset segment should be formed for any arriving ACK-bearing segment
      tcpSendResetSegment(interface, pseudoHeader, segment, length);
      //Return immediately
      return;
   }

   //Check the SYN bit
   if(segment->flags & TCP_FLAG_SYN)
   {
      //The SYN queue is empty?
      if(!socket->synQueue)
      {
         //Allocate memory to save incoming data
         queueItem = memPoolAlloc(sizeof(TcpSynQueueItem));
         //Add the newly created item to the queue
         socket->synQueue = queueItem;
      }
      else
      {
         //Point to the very first item
         queueItem = socket->synQueue;

         //Reach the last item in the receive queue
         for(i = 1; queueItem->next; i++)
            queueItem = queueItem->next;

         //Make sure the receive queue is not full
         if(i >= socket->synQueueSize)
            return;

         //Allocate memory to save incoming data
         queueItem->next = memPoolAlloc(sizeof(TcpSynQueueItem));
         //Point to the newly created item
         queueItem = queueItem->next;
      }

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

#if (IPV4_SUPPORT == ENABLED)
      //IPv4 is currently used?
      if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
      {
         //Save the source IPv4 address
         queueItem->srcAddr.length = sizeof(Ipv4Addr);
         queueItem->srcAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr;
         //Save the destination IPv4 address
         queueItem->destAddr.length = sizeof(Ipv4Addr);
         queueItem->destAddr.ipv4Addr = pseudoHeader->ipv4Data.destAddr;
      }
      else
#endif
#if (IPV6_SUPPORT == ENABLED)
      //IPv6 is currently used?
      if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
      {
         //Save the source IPv6 address
         queueItem->srcAddr.length = sizeof(Ipv6Addr);
         queueItem->srcAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr;
         //Save the destination IPv6 address
         queueItem->destAddr.length = sizeof(Ipv6Addr);
         queueItem->destAddr.ipv6Addr = pseudoHeader->ipv6Data.destAddr;
      }
      else
#endif
      //Invalid pseudo header?
      {
         //This should never occur...
         return;
      }

      //Initialize next field
      queueItem->next = NULL;
      //Underlying network interface
      queueItem->interface = interface;
      //Save the port number of the client
      queueItem->srcPort = segment->srcPort;
      //Save the initial sequence number
      queueItem->isn = segment->seqNum;
      //Default MSS value
      queueItem->mss = MIN(TCP_DEFAULT_MSS, TCP_MAX_MSS);

      //Get the maximum segment size
      option = tcpGetOption(segment, TCP_OPTION_MAX_SEGMENT_SIZE);
      //Specified option found?
      if(option != NULL && option->length == 4)
      {
         //Retrieve MSS value
         memcpy(&queueItem->mss, option->value, 2);
         //Convert from network byte order to host byte order
         queueItem->mss = ntohs(queueItem->mss);

         //Debug message
         TRACE_DEBUG("Remote host MSS = %" PRIu16 "\r\n", queueItem->mss);

         //Make sure that the MSS advertised by the peer is acceptable
         queueItem->mss = MIN(queueItem->mss, TCP_MAX_MSS);
         queueItem->mss = MAX(queueItem->mss, TCP_MIN_MSS);
      }

      //Notify user that a connection request is pending
      tcpUpdateEvents(socket);

      //The rest of the processing described in RFC 793 will be done
      //asynchronously when socketAccept() function is called
   }
}
Exemplo n.º 3
0
error_t tcpReceive(Socket *socket, uint8_t *data,
   size_t size, size_t *received, uint_t flags)
{
   uint_t i;
   uint_t n;
   uint_t event;
   uint32_t seqNum;
   systime_t timeout;

   //Retrieve the break character code
   char_t c = LSB(flags);
   //No data has been read yet
   *received = 0;

   //Check whether the socket is in the listening state
   if(socket->state == TCP_STATE_LISTEN)
      return ERROR_NOT_CONNECTED;

   //Read as much data as possible
   while(*received < size)
   {
      //The SOCKET_FLAG_DONT_WAIT enables non-blocking operation
      timeout = (flags & SOCKET_FLAG_DONT_WAIT) ? 0 : socket->timeout;
      //Wait for data to be available for reading
      event = tcpWaitForEvents(socket, SOCKET_EVENT_RX_READY, timeout);

      //A timeout exception occurred?
      if(event != SOCKET_EVENT_RX_READY)
         return ERROR_TIMEOUT;

      //Check current TCP state
      switch(socket->state)
      {
      //ESTABLISHED, FIN-WAIT-1 or FIN-WAIT-2 state?
      case TCP_STATE_ESTABLISHED:
      case TCP_STATE_FIN_WAIT_1:
      case TCP_STATE_FIN_WAIT_2:
         //Sequence number of the first byte to read
         seqNum = socket->rcvNxt - socket->rcvUser;
         //Data is available in the receive buffer
         break;

      //CLOSE-WAIT, LAST-ACK, CLOSING or TIME-WAIT state?
      case TCP_STATE_CLOSE_WAIT:
      case TCP_STATE_LAST_ACK:
      case TCP_STATE_CLOSING:
      case TCP_STATE_TIME_WAIT:
         //The user must be satisfied with data already on hand
         if(!socket->rcvUser)
         {
            if(*received > 0)
               return NO_ERROR;
            else
               return ERROR_END_OF_STREAM;
         }

         //Sequence number of the first byte to read
         seqNum = (socket->rcvNxt - 1) - socket->rcvUser;
         //Data is available in the receive buffer
         break;

      //CLOSED state?
      default:
         //The connection was reset by remote side?
         if(socket->resetFlag)
            return ERROR_CONNECTION_RESET;
         //The connection has not yet been established?
         if(!socket->closedFlag)
            return ERROR_NOT_CONNECTED;

         //The user must be satisfied with data already on hand
         if(!socket->rcvUser)
         {
            if(*received > 0)
               return NO_ERROR;
            else
               return ERROR_END_OF_STREAM;
         }

         //Sequence number of the first byte to read
         seqNum = (socket->rcvNxt - 1) - socket->rcvUser;
         //Data is available in the receive buffer
         break;
      }

      //Sanity check
      if(!socket->rcvUser)
         return ERROR_FAILURE;

      //Calculate the number of bytes to read at a time
      n = MIN(socket->rcvUser, size - *received);
      //Copy data from circular buffer
      tcpReadRxBuffer(socket, seqNum, data, n);

      //Read data until a break character is encountered?
      if(flags & SOCKET_FLAG_BREAK_CHAR)
      {
         //Search for the specified break character
         for(i = 0; i < n && data[i] != c; i++);
         //Adjust the number of data to read
         n = MIN(n, i + 1);
      }

      //Total number of data that have been read
      *received += n;
      //Remaining data still available in the receive buffer
      socket->rcvUser -= n;

      //Update the receive window
      tcpUpdateReceiveWindow(socket);
      //Update RX event state
      tcpUpdateEvents(socket);

      //The SOCKET_FLAG_BREAK_CHAR flag causes the function to stop reading
      //data as soon as the specified break character is encountered
      if(flags & SOCKET_FLAG_BREAK_CHAR)
      {
         //Check whether a break character has been found
         if(data[n - 1] == c) break;
      }
      //The SOCKET_FLAG_WAIT_ALL flag causes the function to return
      //only when the requested number of bytes have been read
      else if(!(flags & SOCKET_FLAG_WAIT_ALL))
      {
         break;
      }

      //Advance data pointer
      data += n;
   }

   //Successful read operation
   return NO_ERROR;
}
Exemplo n.º 4
0
error_t tcpSend(Socket *socket, const uint8_t *data,
   size_t length, size_t *written, uint_t flags)
{
   uint_t n;
   uint_t totalLength;
   uint_t event;

   //Check whether the socket is in the listening state
   if(socket->state == TCP_STATE_LISTEN)
      return ERROR_NOT_CONNECTED;

   //Actual number of bytes written
   totalLength = 0;

   //Send as much data as possible
   do
   {
      //Wait until there is more room in the send buffer
      event = tcpWaitForEvents(socket, SOCKET_EVENT_TX_READY, socket->timeout);

      //A timeout exception occurred?
      if(event != SOCKET_EVENT_TX_READY)
         return ERROR_TIMEOUT;

      //Check current TCP state
      switch(socket->state)
      {
      //ESTABLISHED or CLOSE-WAIT state?
      case TCP_STATE_ESTABLISHED:
      case TCP_STATE_CLOSE_WAIT:
         //The send buffer is now available for writing
         break;

      //LAST-ACK, FIN-WAIT-1, FIN-WAIT-2, CLOSING or TIME-WAIT state?
      case TCP_STATE_LAST_ACK:
      case TCP_STATE_FIN_WAIT_1:
      case TCP_STATE_FIN_WAIT_2:
      case TCP_STATE_CLOSING:
      case TCP_STATE_TIME_WAIT:
         //The connection is being closed
         return ERROR_CONNECTION_CLOSING;

      //CLOSED state?
      default:
         //The connection was reset by remote side?
         return (socket->resetFlag) ? ERROR_CONNECTION_RESET : ERROR_NOT_CONNECTED;
      }

      //Determine the actual number of bytes in the send buffer
      n = socket->sndUser + socket->sndNxt - socket->sndUna;
      //Exit immediately if the transmission buffer is full (sanity check)
      if(n >= socket->txBufferSize)
         return ERROR_FAILURE;

      //Number of bytes available for writing
      n = socket->txBufferSize - n;
      //Calculate the number of bytes to copy at a time
      n = MIN(n, length - totalLength);

      //Any data to copy?
      if(n > 0)
      {
         //Copy user data to send buffer
         tcpWriteTxBuffer(socket, socket->sndNxt + socket->sndUser, data, n);

         //Update the number of data buffered but not yet sent
         socket->sndUser += n;
         //Advance data pointer
         data += n;
         //Update byte counter
         totalLength += n;

         //Total number of data that have been written
         if(written != NULL)
            *written = totalLength;

         //Update TX events
         tcpUpdateEvents(socket);

         //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->sndUser == n)
            tcpTimerStart(&socket->overrideTimer, TCP_OVERRIDE_TIMEOUT);
      }

      //The Nagle algorithm should be implemented to coalesce
      //short segments (refer to RFC 1122 4.2.3.4)
      tcpNagleAlgo(socket, flags);

      //Send as much data as possible
   } while(totalLength < length);

   //The SOCKET_FLAG_WAIT_ACK flag causes the function to
   //wait for acknowledgement from the remote side
   if(flags & SOCKET_FLAG_WAIT_ACK)
   {
      //Wait for the data to be acknowledged
      event = tcpWaitForEvents(socket, SOCKET_EVENT_TX_ACKED, socket->timeout);

      //A timeout exception occurred?
      if(event != SOCKET_EVENT_TX_ACKED)
         return ERROR_TIMEOUT;

      //The connection was closed before an acknowledgement was received?
      if(socket->state != TCP_STATE_ESTABLISHED && socket->state != TCP_STATE_CLOSE_WAIT)
         return ERROR_NOT_CONNECTED;
   }

   //Successful write operation
   return NO_ERROR;
}
Exemplo n.º 5
0
Socket *tcpAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
{
   error_t error;
   Socket *newSocket;
   TcpSynQueueItem *queueItem;

   //Ensure the socket was previously placed in the listening state
   if(tcpGetState(socket) != TCP_STATE_LISTEN)
      return NULL;

   //Enter critical section
   osAcquireMutex(&socketMutex);

   //Wait for an connection attempt
   while(1)
   {
      //The SYN queue is empty?
      if(!socket->synQueue)
      {
         //Set the events the application is interested in
         socket->eventMask = SOCKET_EVENT_RX_READY;
         //Reset the event object
         osResetEvent(&socket->event);
         //Leave critical section
         osReleaseMutex(&socketMutex);
         //Wait until a SYN message is received from a client
         osWaitForEvent(&socket->event, socket->timeout);
         //Enter critical section
         osAcquireMutex(&socketMutex);
      }

      //Check whether the queue is still empty
      if(!socket->synQueue)
      {
         //Timeout error
         newSocket = NULL;
         //Exit immediately
         break;
      }

      //Point to the first item in the receive queue
      queueItem = socket->synQueue;

      //Return the client IP address and port number
      if(clientIpAddr)
         *clientIpAddr = queueItem->srcAddr;
      if(clientPort)
         *clientPort = queueItem->srcPort;

      //Leave critical section
      osReleaseMutex(&socketMutex);
      //Create a new socket to handle the incoming connection request
      newSocket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
      //Enter critical section
      osAcquireMutex(&socketMutex);

      //Socket successfully created?
      if(newSocket != NULL)
      {
         //The user owns the socket
         newSocket->ownedFlag = TRUE;

         //Inherit settings from the listening socket
         newSocket->txBufferSize = socket->txBufferSize;
         newSocket->rxBufferSize = socket->rxBufferSize;

         //Number of chunks that comprise the TX and the RX buffers
         newSocket->txBuffer.maxChunkCount = arraysize(newSocket->txBuffer.chunk);
         newSocket->rxBuffer.maxChunkCount = arraysize(newSocket->rxBuffer.chunk);

         //Allocate transmit buffer
         error = netBufferSetLength((NetBuffer *) &newSocket->txBuffer, newSocket->txBufferSize);

         //Check status code
         if(!error)
         {
            //Allocate receive buffer
            error = netBufferSetLength((NetBuffer *) &newSocket->rxBuffer, newSocket->rxBufferSize);
         }

         //Transmit and receive buffers successfully allocated?
         if(!error)
         {
            //Bind the newly created socket to the appropriate interface
            newSocket->interface = queueItem->interface;
            //Bind the socket to the specified address
            newSocket->localIpAddr = queueItem->destAddr;
            newSocket->localPort = socket->localPort;
            //Save the port number and the IP address of the remote host
            newSocket->remoteIpAddr = queueItem->srcAddr;
            newSocket->remotePort = queueItem->srcPort;
            //Save the maximum segment size
            newSocket->mss = queueItem->mss;

            //Initialize TCP control block
            newSocket->iss = netGetRand();
            newSocket->irs = queueItem->isn;
            newSocket->sndUna = newSocket->iss;
            newSocket->sndNxt = newSocket->iss + 1;
            newSocket->rcvNxt = newSocket->irs + 1;
            newSocket->rcvUser = 0;
            newSocket->rcvWnd = newSocket->rxBufferSize;

            //Default retransmission timeout
            newSocket->rto = TCP_INITIAL_RTO;

#if (TCP_CONGESTION_CONTROL_SUPPORT == ENABLED)
            //Initial congestion window
            newSocket->cwnd = MIN(TCP_INITIAL_WINDOW * newSocket->mss, newSocket->txBufferSize);
            //Slow start threshold should be set arbitrarily high
            newSocket->ssthresh = UINT16_MAX;
#endif

            //Send a SYN ACK control segment
            error = tcpSendSegment(newSocket, TCP_FLAG_SYN | TCP_FLAG_ACK,
               newSocket->iss, newSocket->rcvNxt, 0, TRUE);

            //TCP segment successfully sent?
            if(!error)
            {
               //Remove the item from the SYN queue
               socket->synQueue = queueItem->next;
               //Deallocate memory buffer
               memPoolFree(queueItem);
               //Update the state of events
               tcpUpdateEvents(socket);

               //The connection state should be changed to SYN-RECEIVED
               tcpChangeState(newSocket, TCP_STATE_SYN_RECEIVED);

               //We are done...
               break;
            }
         }

         //Dispose the socket
         tcpAbort(newSocket);
      }

      //Debug message
      TRACE_WARNING("Cannot accept TCP connection!\r\n");

      //Remove the item from the SYN queue
      socket->synQueue = queueItem->next;
      //Deallocate memory buffer
      memPoolFree(queueItem);

      //Wait for the next connection attempt
   }

   //Leave critical section
   osReleaseMutex(&socketMutex);

   //Return a handle to the newly created socket
   return newSocket;
}
Exemplo n.º 6
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);
}