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