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