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