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