tcp_fsm.c
Go to the documentation of this file.
1 /**
2  * @file tcp_fsm.c
3  * @brief TCP finite state machine
4  *
5  * @section License
6  *
7  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @section Description
26  *
27  * The TCP state machine progresses from one state to another in response to
28  * events (user calls, incoming segments and timeouts). This file describes
29  * the state transitions caused by incoming segments. Refer to the
30  * following RFCs for complete details:
31  * - RFC 793: Transmission Control Protocol
32  * - RFC 1122: Requirements for Internet Hosts - Communication Layers
33  *
34  * @author Oryx Embedded SARL (www.oryx-embedded.com)
35  * @version 1.9.0
36  **/
37 
38 //Switch to the appropriate trace level
39 #define TRACE_LEVEL TCP_TRACE_LEVEL
40 
41 //Dependencies
42 #include <stdlib.h>
43 #include <string.h>
44 #include "core/net.h"
45 #include "core/ip.h"
46 #include "core/socket.h"
47 #include "core/tcp.h"
48 #include "core/tcp_fsm.h"
49 #include "core/tcp_misc.h"
50 #include "core/tcp_timer.h"
51 #include "ipv4/ipv4.h"
52 #include "ipv6/ipv6.h"
53 #include "mibs/mib2_module.h"
54 #include "mibs/tcp_mib_module.h"
55 #include "date_time.h"
56 #include "debug.h"
57 
58 //Check TCP/IP stack configuration
59 #if (TCP_SUPPORT == ENABLED)
60 
61 
62 /**
63  * @brief Incoming TCP segment processing
64  * @param[in] interface Underlying network interface
65  * @param[in] pseudoHeader TCP pseudo header
66  * @param[in] buffer Multi-part buffer that holds the incoming TCP segment
67  * @param[in] offset Offset to the first byte of the TCP header
68  **/
69 
71  IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
72 {
73  uint_t i;
74  size_t length;
75  Socket *socket;
76  Socket *passiveSocket;
77  TcpHeader *segment;
78 
79  //Total number of segments received, including those received in error
80  MIB2_INC_COUNTER32(tcpGroup.tcpInSegs, 1);
81  TCP_MIB_INC_COUNTER32(tcpInSegs, 1);
82  TCP_MIB_INC_COUNTER64(tcpHCInSegs, 1);
83 
84  //A TCP implementation must silently discard an incoming
85  //segment that is addressed to a broadcast or multicast
86  //address (see RFC 1122 4.2.3.10)
87 #if (IPV4_SUPPORT == ENABLED)
88  if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
89  {
90  //Ensure the destination address is not a broadcast address
91  if(ipv4IsBroadcastAddr(interface, pseudoHeader->ipv4Data.destAddr))
92  return;
93  //Ensure the destination address is not a multicast address
94  if(ipv4IsMulticastAddr(pseudoHeader->ipv4Data.destAddr))
95  return;
96  }
97  else
98 #endif
99 #if (IPV6_SUPPORT == ENABLED)
100  if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
101  {
102  //Ensure the destination address is not a multicast address
103  if(ipv6IsMulticastAddr(&pseudoHeader->ipv6Data.destAddr))
104  return;
105  }
106  else
107 #endif
108  {
109  //This should never occur...
110  return;
111  }
112 
113  //Retrieve the length of the TCP segment
114  length = netBufferGetLength(buffer) - offset;
115 
116  //Point to the TCP header
117  segment = netBufferAt(buffer, offset);
118  //Sanity check
119  if(segment == NULL)
120  return;
121 
122  //Ensure the TCP header is valid
123  if(length < sizeof(TcpHeader))
124  {
125  //Debug message
126  TRACE_WARNING("TCP segment length is invalid!\r\n");
127 
128  //Total number of segments received in error
129  MIB2_INC_COUNTER32(tcpGroup.tcpInErrs, 1);
130  TCP_MIB_INC_COUNTER32(tcpInErrs, 1);
131 
132  //Exit immediately
133  return;
134  }
135 
136  //Check header length
137  if(segment->dataOffset < 5 || ((size_t) segment->dataOffset * 4) > length)
138  {
139  //Debug message
140  TRACE_WARNING("TCP header length is invalid!\r\n");
141 
142  //Total number of segments received in error
143  MIB2_INC_COUNTER32(tcpGroup.tcpInErrs, 1);
144  TCP_MIB_INC_COUNTER32(tcpInErrs, 1);
145 
146  //Exit immediately
147  return;
148  }
149 
150  //Verify TCP checksum
151  if(ipCalcUpperLayerChecksumEx(pseudoHeader->data,
152  pseudoHeader->length, buffer, offset, length) != 0x0000)
153  {
154  //Debug message
155  TRACE_WARNING("Wrong TCP header checksum!\r\n");
156 
157  //Total number of segments received in error
158  MIB2_INC_COUNTER32(tcpGroup.tcpInErrs, 1);
159  TCP_MIB_INC_COUNTER32(tcpInErrs, 1);
160 
161  //Exit immediately
162  return;
163  }
164 
165  //No matching socket in the LISTEN state for the moment
166  passiveSocket = NULL;
167 
168  //Look through opened sockets
169  for(i = 0; i < SOCKET_MAX_COUNT; i++)
170  {
171  //Point to the current socket
172  socket = socketTable + i;
173 
174  //TCP socket found?
175  if(socket->type != SOCKET_TYPE_STREAM)
176  continue;
177  //Check whether the socket is bound to a particular interface
178  if(socket->interface && socket->interface != interface)
179  continue;
180  //Check destination port number
181  if(socket->localPort != ntohs(segment->destPort))
182  continue;
183 
184 #if (IPV4_SUPPORT == ENABLED)
185  //IPv4 packet received?
186  if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
187  {
188  //Destination IP address filtering
189  if(socket->localIpAddr.length != 0)
190  {
191  //An IPv4 address is expected
192  if(socket->localIpAddr.length != sizeof(Ipv4Addr))
193  continue;
194  //Filter out non-matching addresses
195  if(socket->localIpAddr.ipv4Addr != pseudoHeader->ipv4Data.destAddr)
196  continue;
197  }
198 
199  //Source IP address filtering
200  if(socket->remoteIpAddr.length != 0)
201  {
202  //An IPv4 address is expected
203  if(socket->remoteIpAddr.length != sizeof(Ipv4Addr))
204  continue;
205  //Filter out non-matching addresses
206  if(socket->remoteIpAddr.ipv4Addr != pseudoHeader->ipv4Data.srcAddr)
207  continue;
208  }
209  }
210  else
211 #endif
212 #if (IPV6_SUPPORT == ENABLED)
213  //IPv6 packet received?
214  if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
215  {
216  //Destination IP address filtering
217  if(socket->localIpAddr.length != 0)
218  {
219  //An IPv6 address is expected
220  if(socket->localIpAddr.length != sizeof(Ipv6Addr))
221  continue;
222  //Filter out non-matching addresses
223  if(!ipv6CompAddr(&socket->localIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.destAddr))
224  continue;
225  }
226 
227  //Source IP address filtering
228  if(socket->remoteIpAddr.length != 0)
229  {
230  //An IPv6 address is expected
231  if(socket->remoteIpAddr.length != sizeof(Ipv6Addr))
232  continue;
233  //Filter out non-matching addresses
234  if(!ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.srcAddr))
235  continue;
236  }
237  }
238  else
239 #endif
240  //Invalid packet received?
241  {
242  //This should never occur...
243  continue;
244  }
245 
246  //Keep track of the first matching socket in the LISTEN state
247  if(socket->state == TCP_STATE_LISTEN && passiveSocket == NULL)
248  passiveSocket = socket;
249 
250  //Source port filtering
251  if(socket->remotePort != ntohs(segment->srcPort))
252  continue;
253 
254  //A matching socket has been found
255  break;
256  }
257 
258  //If no matching socket has been found then try to
259  //use the first matching socket in the LISTEN state
260  if(i >= SOCKET_MAX_COUNT)
261  socket = passiveSocket;
262 
263  //Offset to the first data byte
264  offset += segment->dataOffset * 4;
265  //Calculate the length of the data
266  length -= segment->dataOffset * 4;
267 
268  //Debug message
269  TRACE_DEBUG("%s: TCP segment received (%" PRIuSIZE " data bytes)...\r\n",
271 
272  //Dump TCP header contents for debugging purpose
273  if(socket == NULL)
274  tcpDumpHeader(segment, length, 0, 0);
275  else
276  tcpDumpHeader(segment, length, socket->irs, socket->iss);
277 
278  //Convert from network byte order to host byte order
279  segment->srcPort = ntohs(segment->srcPort);
280  segment->destPort = ntohs(segment->destPort);
281  segment->seqNum = ntohl(segment->seqNum);
282  segment->ackNum = ntohl(segment->ackNum);
283  segment->window = ntohs(segment->window);
284  segment->urgentPointer = ntohs(segment->urgentPointer);
285 
286  //Specified port is unreachable?
287  if(socket == NULL)
288  {
289  //An incoming segment not containing a RST causes
290  //a reset to be sent in response
291  if(!(segment->flags & TCP_FLAG_RST))
292  tcpSendResetSegment(interface, pseudoHeader, segment, length);
293 
294  //Return immediately
295  return;
296  }
297 
298  //Check current state
299  switch(socket->state)
300  {
301  //Process CLOSED state
302  case TCP_STATE_CLOSED:
303  //This is the default state that each connection starts in before
304  //the process of establishing it begins
305  tcpStateClosed(interface, pseudoHeader, segment, length);
306  break;
307  //Process LISTEN state
308  case TCP_STATE_LISTEN:
309  //A device (normally a server) is waiting to receive a synchronize (SYN)
310  //message from a client. It has not yet sent its own SYN message
311  tcpStateListen(socket, interface, pseudoHeader, segment, length);
312  break;
313  //Process SYN_SENT state
314  case TCP_STATE_SYN_SENT:
315  //The device (normally a client) has sent a synchronize (SYN) message and
316  //is waiting for a matching SYN from the other device (usually a server)
317  tcpStateSynSent(socket, segment, length);
318  break;
319  //Process SYN_RECEIVED state
321  //The device has both received a SYN from its partner and sent its own SYN.
322  //It is now waiting for an ACK to its SYN to finish connection setup
323  tcpStateSynReceived(socket, segment, buffer, offset, length);
324  break;
325  //Process ESTABLISHED state
327  //Data can be exchanged freely once both devices in the connection enter
328  //this state. This will continue until the connection is closed
329  tcpStateEstablished(socket, segment, buffer, offset, length);
330  break;
331  //Process CLOSE_WAIT state
333  //The device has received a close request (FIN) from the other device. It
334  //must now wait for the application to acknowledge this request and
335  //generate a matching request
336  tcpStateCloseWait(socket, segment, length);
337  break;
338  //Process LAST_ACK state
339  case TCP_STATE_LAST_ACK:
340  //A device that has already received a close request and acknowledged it,
341  //has sent its own FIN and is waiting for an ACK to this request
342  tcpStateLastAck(socket, segment, length);
343  break;
344  //Process FIN_WAIT_1 state
346  //A device in this state is waiting for an ACK for a FIN it has sent, or
347  //is waiting for a connection termination request from the other device
348  tcpStateFinWait1(socket, segment, buffer, offset, length);
349  break;
350  //Process FIN_WAIT_2 state
352  //A device in this state has received an ACK for its request to terminate the
353  //connection and is now waiting for a matching FIN from the other device
354  tcpStateFinWait2(socket, segment, buffer, offset, length);
355  break;
356  //Process CLOSING state
357  case TCP_STATE_CLOSING:
358  //The device has received a FIN from the other device and sent an ACK for
359  //it, but not yet received an ACK for its own FIN message
360  tcpStateClosing(socket, segment, length);
361  break;
362  //Process TIME_WAIT state
363  case TCP_STATE_TIME_WAIT:
364  //The device has now received a FIN from the other device and acknowledged
365  //it, and sent its own FIN and received an ACK for it. We are done, except
366  //for waiting to ensure the ACK is received and prevent potential overlap
367  //with new connections
368  tcpStateTimeWait(socket, segment, length);
369  break;
370  //Invalid state...
371  default:
372  //Back to the CLOSED state
374  //Silently discard incoming packet
375  break;
376  }
377 }
378 
379 
380 /**
381  * @brief CLOSED state
382  *
383  * This is the default state that each connection starts in before
384  * the process of establishing it begins
385  *
386  * @param[in] interface Underlying network interface
387  * @param[in] pseudoHeader TCP pseudo header
388  * @param[in] segment Incoming TCP segment
389  * @param[in] length Length of the segment data
390  **/
391 
393  IpPseudoHeader *pseudoHeader, TcpHeader *segment, size_t length)
394 {
395  //Debug message
396  TRACE_DEBUG("TCP FSM: CLOSED state\r\n");
397 
398  //An incoming segment not containing a RST causes
399  //a reset to be sent in response
400  if(!(segment->flags & TCP_FLAG_RST))
401  tcpSendResetSegment(interface, pseudoHeader, segment, length);
402 }
403 
404 
405 /**
406  * @brief LISTEN state
407  *
408  * A device (normally a server) is waiting to receive a synchronize (SYN)
409  * message from a client. It has not yet sent its own SYN message
410  *
411  * @param[in] socket Handle referencing the current socket
412  * @param[in] interface Underlying network interface
413  * @param[in] pseudoHeader TCP pseudo header
414  * @param[in] segment Incoming TCP segment
415  * @param[in] length Length of the segment data
416  **/
417 
419  IpPseudoHeader *pseudoHeader, TcpHeader *segment, size_t length)
420 {
421  uint_t i;
422  TcpOption *option;
423  TcpSynQueueItem *queueItem;
424 
425  //Debug message
426  TRACE_DEBUG("TCP FSM: LISTEN state\r\n");
427 
428  //An incoming RST should be ignored
429  if(segment->flags & TCP_FLAG_RST)
430  return;
431 
432  //Any acknowledgment is bad if it arrives on a connection
433  //still in the LISTEN state
434  if(segment->flags & TCP_FLAG_ACK)
435  {
436  //A reset segment should be formed for any arriving ACK-bearing segment
437  tcpSendResetSegment(interface, pseudoHeader, segment, length);
438  //Return immediately
439  return;
440  }
441 
442  //Check the SYN bit
443  if(segment->flags & TCP_FLAG_SYN)
444  {
445  //Silently drop duplicate SYN segments
446  if(tcpIsDuplicateSyn(socket, pseudoHeader, segment))
447  return;
448 
449  //Check whether the SYN queue is empty
450  if(socket->synQueue == NULL)
451  {
452  //Allocate memory to save incoming data
453  queueItem = memPoolAlloc(sizeof(TcpSynQueueItem));
454  //Add the newly created item to the queue
455  socket->synQueue = queueItem;
456  }
457  else
458  {
459  //Point to the very first item
460  queueItem = socket->synQueue;
461 
462  //Reach the last item in the SYN queue
463  for(i = 1; queueItem->next != NULL; i++)
464  queueItem = queueItem->next;
465 
466  //Make sure the SYN queue is not full
467  if(i >= socket->synQueueSize)
468  return;
469 
470  //Allocate memory to save incoming data
471  queueItem->next = memPoolAlloc(sizeof(TcpSynQueueItem));
472  //Point to the newly created item
473  queueItem = queueItem->next;
474  }
475 
476  //Failed to allocate memory?
477  if(queueItem == NULL)
478  return;
479 
480 #if (IPV4_SUPPORT == ENABLED)
481  //IPv4 is currently used?
482  if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
483  {
484  //Save the source IPv4 address
485  queueItem->srcAddr.length = sizeof(Ipv4Addr);
486  queueItem->srcAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr;
487  //Save the destination IPv4 address
488  queueItem->destAddr.length = sizeof(Ipv4Addr);
489  queueItem->destAddr.ipv4Addr = pseudoHeader->ipv4Data.destAddr;
490  }
491  else
492 #endif
493 #if (IPV6_SUPPORT == ENABLED)
494  //IPv6 is currently used?
495  if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
496  {
497  //Save the source IPv6 address
498  queueItem->srcAddr.length = sizeof(Ipv6Addr);
499  queueItem->srcAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr;
500  //Save the destination IPv6 address
501  queueItem->destAddr.length = sizeof(Ipv6Addr);
502  queueItem->destAddr.ipv6Addr = pseudoHeader->ipv6Data.destAddr;
503  }
504  else
505 #endif
506  //Invalid pseudo header?
507  {
508  //This should never occur...
509  return;
510  }
511 
512  //Initialize next field
513  queueItem->next = NULL;
514  //Underlying network interface
515  queueItem->interface = interface;
516  //Save the port number of the client
517  queueItem->srcPort = segment->srcPort;
518  //Save the initial sequence number
519  queueItem->isn = segment->seqNum;
520  //Default MSS value
521  queueItem->mss = MIN(TCP_DEFAULT_MSS, TCP_MAX_MSS);
522 
523  //Get the maximum segment size
524  option = tcpGetOption(segment, TCP_OPTION_MAX_SEGMENT_SIZE);
525 
526  //Specified option found?
527  if(option != NULL && option->length == 4)
528  {
529  //Retrieve MSS value
530  memcpy(&queueItem->mss, option->value, 2);
531  //Convert from network byte order to host byte order
532  queueItem->mss = ntohs(queueItem->mss);
533 
534  //Debug message
535  TRACE_DEBUG("Remote host MSS = %" PRIu16 "\r\n", queueItem->mss);
536 
537  //Make sure that the MSS advertised by the peer is acceptable
538  queueItem->mss = MIN(queueItem->mss, TCP_MAX_MSS);
539  queueItem->mss = MAX(queueItem->mss, TCP_MIN_MSS);
540  }
541 
542  //Notify user that a connection request is pending
544 
545  //The rest of the processing described in RFC 793 will be done
546  //asynchronously when socketAccept() function is called
547  }
548 }
549 
550 
551 /**
552  * @brief SYN-SENT state
553  *
554  * The device (normally a client) has sent a synchronize (SYN) message and
555  * is waiting for a matching SYN from the other device (usually a server)
556  *
557  * @param[in] socket Handle referencing the current socket
558  * @param[in] segment Incoming TCP segment
559  * @param[in] length Length of the segment data
560  **/
561 
562 void tcpStateSynSent(Socket *socket, TcpHeader *segment, size_t length)
563 {
564  TcpOption *option;
565 
566  //Debug message
567  TRACE_DEBUG("TCP FSM: SYN-SENT state\r\n");
568 
569  //Check the ACK bit
570  if(segment->flags & TCP_FLAG_ACK)
571  {
572  //Make sure the acknowledgment number is valid
573  if(segment->ackNum != socket->sndNxt)
574  {
575  //Send a reset segment unless the RST bit is set
576  if(!(segment->flags & TCP_FLAG_RST))
577  tcpSendSegment(socket, TCP_FLAG_RST, segment->ackNum, 0, 0, FALSE);
578 
579  //Drop the segment and return
580  return;
581  }
582  }
583 
584  //Check the RST bit
585  if(segment->flags & TCP_FLAG_RST)
586  {
587  //Make sure the ACK is acceptable
588  if(segment->flags & TCP_FLAG_ACK)
589  {
590  //Enter CLOSED state
592 
593  //Number of times TCP connections have made a direct transition to the
594  //CLOSED state from either the SYN-SENT state or the SYN-RECEIVED state
595  MIB2_INC_COUNTER32(tcpGroup.tcpAttemptFails, 1);
596  TCP_MIB_INC_COUNTER32(tcpAttemptFails, 1);
597  }
598 
599  //Drop the segment and return
600  return;
601  }
602 
603  //Check the SYN bit
604  if(segment->flags & TCP_FLAG_SYN)
605  {
606  //Save initial receive sequence number
607  socket->irs = segment->seqNum;
608  //Initialize RCV.NXT pointer
609  socket->rcvNxt = segment->seqNum + 1;
610 
611  //If there is an ACK, SND.UNA should be advanced to equal SEG.ACK
612  if(segment->flags & TCP_FLAG_ACK)
613  socket->sndUna = segment->ackNum;
614 
615  //Compute retransmission timeout
617 
618  //Any segments on the retransmission queue which are thereby
619  //acknowledged should be removed
621 
622  //Get the maximum segment size
623  option = tcpGetOption(segment, TCP_OPTION_MAX_SEGMENT_SIZE);
624 
625  //Specified option found?
626  if(option != NULL && option->length == 4)
627  {
628  //Retrieve MSS value
629  memcpy(&socket->smss, option->value, 2);
630  //Convert from network byte order to host byte order
631  socket->smss = ntohs(socket->smss);
632 
633  //Debug message
634  TRACE_DEBUG("Remote host MSS = %" PRIu16 "\r\n", socket->smss);
635 
636  //Make sure that the MSS advertised by the peer is acceptable
637  socket->smss = MIN(socket->smss, TCP_MAX_MSS);
638  socket->smss = MAX(socket->smss, TCP_MIN_MSS);
639  }
640 
641 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
642  //Initial congestion window
643  socket->cwnd = MIN(TCP_INITIAL_WINDOW * socket->smss, socket->txBufferSize);
644 #endif
645 
646  //Check whether our SYN has been acknowledged (SND.UNA > ISS)
647  if(TCP_CMP_SEQ(socket->sndUna, socket->iss) > 0)
648  {
649  //Update the send window before entering ESTABLISHED state (see RFC 1122 4.2.2.20)
650  socket->sndWnd = segment->window;
651  socket->sndWl1 = segment->seqNum;
652  socket->sndWl2 = segment->ackNum;
653 
654  //Maximum send window it has seen so far on the connection
655  socket->maxSndWnd = segment->window;
656 
657  //Form an ACK segment and send it
658  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE);
659  //Switch to the ESTABLISHED state
661  }
662  else
663  {
664  //Form an SYN ACK segment and send it
666  //Enter SYN-RECEIVED state
668  }
669  }
670 }
671 
672 
673 /**
674  * @brief SYN-RECEIVED state
675  *
676  * The device has both received a SYN from its partner and sent its own SYN.
677  * It is now waiting for an ACK to its SYN to finish connection setup
678  *
679  * @param[in] socket Handle referencing the current socket
680  * @param[in] segment Incoming TCP segment
681  * @param[in] buffer Multi-part buffer containing the incoming TCP segment
682  * @param[in] offset Offset to the first data byte
683  * @param[in] length Length of the segment data
684  **/
685 
687  const NetBuffer *buffer, size_t offset, size_t length)
688 {
689  //Debug message
690  TRACE_DEBUG("TCP FSM: SYN-RECEIVED state\r\n");
691 
692  //First check sequence number
693  if(tcpCheckSequenceNumber(socket, segment, length))
694  return;
695 
696  //Check the RST bit
697  if(segment->flags & TCP_FLAG_RST)
698  {
699  //Return to CLOSED state
701 
702  //Number of times TCP connections have made a direct transition to the
703  //CLOSED state from either the SYN-SENT state or the SYN-RECEIVED state
704  MIB2_INC_COUNTER32(tcpGroup.tcpAttemptFails, 1);
705  TCP_MIB_INC_COUNTER32(tcpAttemptFails, 1);
706 
707  //Return immediately
708  return;
709  }
710 
711  //Check the SYN bit
712  if(tcpCheckSyn(socket, segment, length))
713  return;
714 
715  //If the ACK bit is off drop the segment and return
716  if(!(segment->flags & TCP_FLAG_ACK))
717  return;
718 
719  //Make sure the acknowledgment number is valid
720  if(segment->ackNum != socket->sndNxt)
721  {
722  //If the segment acknowledgment is not acceptable, form a reset
723  //segment and send it
724  tcpSendSegment(socket, TCP_FLAG_RST, segment->ackNum, 0, 0, FALSE);
725 
726  //Drop the segment and return
727  return;
728  }
729 
730  //Update the send window before entering ESTABLISHED state (see RFC 1122 4.2.2.20)
731  socket->sndWnd = segment->window;
732  socket->sndWl1 = segment->seqNum;
733  socket->sndWl2 = segment->ackNum;
734 
735  //Maximum send window it has seen so far on the connection
736  socket->maxSndWnd = segment->window;
737 
738  //Enter ESTABLISHED state
740  //And continue processing...
741  tcpStateEstablished(socket, segment, buffer, offset, length);
742 }
743 
744 
745 /**
746  * @brief ESTABLISHED state
747  *
748  * Data can be exchanged freely once both devices in the connection enter
749  * this state. This will continue until the connection is closed
750  *
751  * @param[in] socket Handle referencing the current socket
752  * @param[in] segment Incoming TCP segment
753  * @param[in] buffer Multi-part buffer containing the incoming TCP segment
754  * @param[in] offset Offset to the first data byte
755  * @param[in] length Length of the segment data
756  **/
757 
759  const NetBuffer *buffer, size_t offset, size_t length)
760 {
761  uint_t flags = 0;
762 
763  //Debug message
764  TRACE_DEBUG("TCP FSM: ESTABLISHED state\r\n");
765 
766  //First check sequence number
767  if(tcpCheckSequenceNumber(socket, segment, length))
768  return;
769 
770  //Check the RST bit
771  if(segment->flags & TCP_FLAG_RST)
772  {
773  //Switch to the CLOSED state
775 
776  //Number of times TCP connections have made a direct transition to the
777  //CLOSED state from either the ESTABLISHED state or the CLOSE-WAIT state
778  MIB2_INC_COUNTER32(tcpGroup.tcpEstabResets, 1);
779  TCP_MIB_INC_COUNTER32(tcpEstabResets, 1);
780 
781  //Return immediately
782  return;
783  }
784 
785  //Check the SYN bit
786  if(tcpCheckSyn(socket, segment, length))
787  return;
788  //Check the ACK field
789  if(tcpCheckAck(socket, segment, length))
790  return;
791  //Process the segment text
792  if(length > 0)
793  tcpProcessSegmentData(socket, segment, buffer, offset, length);
794 
795  //Check the FIN bit
796  if(segment->flags & TCP_FLAG_FIN)
797  {
798  //The FIN can only be acknowledged if all the segment data
799  //has been successfully transferred to the receive buffer
800  if(socket->rcvNxt == (segment->seqNum + length))
801  {
802  //Advance RCV.NXT over the FIN
803  socket->rcvNxt++;
804  //Send an acknowledgment for the FIN
805  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE);
806  //Switch to the CLOSE-WAIT state
808  }
809  }
810 
811 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
812  //Duplicate AK received?
813  if(socket->dupAckCount > 0)
815 #endif
816 
817  //The Nagle algorithm should be implemented to coalesce
818  //short segments (refer to RFC 1122 4.2.3.4)
820 }
821 
822 
823 /**
824  * @brief CLOSE-WAIT state
825  *
826  * The device has received a close request (FIN) from the other device. It
827  * must now wait for the application to acknowledge this request and
828  * generate a matching request
829  *
830  * @param[in] socket Handle referencing the current socket
831  * @param[in] segment Incoming TCP segment
832  * @param[in] length Length of the segment data
833  **/
834 
836 {
837  uint_t flags = 0;
838 
839  //Debug message
840  TRACE_DEBUG("TCP FSM: CLOSE-WAIT state\r\n");
841 
842  //First check sequence number
843  if(tcpCheckSequenceNumber(socket, segment, length))
844  return;
845 
846  //Check the RST bit
847  if(segment->flags & TCP_FLAG_RST)
848  {
849  //Switch to the CLOSED state
851 
852  //Number of times TCP connections have made a direct transition to the
853  //CLOSED state from either the ESTABLISHED state or the CLOSE-WAIT state
854  MIB2_INC_COUNTER32(tcpGroup.tcpEstabResets, 1);
855  TCP_MIB_INC_COUNTER32(tcpEstabResets, 1);
856 
857  //Return immediately
858  return;
859  }
860 
861  //Check the SYN bit
862  if(tcpCheckSyn(socket, segment, length))
863  return;
864  //Check the ACK field
865  if(tcpCheckAck(socket, segment, length))
866  return;
867 
868 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
869  //Duplicate AK received?
870  if(socket->dupAckCount > 0)
872 #endif
873 
874  //The Nagle algorithm should be implemented to coalesce
875  //short segments (refer to RFC 1122 4.2.3.4)
877 }
878 
879 
880 /**
881  * @brief LAST-ACK state
882  *
883  * A device that has already received a close request and acknowledged it,
884  * has sent its own FIN and is waiting for an ACK to this request
885  *
886  * @param[in] socket Handle referencing the current socket
887  * @param[in] segment Incoming TCP segment
888  * @param[in] length Length of the segment data
889  **/
890 
891 void tcpStateLastAck(Socket *socket, TcpHeader *segment, size_t length)
892 {
893  //Debug message
894  TRACE_DEBUG("TCP FSM: LAST-ACK state\r\n");
895 
896  //First check sequence number
897  if(tcpCheckSequenceNumber(socket, segment, length))
898  return;
899 
900  //Check the RST bit
901  if(segment->flags & TCP_FLAG_RST)
902  {
903  //Enter CLOSED state
905  //Return immediately
906  return;
907  }
908 
909  //Check the SYN bit
910  if(tcpCheckSyn(socket, segment, length))
911  return;
912  //If the ACK bit is off drop the segment and return
913  if(!(segment->flags & TCP_FLAG_ACK))
914  return;
915 
916  //The only thing that can arrive in this state is an
917  //acknowledgment of our FIN
918  if(segment->ackNum == socket->sndNxt)
919  {
920  //Enter CLOSED state
922  }
923 }
924 
925 
926 /**
927  * @brief FIN-WAIT-1 state
928  *
929  * A device in this state is waiting for an ACK for a FIN it has sent, or
930  * is waiting for a connection termination request from the other device
931  *
932  * @param[in] socket Handle referencing the current socket
933  * @param[in] segment Incoming TCP segment
934  * @param[in] buffer Multi-part buffer containing the incoming TCP segment
935  * @param[in] offset Offset to the first data byte
936  * @param[in] length Length of the segment data
937  **/
938 
940  const NetBuffer *buffer, size_t offset, size_t length)
941 {
942  //Debug message
943  TRACE_DEBUG("TCP FSM: FIN-WAIT-1 state\r\n");
944 
945  //First check sequence number
946  if(tcpCheckSequenceNumber(socket, segment, length))
947  return;
948 
949  //Check the RST bit
950  if(segment->flags & TCP_FLAG_RST)
951  {
952  //Switch to the CLOSED state
954  //Return immediately
955  return;
956  }
957 
958  //Check the SYN bit
959  if(tcpCheckSyn(socket, segment, length))
960  return;
961  //Check the ACK field
962  if(tcpCheckAck(socket, segment, length))
963  return;
964 
965  //Check whether our FIN is now acknowledged
966  if(segment->ackNum == socket->sndNxt)
967  {
968  //Start the FIN-WAIT-2 timer to prevent the connection
969  //from staying in the FIN-WAIT-2 state forever
970  tcpTimerStart(&socket->finWait2Timer, TCP_FIN_WAIT_2_TIMER);
971  //enter FIN-WAIT-2 and continue processing in that state
973  }
974 
975  //Process the segment text
976  if(length > 0)
977  tcpProcessSegmentData(socket, segment, buffer, offset, length);
978 
979  //Check the FIN bit
980  if(segment->flags & TCP_FLAG_FIN)
981  {
982  //The FIN can only be acknowledged if all the segment data
983  //has been successfully transferred to the receive buffer
984  if(socket->rcvNxt == (segment->seqNum + length))
985  {
986  //Advance RCV.NXT over the FIN
987  socket->rcvNxt++;
988  //Send an acknowledgment for the FIN
989  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE);
990 
991  //Check if our FIN has been acknowledged
992  if(segment->ackNum == socket->sndNxt)
993  {
994  //Release previously allocated resources
996  //Start the 2MSL timer
997  tcpTimerStart(&socket->timeWaitTimer, TCP_2MSL_TIMER);
998  //Switch to the TIME-WAIT state
1000  }
1001  else
1002  {
1003  //If our FIN has not been acknowledged, then enter CLOSING state
1005  }
1006  }
1007  }
1008 }
1009 
1010 
1011 /**
1012  * @brief FIN-WAIT-2 state
1013  *
1014  * A device in this state has received an ACK for its request to terminate the
1015  * connection and is now waiting for a matching FIN from the other device
1016  *
1017  * @param[in] socket Handle referencing the current socket
1018  * @param[in] segment Incoming TCP segment
1019  * @param[in] buffer Multi-part buffer containing the incoming TCP segment
1020  * @param[in] offset Offset to the first data byte
1021  * @param[in] length Length of the segment data
1022  **/
1023 
1025  const NetBuffer *buffer, size_t offset, size_t length)
1026 {
1027  //Debug message
1028  TRACE_DEBUG("TCP FSM: FIN-WAIT-2 state\r\n");
1029 
1030  //First check sequence number
1031  if(tcpCheckSequenceNumber(socket, segment, length))
1032  return;
1033 
1034  //Check the RST bit
1035  if(segment->flags & TCP_FLAG_RST)
1036  {
1037  //Switch to the CLOSED state
1039  //Return immediately
1040  return;
1041  }
1042 
1043  //Check the SYN bit
1044  if(tcpCheckSyn(socket, segment, length))
1045  return;
1046  //Check the ACK field
1047  if(tcpCheckAck(socket, segment, length))
1048  return;
1049  //Process the segment text
1050  if(length > 0)
1051  tcpProcessSegmentData(socket, segment, buffer, offset, length);
1052 
1053  //Check the FIN bit
1054  if(segment->flags & TCP_FLAG_FIN)
1055  {
1056  //The FIN can only be acknowledged if all the segment data
1057  //has been successfully transferred to the receive buffer
1058  if(socket->rcvNxt == (segment->seqNum + length))
1059  {
1060  //Advance RCV.NXT over the FIN
1061  socket->rcvNxt++;
1062  //Send an acknowledgment for the FIN
1063  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE);
1064 
1065  //Release previously allocated resources
1067  //Start the 2MSL timer
1068  tcpTimerStart(&socket->timeWaitTimer, TCP_2MSL_TIMER);
1069  //Switch to the TIME_WAIT state
1071  }
1072  }
1073 }
1074 
1075 
1076 /**
1077  * @brief CLOSING state
1078  *
1079  * The device has received a FIN from the other device and sent an ACK for
1080  * it, but not yet received an ACK for its own FIN message
1081  *
1082  * @param[in] socket Handle referencing the current socket
1083  * @param[in] segment Incoming TCP segment
1084  * @param[in] length Length of the segment data
1085  **/
1086 
1088 {
1089  //Debug message
1090  TRACE_DEBUG("TCP FSM: CLOSING state\r\n");
1091 
1092  //First check sequence number
1093  if(tcpCheckSequenceNumber(socket, segment, length))
1094  return;
1095 
1096  //Check the RST bit
1097  if(segment->flags & TCP_FLAG_RST)
1098  {
1099  //Enter CLOSED state
1101  //Return immediately
1102  return;
1103  }
1104 
1105  //Check the SYN bit
1106  if(tcpCheckSyn(socket, segment, length))
1107  return;
1108  //Check the ACK field
1109  if(tcpCheckAck(socket, segment, length))
1110  return;
1111 
1112  //If the ACK acknowledges our FIN then enter the TIME-WAIT
1113  //state, otherwise ignore the segment
1114  if(segment->ackNum == socket->sndNxt)
1115  {
1116  //Release previously allocated resources
1118  //Start the 2MSL timer
1119  tcpTimerStart(&socket->timeWaitTimer, TCP_2MSL_TIMER);
1120  //Switch to the TIME-WAIT state
1122  }
1123 }
1124 
1125 
1126 /**
1127  * @brief TIME-WAIT state
1128  *
1129  * The device has now received a FIN from the other device and acknowledged
1130  * it, and sent its own FIN and received an ACK for it. We are done, except
1131  * for waiting to ensure the ACK is received and prevent potential overlap
1132  * with new connections
1133  *
1134  * @param[in] socket Handle referencing the current socket
1135  * @param[in] segment Incoming TCP segment
1136  * @param[in] length Length of the segment data
1137  **/
1138 
1140 {
1141  //Debug message
1142  TRACE_DEBUG("TCP FSM: TIME-WAIT state\r\n");
1143 
1144  //First check sequence number
1145  if(tcpCheckSequenceNumber(socket, segment, length))
1146  return;
1147 
1148  //Check the RST bit
1149  if(segment->flags & TCP_FLAG_RST)
1150  {
1151  //Enter CLOSED state
1153 
1154  //Dispose the socket if the user does not have the ownership anymore
1155  if(!socket->ownedFlag)
1156  {
1157  //Delete the TCB
1159  //Mark the socket as closed
1160  socket->type = SOCKET_TYPE_UNUSED;
1161  }
1162 
1163  //Return immediately
1164  return;
1165  }
1166 
1167  //Check the SYN bit
1168  if(tcpCheckSyn(socket, segment, length))
1169  return;
1170  //If the ACK bit is off drop the segment and return
1171  if(!(segment->flags & TCP_FLAG_ACK))
1172  return;
1173 
1174  //The only thing that can arrive in this state is a retransmission
1175  //of the remote FIN. Acknowledge it and restart the 2 MSL timeout
1176  if(segment->flags & TCP_FLAG_FIN)
1177  {
1178  //Send an acknowledgment for the FIN
1179  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE);
1180  //Restart the 2MSL timer
1181  tcpTimerStart(&socket->timeWaitTimer, TCP_2MSL_TIMER);
1182  }
1183 }
1184 
1185 #endif
bool_t ipv4IsBroadcastAddr(NetInterface *interface, Ipv4Addr ipAddr)
Check whether an IPv4 address is a broadcast address.
Definition: ipv4.c:1275
#define TCP_2MSL_TIMER
Definition: tcp.h:192
SYN queue item.
Definition: tcp.h:370
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:232
NetInterface * interface
Definition: tcp.h:373
error_t tcpCheckSyn(Socket *socket, TcpHeader *segment, size_t length)
Check the SYN bit of an incoming segment.
Definition: tcp_misc.c:592
#define TCP_MIB_INC_COUNTER64(name, value)
#define TCP_MIB_INC_COUNTER32(name, value)
#define TCP_MAX_MSS
Definition: tcp.h:52
bool_t tcpIsDuplicateSyn(Socket *socket, IpPseudoHeader *pseudoHeader, TcpHeader *segment)
Test whether the incoming SYN segment is a duplicate.
Definition: tcp_misc.c:817
void tcpStateLastAck(Socket *socket, TcpHeader *segment, size_t length)
LAST-ACK state.
Definition: tcp_fsm.c:891
uint8_t flags
Definition: tcp.h:312
#define TCP_FIN_WAIT_2_TIMER
Definition: tcp.h:185
#define ipv6IsMulticastAddr(ipAddr)
Definition: ipv6.h:131
Ipv4Addr ipv4Addr
Definition: ip.h:63
systime_t osGetSystemTime(void)
Retrieve system time.
uint32_t isn
Definition: tcp.h:377
error_t tcpCheckSequenceNumber(Socket *socket, TcpHeader *segment, size_t length)
Test the sequence number of an incoming segment.
Definition: tcp_misc.c:523
TCP/IP stack core.
void tcpProcessSegmentData(Socket *socket, TcpHeader *segment, const NetBuffer *buffer, size_t offset, size_t length)
Process the segment text.
Definition: tcp_misc.c:1061
Debugging facilities.
void tcpStateSynSent(Socket *socket, TcpHeader *segment, size_t length)
SYN-SENT state.
Definition: tcp_fsm.c:562
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:295
MIB-II module.
__start_packed struct @124 TcpHeader
TCP header.
IPv4 and IPv6 common routines.
__start_packed struct @183 Ipv6Addr
IPv6 network address.
void * memPoolAlloc(size_t size)
Allocate a memory block.
Definition: net_mem.c:98
uint16_t ipCalcUpperLayerChecksumEx(const void *pseudoHeader, size_t pseudoHeaderLen, const NetBuffer *buffer, size_t offset, size_t length)
Calculate IP upper-layer checksum over a multi-part buffer.
Definition: ip.c:571
#define SOCKET_MAX_COUNT
Definition: socket.h:43
void tcpDumpHeader(const TcpHeader *segment, size_t length, uint32_t iss, uint32_t irs)
Dump TCP header for debugging purpose.
Definition: tcp_misc.c:2065
#define MIB2_INC_COUNTER32(name, value)
Definition: mib2_module.h:154
#define Ipv4PseudoHeader
Definition: ipv4.h:37
void tcpUpdateRetransmitQueue(Socket *socket)
Remove acknowledged segments from retransmission queue.
Definition: tcp_misc.c:1149
#define MAX(a, b)
Definition: os_port.h:64
void tcpDeleteControlBlock(Socket *socket)
Delete TCB structure.
Definition: tcp_misc.c:1128
#define TRUE
Definition: os_port.h:48
int_t socket(int_t family, int_t type, int_t protocol)
Create a socket that is bound to a specific transport service provider.
Definition: bsd_socket.c:106
error_t tcpSendSegment(Socket *socket, uint8_t flags, uint32_t seqNum, uint32_t ackNum, size_t length, bool_t addToQueue)
Send a TCP segment.
Definition: tcp_misc.c:63
Socket socketTable[SOCKET_MAX_COUNT]
Definition: socket.c:46
void tcpStateClosed(NetInterface *interface, IpPseudoHeader *pseudoHeader, TcpHeader *segment, size_t length)
CLOSED state.
Definition: tcp_fsm.c:392
error_t tcpSendResetSegment(NetInterface *interface, IpPseudoHeader *pseudoHeader, TcpHeader *segment, size_t length)
Send a TCP reset in response to an invalid segment.
Definition: tcp_misc.c:283
#define Socket
Definition: socket.h:34
#define ntohl(value)
Definition: cpu_endian.h:397
void tcpStateEstablished(Socket *socket, TcpHeader *segment, const NetBuffer *buffer, size_t offset, size_t length)
ESTABLISHED state.
Definition: tcp_fsm.c:758
uint8_t data[4]
Definition: ip.h:87
TcpOption * tcpGetOption(TcpHeader *segment, uint8_t kind)
Find a specified option in a TCP segment.
Definition: tcp_misc.c:467
const char_t * formatSystemTime(systime_t time, char_t *str)
Format system time.
Definition: date_time.c:75
#define ntohs(value)
Definition: cpu_endian.h:396
size_t length
Definition: ip.h:78
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
Definition: net_mem.c:411
Date and time management.
bool_t tcpComputeRto(Socket *socket)
Compute retransmission timeout.
Definition: tcp_misc.c:1422
IPv4 (Internet Protocol Version 4)
#define TCP_CMP_SEQ(a, b)
Definition: tcp.h:217
error_t tcpNagleAlgo(Socket *socket, uint_t flags)
Nagle algorithm implementation.
Definition: tcp_misc.c:1594
void tcpStateFinWait1(Socket *socket, TcpHeader *segment, const NetBuffer *buffer, size_t offset, size_t length)
FIN-WAIT-1 state.
Definition: tcp_fsm.c:939
void tcpStateCloseWait(Socket *socket, TcpHeader *segment, size_t length)
CLOSE-WAIT state.
Definition: tcp_fsm.c:835
#define Ipv6PseudoHeader
Definition: ipv6.h:40
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:86
#define MIN(a, b)
Definition: os_port.h:60
uint16_t mss
Definition: tcp.h:378
uint16_t srcPort
Definition: tcp.h:375
IPv6 (Internet Protocol Version 6)
IpAddr destAddr
Definition: tcp.h:376
#define TRACE_WARNING(...)
Definition: debug.h:78
size_t length
Definition: ip.h:59
unsigned int uint_t
Definition: compiler_port.h:43
void tcpStateClosing(Socket *socket, TcpHeader *segment, size_t length)
CLOSING state.
Definition: tcp_fsm.c:1087
error_t tcpCheckAck(Socket *socket, TcpHeader *segment, size_t length)
Test the ACK field of an incoming segment.
Definition: tcp_misc.c:626
Ipv6Addr ipv6Addr
Definition: ip.h:66
#define PRIuSIZE
Definition: compiler_port.h:72
#define NetInterface
Definition: net.h:34
void tcpStateFinWait2(Socket *socket, TcpHeader *segment, const NetBuffer *buffer, size_t offset, size_t length)
FIN-WAIT-2 state.
Definition: tcp_fsm.c:1024
Helper functions for TCP.
#define ipv4IsMulticastAddr(ipAddr)
Definition: ipv4.h:150
void tcpChangeState(Socket *socket, TcpState newState)
Update TCP FSM current state.
Definition: tcp_misc.c:1723
void tcpUpdateEvents(Socket *socket)
Update TCP related events.
Definition: tcp_misc.c:1754
IpAddr srcAddr
Definition: tcp.h:374
IP pseudo header.
Definition: ip.h:76
#define TCP_MIN_MSS
Definition: tcp.h:59
void tcpTimerStart(TcpTimer *timer, systime_t delay)
Start TCP timer.
Definition: tcp_timer.c:272
Ipv6PseudoHeader ipv6Data
Definition: ip.h:85
void tcpStateTimeWait(Socket *socket, TcpHeader *segment, size_t length)
TIME-WAIT state.
Definition: tcp_fsm.c:1139
struct _TcpSynQueueItem * next
Definition: tcp.h:372
Ipv4PseudoHeader ipv4Data
Definition: ip.h:82
Socket API.
void tcpStateListen(Socket *socket, NetInterface *interface, IpPseudoHeader *pseudoHeader, TcpHeader *segment, size_t length)
LISTEN state.
Definition: tcp_fsm.c:418
uint8_t length
Definition: dtls_misc.h:140
void tcpStateSynReceived(Socket *socket, TcpHeader *segment, const NetBuffer *buffer, size_t offset, size_t length)
SYN-RECEIVED state.
Definition: tcp_fsm.c:686
TCP (Transmission Control Protocol)
TCP MIB module.
#define TCP_DEFAULT_MSS
Definition: tcp.h:214
#define FALSE
Definition: os_port.h:44
TCP finite state machine.
#define ipv6CompAddr(ipAddr1, ipAddr2)
Definition: ipv6.h:119
TCP timer management.
void tcpProcessSegment(NetInterface *interface, IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
Incoming TCP segment processing.
Definition: tcp_fsm.c:70
__start_packed struct @125 TcpOption
TCP option.
#define TRACE_DEBUG(...)
Definition: debug.h:98
#define TCP_INITIAL_WINDOW
Definition: tcp.h:150