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