tcp_misc.c
Go to the documentation of this file.
1 /**
2  * @file tcp_misc.c
3  * @brief Helper functions for TCP
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL TCP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "core/socket.h"
37 #include "core/tcp.h"
38 #include "core/tcp_misc.h"
39 #include "core/tcp_timer.h"
40 #include "core/ip.h"
41 #include "ipv4/ipv4.h"
42 #include "ipv6/ipv6.h"
43 #include "mibs/mib2_module.h"
44 #include "mibs/tcp_mib_module.h"
45 #include "date_time.h"
46 #include "debug.h"
47 
48 //Secure initial sequence number generation?
49 #if (TCP_SECURE_ISN_SUPPORT == ENABLED)
50  #include "hash/md5.h"
51 #endif
52 
53 //Check TCP/IP stack configuration
54 #if (TCP_SUPPORT == ENABLED)
55 
56 
57 /**
58  * @brief Send a TCP segment
59  * @param[in] socket Handle referencing a socket
60  * @param[in] flags Value that contains bitwise OR of flags (see #TcpFlags enumeration)
61  * @param[in] seqNum Sequence number
62  * @param[in] ackNum Acknowledgment number
63  * @param[in] length Length of the segment data
64  * @param[in] addToQueue Add the segment to retransmission queue
65  * @return Error code
66  **/
67 
69  uint32_t ackNum, size_t length, bool_t addToQueue)
70 {
71  error_t error;
72  uint16_t mss;
73  size_t offset;
74  size_t totalLength;
75  NetBuffer *buffer;
76  TcpHeader *segment;
77  TcpQueueItem *queueItem;
78  IpPseudoHeader pseudoHeader;
79  NetTxAncillary ancillary;
80 
81  //Maximum segment size
82  mss = HTONS(socket->rmss);
83 
84  //Allocate a memory buffer to hold the TCP segment
85  buffer = ipAllocBuffer(TCP_MAX_HEADER_LENGTH, &offset);
86  //Failed to allocate memory?
87  if(buffer == NULL)
88  return ERROR_OUT_OF_MEMORY;
89 
90  //Point to the beginning of the TCP segment
91  segment = netBufferAt(buffer, offset, 0);
92 
93  //Format TCP header
94  segment->srcPort = htons(socket->localPort);
95  segment->destPort = htons(socket->remotePort);
96  segment->seqNum = htonl(seqNum);
97  segment->ackNum = (flags & TCP_FLAG_ACK) ? htonl(ackNum) : 0;
98  segment->reserved1 = 0;
99  segment->dataOffset = sizeof(TcpHeader) / 4;
100  segment->flags = flags;
101  segment->reserved2 = 0;
102  segment->checksum = 0;
103  segment->urgentPointer = 0;
104 
105  //SYN flag set?
106  if((flags & TCP_FLAG_SYN) != 0)
107  {
108  //Append Maximum Segment Size option
110  sizeof(uint16_t));
111  }
112 
113 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
114  //SYN flag set?
115  if((flags & TCP_FLAG_SYN) != 0)
116  {
117  //Check ACK flag
118  if((flags & TCP_FLAG_ACK) == 0)
119  {
120  //The TCP Window Scale option may be sent in an initial SYN segment
121  //(refer to RFC 7323, section 2.2)
123  &socket->rcvWndShift, sizeof(uint8_t));
124  }
125  else
126  {
127  //If a Window Scale option was received in the initial SYN segment,
128  //then this option may be sent in the SYN/ACK segment
129  if(socket->wndScaleOptionReceived)
130  {
132  &socket->rcvWndShift, sizeof(uint8_t));
133  }
134  }
135 
136  //The window field in a segment where the SYN bit is set must not be
137  //scaled (refer to RFC 7323, section 2.2)
138  segment->window = htons(MIN(socket->rcvWnd, UINT16_MAX));
139  }
140  else
141  {
142  //Check whether window scaling is enabled
143  if(socket->wndScaleOptionReceived)
144  {
145  //The window field (SEG.WND) of every outgoing segment, with the
146  //exception of SYN segments, must be right-shifted by Rcv.Wind.Shift
147  //bits (refer to RFC 7323, section 2.3)
148  segment->window = htons(socket->rcvWnd >> socket->rcvWndShift);
149  }
150  else
151  {
152  //The maximum unscaled window is 2^16 - 1
153  segment->window = htons(MIN(socket->rcvWnd, UINT16_MAX));
154  }
155  }
156 #else
157  //The window field indicates the number of data octets beginning with the
158  //one indicated in the acknowledgment field that the sender of this segment
159  //is willing to accept (refer to RFC 793, section 3.1)
160  segment->window = htons(MIN(socket->rcvWnd, UINT16_MAX));
161 #endif
162 
163 #if (TCP_SACK_SUPPORT == ENABLED)
164  //SYN flag set?
165  if((flags & TCP_FLAG_SYN) != 0)
166  {
167  //Append SACK Permitted option
168  tcpAddOption(segment, TCP_OPTION_SACK_PERMITTED, NULL, 0);
169  }
170 
171  //ACK flag set?
172  if((flags & TCP_FLAG_ACK) != 0)
173  {
174  //If the data receiver has not received a SACK Permitted option for a
175  //given connection, it must not send SACK options on that connection
176  if(socket->sackPermitted)
177  {
178  //SACK options should be included in all ACKs which do not ACK the
179  //highest sequence number in the data receiver's queue. In this
180  //situation the network has lost or mis-ordered data, such that the
181  //receiver holds non-contiguous data in its queue
182  if(socket->sackBlockCount > 0 &&
183  socket->sackBlockCount <= TCP_MAX_SACK_BLOCKS)
184  {
185  uint_t i;
186  uint32_t data[TCP_MAX_SACK_BLOCKS * 2];
187 
188  //This option contains a list of some of the blocks of contiguous
189  //sequence space occupied by data that has been received and queued
190  //within the window
191  for(i = 0; i < socket->sackBlockCount; i++)
192  {
193  data[i * 2] = htonl(socket->sackBlock[i].leftEdge);
194  data[i * 2 + 1] = htonl(socket->sackBlock[i].rightEdge);
195  }
196 
197  //Append SACK option
198  tcpAddOption(segment, TCP_OPTION_SACK, data, socket->sackBlockCount * 8);
199  }
200  }
201  }
202 #endif
203 
204  //Adjust the length of the multi-part buffer
205  netBufferSetLength(buffer, offset + segment->dataOffset * 4);
206 
207  //Any data to send?
208  if(length > 0)
209  {
210  //Copy data
211  error = tcpReadTxBuffer(socket, seqNum, buffer, length);
212  //Any error to report?
213  if(error)
214  {
215  //Clean up side effects
216  netBufferFree(buffer);
217  //Exit immediately
218  return error;
219  }
220  }
221 
222  //Calculate the length of the complete TCP segment
223  totalLength = segment->dataOffset * 4 + length;
224 
225 #if (IPV4_SUPPORT == ENABLED)
226  //Destination address is an IPv4 address?
227  if(socket->remoteIpAddr.length == sizeof(Ipv4Addr))
228  {
229  //Format IPv4 pseudo header
230  pseudoHeader.length = sizeof(Ipv4PseudoHeader);
231  pseudoHeader.ipv4Data.srcAddr = socket->localIpAddr.ipv4Addr;
232  pseudoHeader.ipv4Data.destAddr = socket->remoteIpAddr.ipv4Addr;
233  pseudoHeader.ipv4Data.reserved = 0;
234  pseudoHeader.ipv4Data.protocol = IPV4_PROTOCOL_TCP;
235  pseudoHeader.ipv4Data.length = htons(totalLength);
236 
237  //Calculate TCP header checksum
238  segment->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader.ipv4Data,
239  sizeof(Ipv4PseudoHeader), buffer, offset, totalLength);
240  }
241  else
242 #endif
243 #if (IPV6_SUPPORT == ENABLED)
244  //Destination address is an IPv6 address?
245  if(socket->remoteIpAddr.length == sizeof(Ipv6Addr))
246  {
247  //Format IPv6 pseudo header
248  pseudoHeader.length = sizeof(Ipv6PseudoHeader);
249  pseudoHeader.ipv6Data.srcAddr = socket->localIpAddr.ipv6Addr;
250  pseudoHeader.ipv6Data.destAddr = socket->remoteIpAddr.ipv6Addr;
251  pseudoHeader.ipv6Data.length = htonl(totalLength);
252  pseudoHeader.ipv6Data.reserved[0] = 0;
253  pseudoHeader.ipv6Data.reserved[1] = 0;
254  pseudoHeader.ipv6Data.reserved[2] = 0;
255  pseudoHeader.ipv6Data.nextHeader = IPV6_TCP_HEADER;
256 
257  //Calculate TCP header checksum
258  segment->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader.ipv6Data,
259  sizeof(Ipv6PseudoHeader), buffer, offset, totalLength);
260  }
261  else
262 #endif
263  //Destination address is not valid?
264  {
265  //Free previously allocated memory
266  netBufferFree(buffer);
267  //This should never occur...
268  return ERROR_INVALID_ADDRESS;
269  }
270 
271  //Add current segment to retransmission queue?
272  if(addToQueue)
273  {
274  //Empty retransmission queue?
275  if(socket->retransmitQueue == NULL)
276  {
277  //Create a new item
278  queueItem = memPoolAlloc(sizeof(TcpQueueItem));
279  //Add the newly created item to the queue
280  socket->retransmitQueue = queueItem;
281  }
282  else
283  {
284  //Point to the very first item
285  queueItem = socket->retransmitQueue;
286 
287  //Reach the last item of the retransmission queue
288  while(queueItem->next != NULL)
289  {
290  queueItem = queueItem->next;
291  }
292 
293  //Create a new item
294  queueItem->next = memPoolAlloc(sizeof(TcpQueueItem));
295  //Point to the newly created item
296  queueItem = queueItem->next;
297  }
298 
299  //Failed to allocate memory?
300  if(queueItem == NULL)
301  {
302  //Free previously allocated memory
303  netBufferFree(buffer);
304  //Return status
305  return ERROR_OUT_OF_MEMORY;
306  }
307 
308  //Retransmission mechanism requires additional information
309  queueItem->next = NULL;
310  queueItem->length = length;
311  queueItem->sacked = FALSE;
312 
313  //Save TCP header
314  osMemcpy(queueItem->header, segment, segment->dataOffset * 4);
315  //Save pseudo header
316  queueItem->pseudoHeader = pseudoHeader;
317 
318  //Take one RTT measurement at a time
319  if(!socket->rttBusy)
320  {
321  //Save round-trip start time
322  socket->rttStartTime = osGetSystemTime();
323  //Record current sequence number
324  socket->rttSeqNum = ntohl(segment->seqNum);
325  //Wait for an acknowledgment that covers that sequence number...
326  socket->rttBusy = TRUE;
327 
328 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
329  //Reset the byte counter
330  socket->n = 0;
331 #endif
332  }
333 
334  //Check whether the RTO timer is running or not
335  if(!netTimerRunning(&socket->retransmitTimer))
336  {
337  //If the timer is not running, start it running so that it will expire
338  //after RTO seconds
339  netStartTimer(&socket->retransmitTimer, socket->rto);
340 
341  //Reset retransmission counter
342  socket->retransmitCount = 0;
343  }
344  }
345 
346 #if (TCP_KEEP_ALIVE_SUPPORT == ENABLED)
347  //Check whether TCP keep-alive mechanism is enabled
348  if(socket->keepAliveEnabled)
349  {
350  //Idle condition?
351  if(socket->keepAliveProbeCount == 0)
352  {
353  //SYN or data packet?
354  if((flags & TCP_FLAG_SYN) != 0 || length > 0)
355  {
356  //Restart keep-alive timer
357  socket->keepAliveTimestamp = osGetSystemTime();
358  }
359  }
360  }
361 #endif
362 
363  //Total number of segments sent
364  MIB2_TCP_INC_COUNTER32(tcpOutSegs, 1);
365  TCP_MIB_INC_COUNTER32(tcpOutSegs, 1);
366  TCP_MIB_INC_COUNTER64(tcpHCOutSegs, 1);
367 
368  //RST flag set?
369  if((flags & TCP_FLAG_RST) != 0)
370  {
371  //Number of TCP segments sent containing the RST flag
372  MIB2_TCP_INC_COUNTER32(tcpOutRsts, 1);
373  TCP_MIB_INC_COUNTER32(tcpOutRsts, 1);
374  }
375 
376  //Debug message
377  TRACE_DEBUG("%s: Sending TCP segment (%" PRIuSIZE " data bytes)...\r\n",
379 
380  //Dump TCP header contents for debugging purpose
381  tcpDumpHeader(segment, length, socket->iss, socket->irs);
382 
383  //Additional options can be passed to the stack along with the packet
384  ancillary = NET_DEFAULT_TX_ANCILLARY;
385  //Set the TTL value to be used
386  ancillary.ttl = socket->ttl;
387  //Set ToS field
388  ancillary.tos = socket->tos;
389 
390 #if (ETH_VLAN_SUPPORT == ENABLED)
391  //Set VLAN PCP and DEI fields
392  ancillary.vlanPcp = socket->vlanPcp;
393  ancillary.vlanDei = socket->vlanDei;
394 #endif
395 
396 #if (ETH_VMAN_SUPPORT == ENABLED)
397  //Set VMAN PCP and DEI fields
398  ancillary.vmanPcp = socket->vmanPcp;
399  ancillary.vmanDei = socket->vmanDei;
400 #endif
401 
402  //Send TCP segment
403  (void) ipSendDatagram(socket->interface, &pseudoHeader, buffer, offset,
404  &ancillary);
405 
406  //Free previously allocated memory
407  netBufferFree(buffer);
408 
409  //Successful processing
410  return NO_ERROR;
411 }
412 
413 
414 /**
415  * @brief Send a TCP reset segment
416  * @param[in] socket Handle referencing a socket
417  * @param[in] seqNum Sequence number
418  * @return Error code
419  **/
420 
422 {
423  error_t error;
424 
425  //Initialize status code
426  error = NO_ERROR;
427 
428  //Check current state
429  if(socket->state == TCP_STATE_SYN_SENT ||
430  socket->state == TCP_STATE_SYN_RECEIVED ||
431  socket->state == TCP_STATE_ESTABLISHED ||
432  socket->state == TCP_STATE_FIN_WAIT_1 ||
433  socket->state == TCP_STATE_FIN_WAIT_2 ||
434  socket->state == TCP_STATE_CLOSE_WAIT)
435  {
436  //Send a reset segment
437  error = tcpSendSegment(socket, TCP_FLAG_RST, seqNum, 0, 0, FALSE);
438  }
439 
440  //Return status code
441  return error;
442 }
443 
444 
445 /**
446  * @brief Send a TCP reset in response to an invalid segment
447  * @param[in] interface Underlying network interface
448  * @param[in] pseudoHeader TCP pseudo header describing the incoming segment
449  * @param[in] segment Incoming TCP segment
450  * @param[in] length Length of the incoming segment data
451  * @return Error code
452  **/
453 
455  const IpPseudoHeader *pseudoHeader, const TcpHeader *segment, size_t length)
456 {
457  error_t error;
458  size_t offset;
459  uint8_t flags;
460  uint32_t seqNum;
461  uint32_t ackNum;
462  NetBuffer *buffer;
463  TcpHeader *segment2;
464  IpPseudoHeader pseudoHeader2;
465  NetTxAncillary ancillary;
466 
467  //Check whether the ACK bit is set
468  if((segment->flags & TCP_FLAG_ACK) != 0)
469  {
470  //If the incoming segment has an ACK field, the reset takes
471  //its sequence number from the ACK field of the segment
473  seqNum = segment->ackNum;
474  ackNum = 0;
475  }
476  else
477  {
478  //Otherwise the reset has sequence number zero and the ACK field is set to
479  //the sum of the sequence number and segment length of the incoming segment
481  seqNum = 0;
482  ackNum = segment->seqNum + length;
483 
484  //Advance the acknowledgment number over the SYN or the FIN
485  if((segment->flags & TCP_FLAG_SYN) != 0)
486  {
487  ackNum++;
488  }
489 
490  if((segment->flags & TCP_FLAG_FIN) != 0)
491  {
492  ackNum++;
493  }
494  }
495 
496  //Allocate a memory buffer to hold the reset segment
497  buffer = ipAllocBuffer(sizeof(TcpHeader), &offset);
498  //Failed to allocate memory?
499  if(buffer == NULL)
500  return ERROR_OUT_OF_MEMORY;
501 
502  //Point to the beginning of the TCP segment
503  segment2 = netBufferAt(buffer, offset, 0);
504 
505  //Format TCP header
506  segment2->srcPort = htons(segment->destPort);
507  segment2->destPort = htons(segment->srcPort);
508  segment2->seqNum = htonl(seqNum);
509  segment2->ackNum = htonl(ackNum);
510  segment2->reserved1 = 0;
511  segment2->dataOffset = 5;
512  segment2->flags = flags;
513  segment2->reserved2 = 0;
514  segment2->window = 0;
515  segment2->checksum = 0;
516  segment2->urgentPointer = 0;
517 
518 #if (IPV4_SUPPORT == ENABLED)
519  //Destination address is an IPv4 address?
520  if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
521  {
522  //Format IPv4 pseudo header
523  pseudoHeader2.length = sizeof(Ipv4PseudoHeader);
524  pseudoHeader2.ipv4Data.srcAddr = pseudoHeader->ipv4Data.destAddr;
525  pseudoHeader2.ipv4Data.destAddr = pseudoHeader->ipv4Data.srcAddr;
526  pseudoHeader2.ipv4Data.reserved = 0;
527  pseudoHeader2.ipv4Data.protocol = IPV4_PROTOCOL_TCP;
528  pseudoHeader2.ipv4Data.length = HTONS(sizeof(TcpHeader));
529 
530  //Calculate TCP header checksum
531  segment2->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader2.ipv4Data,
532  sizeof(Ipv4PseudoHeader), buffer, offset, sizeof(TcpHeader));
533  }
534  else
535 #endif
536 #if (IPV6_SUPPORT == ENABLED)
537  //Destination address is an IPv6 address?
538  if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
539  {
540  //Format IPv6 pseudo header
541  pseudoHeader2.length = sizeof(Ipv6PseudoHeader);
542  pseudoHeader2.ipv6Data.srcAddr = pseudoHeader->ipv6Data.destAddr;
543  pseudoHeader2.ipv6Data.destAddr = pseudoHeader->ipv6Data.srcAddr;
544  pseudoHeader2.ipv6Data.length = HTONL(sizeof(TcpHeader));
545  pseudoHeader2.ipv6Data.reserved[0] = 0;
546  pseudoHeader2.ipv6Data.reserved[1] = 0;
547  pseudoHeader2.ipv6Data.reserved[2] = 0;
548  pseudoHeader2.ipv6Data.nextHeader = IPV6_TCP_HEADER;
549 
550  //Calculate TCP header checksum
551  segment2->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader2.ipv6Data,
552  sizeof(Ipv6PseudoHeader), buffer, offset, sizeof(TcpHeader));
553  }
554  else
555 #endif
556  //Destination address is not valid?
557  {
558  //Free previously allocated memory
559  netBufferFree(buffer);
560  //This should never occur...
561  return ERROR_INVALID_ADDRESS;
562  }
563 
564  //Total number of segments sent
565  MIB2_TCP_INC_COUNTER32(tcpOutSegs, 1);
566  TCP_MIB_INC_COUNTER32(tcpOutSegs, 1);
567  TCP_MIB_INC_COUNTER64(tcpHCOutSegs, 1);
568 
569  //Number of TCP segments sent containing the RST flag
570  MIB2_TCP_INC_COUNTER32(tcpOutRsts, 1);
571  TCP_MIB_INC_COUNTER32(tcpOutRsts, 1);
572 
573  //Debug message
574  TRACE_DEBUG("%s: Sending TCP reset segment...\r\n",
576 
577  //Dump TCP header contents for debugging purpose
578  tcpDumpHeader(segment2, length, 0, 0);
579 
580  //Additional options can be passed to the stack along with the packet
581  ancillary = NET_DEFAULT_TX_ANCILLARY;
582 
583  //Send TCP segment
584  error = ipSendDatagram(interface, &pseudoHeader2, buffer, offset,
585  &ancillary);
586 
587  //Free previously allocated memory
588  netBufferFree(buffer);
589 
590  //Return error code
591  return error;
592 }
593 
594 
595 /**
596  * @brief Append an option to the TCP header
597  * @param[in] segment Pointer to the TCP header
598  * @param[in] kind Option code
599  * @param[in] value Option value
600  * @param[in] length Length of the option value, in bytes
601  * @return Error code
602  **/
603 
604 error_t tcpAddOption(TcpHeader *segment, uint8_t kind, const void *value,
605  uint8_t length)
606 {
607  error_t error;
608  size_t i;
609  size_t paddingSize;
610  TcpOption *option;
611 
612  //The option-length counts the two octets of option-kind and option-length
613  //as well as the option-data octets (refer to RFC 793, section 3.1)
614  length += sizeof(TcpOption);
615 
616  //Make sure there is enough room to add the option
617  if((segment->dataOffset * 4 + length) <= TCP_MAX_HEADER_LENGTH)
618  {
619  //Index of the first available byte
620  i = (segment->dataOffset * 4) - sizeof(TcpHeader);
621 
622  //Calculate the number of padding bytes
623  paddingSize = (length % 4) ? 4 - (length % 4) : 0;
624 
625  //Write padding bytes
626  while(paddingSize--)
627  {
628  segment->options[i++] = TCP_OPTION_NOP;
629  }
630 
631  //Point to the current location
632  option = (TcpOption *) (segment->options + i);
633 
634  //Format option
635  option->kind = kind;
636  option->length = length;
637  osMemcpy(option->value, value, length - sizeof(TcpOption));
638 
639  //Adjust index value
640  i += length;
641 
642  //Update the length of the TCP header
643  segment->dataOffset = (sizeof(TcpHeader) + i) / 4;
644 
645  //Successful processing
646  error = NO_ERROR;
647  }
648  else
649  {
650  //Report an error
651  error = ERROR_FAILURE;
652  }
653 
654  //Return status code
655  return error;
656 }
657 
658 
659 /**
660  * @brief Search the TCP header for a given option
661  * @param[in] segment Pointer to the TCP header
662  * @param[in] kind Code of the option to find
663  * @return If the specified option is found, a pointer to the corresponding
664  * option is returned. Otherwise NULL pointer is returned
665  **/
666 
667 const TcpOption *tcpGetOption(const TcpHeader *segment, uint8_t kind)
668 {
669  size_t i;
670  size_t length;
671  TcpOption *option;
672 
673  //Make sure the TCP header is valid
674  if(segment->dataOffset >= (sizeof(TcpHeader) / 4))
675  {
676  //Compute the length of the options field
677  length = (segment->dataOffset * 4) - sizeof(TcpHeader);
678 
679  //Point to the very first option
680  i = 0;
681 
682  //Loop through the list of options
683  while(i < length)
684  {
685  //Point to the current option
686  option = (TcpOption *) (segment->options + i);
687 
688  //Check option code
689  if(option->kind == TCP_OPTION_END)
690  {
691  //This option code indicates the end of the option list
692  break;
693  }
694  else if(option->kind == TCP_OPTION_NOP)
695  {
696  //This option consists of a single octet
697  i++;
698  }
699  else
700  {
701  //The option code is followed by a one-byte length field
702  if((i + 1) >= length)
703  {
704  break;
705  }
706 
707  //Check the length of the option
708  if(option->length < sizeof(TcpOption) ||
709  (i + option->length) > length)
710  {
711  break;
712  }
713 
714  //Matching option code?
715  if(option->kind == kind)
716  {
717  return option;
718  }
719 
720  //Jump to the next option
721  i += option->length;
722  }
723  }
724  }
725 
726  //The specified option code was not found
727  return NULL;
728 }
729 
730 
731 /**
732  * @brief Initial sequence number generation
733  * @param[in] socket Handle referencing the current socket
734  * @return Value of the initial sequence number
735  **/
736 
738 {
739 #if (TCP_SECURE_ISN_SUPPORT == ENABLED)
740  uint32_t isn;
741  Md5Context md5Context;
742  uint8_t digest[MD5_DIGEST_SIZE];
743 
744  //Generate the initial sequence number as per RFC 6528
745  md5Init(&md5Context);
746  md5Update(&md5Context, &socket->localIpAddr, sizeof(IpAddr));
747  md5Update(&md5Context, &socket->localPort, sizeof(uint16_t));
748  md5Update(&md5Context, &socket->remoteIpAddr, sizeof(IpAddr));
749  md5Update(&md5Context, &socket->remotePort, sizeof(uint16_t));
750  md5Update(&md5Context, socket->netContext->randSeed, NET_RAND_SEED_SIZE);
751  md5Final(&md5Context, digest);
752 
753  //Extract the first 32 bits from the digest value
754  isn = LOAD32BE(digest);
755 
756  //Calculate ISN = M + F(localip, localport, remoteip, remoteport, secretkey)
757  return isn + netGetSystemTickCount();
758 #else
759  //Generate a random initial sequence number
760  return netGenerateRand(socket->netContext);
761 #endif
762 }
763 
764 
765 /**
766  * @brief Test the sequence number of an incoming segment
767  * @param[in] socket Handle referencing the current socket
768  * @param[in] segment Pointer to the TCP segment to check
769  * @param[in] length Length of the segment data
770  * @return NO_ERROR if the incoming segment is acceptable, ERROR_FAILURE otherwise
771  **/
772 
774 {
775  bool_t acceptable;
776 
777  //Due to zero windows and zero length segments, we have four cases for the
778  //acceptability of an incoming segment (refer to RFC 793, section 3.3)
779  if(length == 0 && socket->rcvWnd == 0)
780  {
781  //If both segment length and receive window are zero, then test if
782  //SEG.SEQ = RCV.NXT
783  if(segment->seqNum == socket->rcvNxt)
784  {
785  acceptable = TRUE;
786  }
787  else
788  {
789  acceptable = FALSE;
790  }
791  }
792  else if(length == 0 && socket->rcvWnd != 0)
793  {
794  //If segment length is zero and receive window is non zero, then test if
795  //RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND
796  if(TCP_CMP_SEQ(segment->seqNum, socket->rcvNxt) >= 0 &&
797  TCP_CMP_SEQ(segment->seqNum, socket->rcvNxt + socket->rcvWnd) < 0)
798  {
799  acceptable = TRUE;
800  }
801  else
802  {
803  acceptable = FALSE;
804  }
805  }
806  else if(length != 0 && socket->rcvWnd == 0)
807  {
808  //If segment length is non zero and receive window is zero, then the
809  //sequence number is not acceptable
810  acceptable = FALSE;
811  }
812  else
813  {
814  //If both segment length and receive window are non zero, then test if
815  //RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND or
816  //RCV.NXT <= SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
817  if(TCP_CMP_SEQ(segment->seqNum, socket->rcvNxt) >= 0 &&
818  TCP_CMP_SEQ(segment->seqNum, socket->rcvNxt + socket->rcvWnd) < 0)
819  {
820  acceptable = TRUE;
821  }
822  else if(TCP_CMP_SEQ(segment->seqNum + length - 1, socket->rcvNxt) >= 0 &&
823  TCP_CMP_SEQ(segment->seqNum + length - 1, socket->rcvNxt + socket->rcvWnd) < 0)
824  {
825  acceptable = TRUE;
826  }
827  else
828  {
829  acceptable = FALSE;
830  }
831  }
832 
833  //Non acceptable sequence number?
834  if(!acceptable)
835  {
836  //Debug message
837  TRACE_WARNING("Sequence number is not acceptable!\r\n");
838 
839  //If an incoming segment is not acceptable, an acknowledgment should
840  //be sent in reply (unless the RST bit is set)
841  if((segment->flags & TCP_FLAG_RST) == 0)
842  {
843  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt,
844  0, FALSE);
845  }
846 
847  //Return status code
848  return ERROR_FAILURE;
849  }
850 
851  //Sequence number is acceptable
852  return NO_ERROR;
853 }
854 
855 
856 /**
857  * @brief Check the SYN bit of an incoming segment
858  * @param[in] socket Handle referencing the current socket
859  * @param[in] segment Pointer to the TCP segment to check
860  * @param[in] length Length of the segment data
861  * @return ERROR_FAILURE if the SYN is in the window, NO_ERROR otherwise
862  **/
863 
864 error_t tcpCheckSyn(Socket *socket, const TcpHeader *segment, size_t length)
865 {
866  //Check whether the SYN bit is set
867  if((segment->flags & TCP_FLAG_SYN) != 0)
868  {
869  //If this step is reached, the SYN is in the window. It is an error
870  //and a reset shall be sent in response
871  if((segment->flags & TCP_FLAG_ACK) != 0)
872  {
873  tcpSendResetSegment(socket, segment->ackNum);
874  }
875  else
876  {
878  segment->seqNum + length + 1, 0, FALSE);
879  }
880 
881  //Return immediately
882  return ERROR_FAILURE;
883  }
884 
885  //No error to report
886  return NO_ERROR;
887 }
888 
889 
890 /**
891  * @brief Test the ACK field of an incoming segment
892  * @param[in] socket Handle referencing the current socket
893  * @param[in] segment Pointer to the TCP segment to check
894  * @param[in] length Length of the segment data
895  * @return NO_ERROR if the acknowledgment is acceptable, ERROR_FAILURE otherwise
896  **/
897 
898 error_t tcpCheckAck(Socket *socket, const TcpHeader *segment, size_t length)
899 {
900  bool_t duplicateFlag;
901  bool_t updateFlag;
902 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
903  uint32_t n;
904  uint32_t ownd;
905  uint32_t thresh;
906 #endif
907 
908  //If the ACK bit is off drop the segment and return
909  if((segment->flags & TCP_FLAG_ACK) == 0)
910  return ERROR_FAILURE;
911 
912 #if (TCP_KEEP_ALIVE_SUPPORT == ENABLED)
913  //Check whether TCP keep-alive mechanism is enabled
914  if(socket->keepAliveEnabled)
915  {
916  //Reset keep-alive probe counter
917  socket->keepAliveProbeCount = 0;
918  }
919 #endif
920 
921  //Test the case where SEG.ACK < SND.UNA
922  if(TCP_CMP_SEQ(segment->ackNum, socket->sndUna) < 0)
923  {
924  //An old duplicate ACK has been received
925  return NO_ERROR;
926  }
927  //Test the case where SEG.ACK > SND.NXT
928  else if(TCP_CMP_SEQ(segment->ackNum, socket->sndNxt) > 0)
929  {
930  //Send an ACK segment indicating the current send sequence number
931  //and the acknowledgment number expected to be received
932  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0,
933  FALSE);
934 
935  //The ACK segment acknowledges something not yet sent
936  return ERROR_FAILURE;
937  }
938 
939  //Check whether the ACK is a duplicate
940  duplicateFlag = tcpIsDuplicateAck(socket, segment, length);
941  (void) duplicateFlag;
942 
943  //The send window should be updated
944  tcpUpdateSendWindow(socket, segment);
945 
946  //The incoming ACK segment acknowledges new data?
947  if(TCP_CMP_SEQ(segment->ackNum, socket->sndUna) > 0)
948  {
949 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
950  //Compute the number of bytes acknowledged by the incoming ACK
951  n = segment->ackNum - socket->sndUna;
952 
953  //Check whether the ACK segment acknowledges our SYN
954  if(socket->sndUna == socket->iss)
955  {
956  n--;
957  }
958 
959  //Total number of bytes acknowledged during the whole round-trip
960  socket->n += n;
961 #endif
962  //Update SND.UNA pointer
963  socket->sndUna = segment->ackNum;
964 
965  //Compute retransmission timeout
966  updateFlag = tcpComputeRto(socket);
967  (void) updateFlag;
968 
969  //Any segments on the retransmission queue which are thereby entirely
970  //acknowledged are removed
972 
973 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
974  //Check congestion state
975  if(socket->congestState == TCP_CONGEST_STATE_RECOVERY)
976  {
977  //Invoke fast recovery (refer to RFC 6582)
978  tcpFastRecovery(socket, segment, n);
979  }
980  else
981  {
982  //Reset duplicate ACK counter
983  socket->dupAckCount = 0;
984 
985  //Check congestion state
986  if(socket->congestState == TCP_CONGEST_STATE_LOSS_RECOVERY)
987  {
988  //Invoke fast loss recovery
989  tcpFastLossRecovery(socket, segment);
990  }
991 
992  //Slow start algorithm is used when cwnd is lower than ssthresh
993  if(socket->cwnd < socket->ssthresh)
994  {
995  //During slow start, TCP increments cwnd by at most SMSS bytes
996  //for each ACK received that cumulatively acknowledges new data
997  socket->cwnd += MIN(n, socket->smss);
998  }
999  //Congestion avoidance algorithm is used when cwnd exceeds ssthres
1000  else
1001  {
1002  //Congestion window is updated once per RTT
1003  if(updateFlag)
1004  {
1005  //TCP must not increment cwnd by more than SMSS bytes
1006  socket->cwnd += MIN(socket->n, socket->smss);
1007  }
1008  }
1009  }
1010 
1011  //Limit the size of the congestion window
1012  socket->cwnd = MIN(socket->cwnd, socket->txBufferSize);
1013 #endif
1014  }
1015  //The incoming ACK segment does not acknowledge new data?
1016  else
1017  {
1018 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1019  //Check whether the acknowledgment is a duplicate
1020  if(duplicateFlag)
1021  {
1022  //Increment duplicate ACK counter
1023  socket->dupAckCount++;
1024  //Debug message
1025  TRACE_INFO("TCP duplicate ACK #%u\r\n", socket->dupAckCount);
1026  }
1027  else
1028  {
1029  //Reset duplicate ACK counter
1030  socket->dupAckCount = 0;
1031  }
1032 
1033  //Check congestion state
1034  if(socket->congestState == TCP_CONGEST_STATE_IDLE)
1035  {
1036  //Use default duplicate ACK threshold
1037  thresh = TCP_FAST_RETRANSMIT_THRES;
1038  //Amount of data sent but not yet acknowledged
1039  ownd = socket->sndNxt - socket->sndUna;
1040 
1041  //Test if there is either no unsent data ready for transmission at
1042  //the sender, or the advertised receive window does not permit new
1043  //segments to be transmitted (refer to RFC 5827 section 3.1)
1044  if(socket->sndUser == 0 || socket->sndWnd <= (socket->sndNxt - socket->sndUna))
1045  {
1046  //Compute the duplicate ACK threshold used to trigger a
1047  //retransmission
1048  if(ownd <= ((uint32_t) socket->smss * 3))
1049  {
1050  thresh = 1;
1051  }
1052  else if(ownd <= ((uint32_t) socket->smss * 4))
1053  {
1054  thresh = 2;
1055  }
1056  else
1057  {
1058  }
1059  }
1060 
1061  //Check the number of duplicate ACKs that have been received
1062  if(socket->dupAckCount >= thresh)
1063  {
1064  //The TCP sender first checks the value of recover to see if the
1065  //cumulative acknowledgment field covers more than recover
1066  if(TCP_CMP_SEQ(segment->ackNum, socket->recover + 1) > 0)
1067  {
1068  //Invoke Fast Retransmit (refer to RFC 6582)
1070  }
1071  else
1072  {
1073  //If not, the TCP does not enter fast retransmit and does not
1074  //reset ssthres...
1075  }
1076  }
1077  }
1078  else if(socket->congestState == TCP_CONGEST_STATE_RECOVERY)
1079  {
1080  //Duplicate ACK received?
1081  if(duplicateFlag)
1082  {
1083  //For each additional duplicate ACK received (after the third),
1084  //cwnd must be incremented by SMSS. This artificially inflates
1085  //the congestion window in order to reflect the additional
1086  //segment that has left the network
1087  socket->cwnd += socket->smss;
1088  }
1089  }
1090 
1091  //Limit the size of the congestion window
1092  socket->cwnd = MIN(socket->cwnd, socket->txBufferSize);
1093 #endif
1094  }
1095 
1096  //Update TX events
1098 
1099  //No error to report
1100  return NO_ERROR;
1101 }
1102 
1103 
1104 /**
1105  * @brief Test whether the incoming SYN segment is a duplicate
1106  * @param[in] socket Handle referencing the current socket
1107  * @param[in] pseudoHeader TCP pseudo header
1108  * @param[in] segment Pointer to the TCP segment to check
1109  * @return TRUE if the SYN segment is duplicate, else FALSE
1110  **/
1111 
1113  const TcpHeader *segment)
1114 {
1115  bool_t flag;
1116  TcpSynQueueItem *queueItem;
1117 
1118  //Initialize flag
1119  flag = FALSE;
1120 
1121  //Point to the very first item
1122  queueItem = socket->synQueue;
1123 
1124  //Loop through the SYN queue
1125  while(queueItem != NULL)
1126  {
1127 #if (IPV4_SUPPORT == ENABLED)
1128  //IPv4 packet received?
1129  if(queueItem->srcAddr.length == sizeof(Ipv4Addr) &&
1130  queueItem->destAddr.length == sizeof(Ipv4Addr) &&
1131  pseudoHeader->length == sizeof(Ipv4PseudoHeader))
1132  {
1133  //Check source and destination addresses
1134  if(queueItem->srcAddr.ipv4Addr == pseudoHeader->ipv4Data.srcAddr &&
1135  queueItem->destAddr.ipv4Addr == pseudoHeader->ipv4Data.destAddr)
1136  {
1137  //Check source port
1138  if(queueItem->srcPort == segment->srcPort)
1139  {
1140  //Duplicate SYN
1141  flag = TRUE;
1142  }
1143  }
1144  }
1145  else
1146 #endif
1147 #if (IPV6_SUPPORT == ENABLED)
1148  //IPv6 packet received?
1149  if(queueItem->srcAddr.length == sizeof(Ipv6Addr) &&
1150  queueItem->destAddr.length == sizeof(Ipv6Addr) &&
1151  pseudoHeader->length == sizeof(Ipv6PseudoHeader))
1152  {
1153  //Check source and destination addresses
1154  if(ipv6CompAddr(&queueItem->srcAddr.ipv6Addr, &pseudoHeader->ipv6Data.srcAddr) &&
1155  ipv6CompAddr(&queueItem->destAddr.ipv6Addr, &pseudoHeader->ipv6Data.destAddr))
1156  {
1157  //Check source port
1158  if(queueItem->srcPort == segment->srcPort)
1159  {
1160  //Duplicate SYN
1161  flag = TRUE;
1162  }
1163  }
1164  }
1165  else
1166 #endif
1167  {
1168  //Just for sanity
1169  }
1170 
1171  //Next item
1172  queueItem = queueItem->next;
1173  }
1174 
1175  //Return TRUE if the SYN segment is a duplicate
1176  return flag;
1177 }
1178 
1179 
1180 /**
1181  * @brief Test whether the incoming acknowledgment is a duplicate
1182  * @param[in] socket Handle referencing the current socket
1183  * @param[in] segment Pointer to the TCP segment to check
1184  * @param[in] length Length of the segment data
1185  * @return TRUE if the ACK is duplicate, else FALSE
1186  **/
1187 
1189  size_t length)
1190 {
1191  bool_t flag;
1192 
1193  //An ACK is considered a duplicate when the following conditions are met
1194  flag = FALSE;
1195 
1196  //The receiver of the ACK has outstanding data
1197  if(socket->retransmitQueue != NULL)
1198  {
1199  //The incoming acknowledgment carries no data
1200  if(length == 0)
1201  {
1202  //The SYN and FIN bits are both off
1203  if((segment->flags & (TCP_FLAG_SYN | TCP_FLAG_FIN)) == 0)
1204  {
1205  //The acknowledgment number is equal to the greatest acknowledgment
1206  //received on the given connection
1207  if(segment->ackNum == socket->sndUna)
1208  {
1209  //The advertised window in the incoming acknowledgment equals
1210  //the advertised window in the last incoming acknowledgment
1211  if(segment->window == socket->sndWnd)
1212  {
1213  //Duplicate ACK
1214  flag = TRUE;
1215  }
1216  }
1217  }
1218  }
1219  }
1220 
1221  //Return TRUE if the acknowledgment is a duplicate
1222  return flag;
1223 }
1224 
1225 
1226 /**
1227  * @brief Fast retransmit procedure
1228  * @param[in] socket Handle referencing the current socket
1229  **/
1230 
1232 {
1233 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1234  uint32_t flightSize;
1235 
1236  //Amount of data that has been sent but not yet acknowledged
1237  flightSize = socket->sndNxt - socket->sndUna;
1238  //After receiving 3 duplicate ACKs, ssthresh must be adjusted
1239  socket->ssthresh = MAX(flightSize / 2, (uint32_t) socket->smss * 2);
1240 
1241  //The value of recover is incremented to the value of the highest
1242  //sequence number transmitted by the TCP so far
1243  socket->recover = socket->sndNxt - 1;
1244 
1245  //Debug message
1246  TRACE_INFO("TCP fast retransmit...\r\n");
1247 
1248  //TCP performs a retransmission of what appears to be the missing segment,
1249  //without waiting for the retransmission timer to expire
1251 
1252  //cwnd must set to ssthresh plus 3*SMSS. This artificially inflates the
1253  //congestion window by the number of segments (three) that have left the
1254  //network and which the receiver has buffered
1255  socket->cwnd = socket->ssthresh + (socket->smss * TCP_FAST_RETRANSMIT_THRES);
1256 
1257  //Enter the fast recovery procedure
1258  socket->congestState = TCP_CONGEST_STATE_RECOVERY;
1259 #endif
1260 }
1261 
1262 
1263 /**
1264  * @brief Fast recovery procedure
1265  * @param[in] socket Handle referencing the current socket
1266  * @param[in] segment Pointer to the incoming TCP segment
1267  * @param[in] n Number of bytes acknowledged by the incoming ACK
1268  **/
1269 
1270 void tcpFastRecovery(Socket *socket, const TcpHeader *segment, uint32_t n)
1271 {
1272 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1273  //Check whether this ACK acknowledges all of the data up to and including
1274  //recover
1275  if(TCP_CMP_SEQ(segment->ackNum, socket->recover) > 0)
1276  {
1277  //This is a full acknowledgment
1278  TRACE_INFO("TCP full acknowledgment\r\n");
1279 
1280  //Set cwnd to ssthresh
1281  socket->cwnd = socket->ssthresh;
1282  //Exit the fast recovery procedure
1283  socket->congestState = TCP_CONGEST_STATE_IDLE;
1284  }
1285  else
1286  {
1287  //If this ACK does not acknowledge all of the data up to and including
1288  //recover, then this is a partial ACK
1289  TRACE_INFO("TCP partial acknowledgment\r\n");
1290 
1291  //Retransmit the first unacknowledged segment
1293 
1294  //Deflate the congestion window by the amount of new data acknowledged
1295  //by the cumulative acknowledgment field
1296  if(socket->cwnd > n)
1297  socket->cwnd -= n;
1298 
1299  //If the partial ACK acknowledges at least one SMSS of new data, then
1300  //add back SMSS bytes to the congestion window. This artificially
1301  //inflates the congestion window in order to reflect the additional
1302  //segment that has left the network
1303  if(n >= socket->smss)
1304  socket->cwnd += socket->smss;
1305 
1306  //Do not exit the fast recovery procedure...
1307  socket->congestState = TCP_CONGEST_STATE_RECOVERY;
1308  }
1309 #endif
1310 }
1311 
1312 
1313 /**
1314  * @brief Fast loss recovery procedure
1315  * @param[in] socket Handle referencing the current socket
1316  * @param[in] segment Pointer to the incoming TCP segment
1317  **/
1318 
1320 {
1321 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1322  //Check whether this ACK acknowledges all of the data up to and
1323  //including recover
1324  if(TCP_CMP_SEQ(segment->ackNum, socket->recover) > 0)
1325  {
1326  //This is a full acknowledgment
1327  TRACE_INFO("TCP full acknowledgment\r\n");
1328 
1329  //Exit the fast loss recovery procedure
1330  socket->congestState = TCP_CONGEST_STATE_IDLE;
1331  }
1332  else
1333  {
1334  //If this ACK does not acknowledge all of the data up to and including
1335  //recover, then this is a partial ACK
1336  TRACE_INFO("TCP partial acknowledgment\r\n");
1337 
1338  //Retransmit the first unacknowledged segment
1340 
1341  //Do not exit the fast loss recovery procedure...
1342  socket->congestState = TCP_CONGEST_STATE_LOSS_RECOVERY;
1343  }
1344 #endif
1345 }
1346 
1347 
1348 /**
1349  * @brief Process the segment text
1350  * @param[in] socket Handle referencing the current socket
1351  * @param[in] segment Pointer to the TCP header
1352  * @param[in] buffer Multi-part buffer containing the incoming TCP segment
1353  * @param[in] offset Offset to the first data byte
1354  * @param[in] length Length of the segment data
1355  **/
1356 
1358  const NetBuffer *buffer, size_t offset, size_t length)
1359 {
1360  uint32_t leftEdge;
1361  uint32_t rightEdge;
1362 
1363  //First sequence number occupied by the incoming segment
1364  leftEdge = segment->seqNum;
1365  //Sequence number immediately following the incoming segment
1366  rightEdge = segment->seqNum + length;
1367 
1368  //Check whether some data falls outside the receive window
1369  if(TCP_CMP_SEQ(leftEdge, socket->rcvNxt) < 0)
1370  {
1371  //Position of the first byte to be read
1372  offset += socket->rcvNxt - leftEdge;
1373  //Ignore the data that falls outside the receive window
1374  leftEdge = socket->rcvNxt;
1375  }
1376 
1377  if(TCP_CMP_SEQ(rightEdge, socket->rcvNxt + socket->rcvWnd) > 0)
1378  {
1379  //Ignore the data that falls outside the receive window
1380  rightEdge = socket->rcvNxt + socket->rcvWnd;
1381  }
1382 
1383  //Copy the incoming data to the receive buffer
1384  tcpWriteRxBuffer(socket, leftEdge, buffer, offset, rightEdge - leftEdge);
1385 
1386  //Update the list of non-contiguous blocks of data that have been received
1387  //and queued
1388  tcpUpdateSackBlocks(socket, &leftEdge, &rightEdge);
1389 
1390  //Check whether the segment was received out of order
1391  if(TCP_CMP_SEQ(leftEdge, socket->rcvNxt) > 0)
1392  {
1393  //Out of order data segments should be acknowledged immediately, in order
1394  //to accelerate loss recovery
1395  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0,
1396  FALSE);
1397  }
1398  else
1399  {
1400  //Number of contiguous bytes that have been received
1401  length = rightEdge - leftEdge;
1402 
1403  //Next sequence number expected on incoming segments
1404  socket->rcvNxt += length;
1405  //Number of data available in the receive buffer
1406  socket->rcvUser += length;
1407  //Update the receive window
1408  socket->rcvWnd -= length;
1409 
1410  //Acknowledge the received data (delayed ACK not supported)
1411  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0,
1412  FALSE);
1413 
1414  //Notify user task that data is available
1416  }
1417 }
1418 
1419 
1420 /**
1421  * @brief Delete TCB structure
1422  * @param[in] socket Handle referencing the socket
1423  **/
1424 
1426 {
1427  //Delete retransmission queue
1429 
1430  //Delete SYN queue
1432 
1433  //Release transmit buffer
1434  netBufferSetLength((NetBuffer *) &socket->txBuffer, 0);
1435 
1436  //Release receive buffer
1437  netBufferSetLength((NetBuffer *) &socket->rxBuffer, 0);
1438 }
1439 
1440 
1441 /**
1442  * @brief Remove acknowledged segments from retransmission queue
1443  * @param[in] socket Handle referencing the socket
1444  **/
1445 
1447 {
1448  size_t length;
1449  TcpQueueItem *prevQueueItem;
1450  TcpQueueItem *queueItem;
1451  TcpHeader *header;
1452 
1453  //Point to the first item of the retransmission queue
1454  prevQueueItem = NULL;
1455  queueItem = socket->retransmitQueue;
1456 
1457  //Loop through retransmission queue
1458  while(queueItem != NULL)
1459  {
1460  //Point to the TCP header
1461  header = (TcpHeader *) queueItem->header;
1462 
1463  //Calculate the length of the TCP segment
1464  if(header->flags & TCP_FLAG_SYN)
1465  {
1466  length = 1;
1467  }
1468  else if(header->flags & TCP_FLAG_FIN)
1469  {
1470  length = queueItem->length + 1;
1471  }
1472  else
1473  {
1474  length = queueItem->length;
1475  }
1476 
1477  //If an acknowledgment is received for a segment before its timer
1478  //expires, the segment is removed from the retransmission queue
1479  if(TCP_CMP_SEQ(socket->sndUna, ntohl(header->seqNum) + length) >= 0)
1480  {
1481  //First item of the queue?
1482  if(prevQueueItem == NULL)
1483  {
1484  //Remove the current item from the queue
1485  socket->retransmitQueue = queueItem->next;
1486  //The item can now be safely deleted
1487  memPoolFree(queueItem);
1488  //Point to the next item
1489  queueItem = socket->retransmitQueue;
1490  }
1491  else
1492  {
1493  //Remove the current item from the queue
1494  prevQueueItem->next = queueItem->next;
1495  //The item can now be safely deleted
1496  memPoolFree(queueItem);
1497  //Point to the next item
1498  queueItem = prevQueueItem->next;
1499  }
1500 
1501  //When an ACK is received that acknowledges new data, restart the
1502  //retransmission timer so that it will expire after RTO seconds
1503  netStartTimer(&socket->retransmitTimer, socket->rto);
1504  //Reset retransmission counter
1505  socket->retransmitCount = 0;
1506  }
1507  //No acknowledgment received for the current segment...
1508  else
1509  {
1510  //Point to the next item
1511  prevQueueItem = queueItem;
1512  queueItem = queueItem->next;
1513  }
1514  }
1515 
1516  //When all outstanding data has been acknowledged,
1517  //turn off the retransmission timer
1518  if(socket->retransmitQueue == NULL)
1519  netStopTimer(&socket->retransmitTimer);
1520 }
1521 
1522 
1523 /**
1524  * @brief Flush retransmission queue
1525  * @param[in] socket Handle referencing the socket
1526  **/
1527 
1529 {
1530  //Point to the first item in the retransmission queue
1531  TcpQueueItem *queueItem = socket->retransmitQueue;
1532 
1533  //Loop through retransmission queue
1534  while(queueItem != NULL)
1535  {
1536  //Keep track of the next item in the queue
1537  TcpQueueItem *nextQueueItem = queueItem->next;
1538  //Free previously allocated memory
1539  memPoolFree(queueItem);
1540  //Point to the next item
1541  queueItem = nextQueueItem;
1542  }
1543 
1544  //The retransmission queue is now flushed
1545  socket->retransmitQueue = NULL;
1546 
1547  //Turn off the retransmission timer
1548  netStopTimer(&socket->retransmitTimer);
1549 }
1550 
1551 
1552 /**
1553  * @brief Flush SYN queue
1554  * @param[in] socket Handle referencing the socket
1555  **/
1556 
1558 {
1559  //Point to the first item in the SYN queue
1560  TcpSynQueueItem *queueItem = socket->synQueue;
1561 
1562  //Loop through SYN queue
1563  while(queueItem != NULL)
1564  {
1565  //Keep track of the next item in the queue
1566  TcpSynQueueItem *nextQueueItem = queueItem->next;
1567  //Free previously allocated memory
1568  memPoolFree(queueItem);
1569  //Point to the next item
1570  queueItem = nextQueueItem;
1571  }
1572 
1573  //SYN queue was successfully flushed
1574  socket->synQueue = NULL;
1575 }
1576 
1577 
1578 /**
1579  * @brief Compute the window scale factor to use for the receive window
1580  * @param[in] socket Handle referencing the socket
1581  **/
1582 
1584 {
1585 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
1586  uint32_t n;
1587  uint32_t window;
1588 
1589  //The window scale extension expands the definition of the TCP window to
1590  //30 bits and then uses an implicit scale factor to carry this 30-bit
1591  //value in the 16-bit window field of the TCP header
1592  window = socket->rxBufferSize;
1593 
1594  //The scale factor is determined by the maximum receive buffer space
1595  for(n = 0; window > UINT16_MAX; n++)
1596  {
1597  window >>= 1;
1598  }
1599 
1600  //The window scale is fixed in each direction when a connection is opened
1601  socket->rcvWndShift = n;
1602 #endif
1603 }
1604 
1605 
1606 /**
1607  * @brief Update the list of non-contiguous blocks that have been received
1608  * @param[in] socket Handle referencing the socket
1609  * @param[in,out] leftEdge First sequence number occupied by the incoming data
1610  * @param[in,out] rightEdge Sequence number immediately following the incoming data
1611  **/
1612 
1613 void tcpUpdateSackBlocks(Socket *socket, uint32_t *leftEdge, uint32_t *rightEdge)
1614 {
1615  uint_t i = 0;
1616 
1617  //Loop through the blocks
1618  while(i < socket->sackBlockCount)
1619  {
1620  //Find each block that overlaps the specified one
1621  if(TCP_CMP_SEQ(*rightEdge, socket->sackBlock[i].leftEdge) >= 0 &&
1622  TCP_CMP_SEQ(*leftEdge, socket->sackBlock[i].rightEdge) <= 0)
1623  {
1624  //Merge blocks to form a contiguous one
1625  *leftEdge = MIN(*leftEdge, socket->sackBlock[i].leftEdge);
1626  *rightEdge = MAX(*rightEdge, socket->sackBlock[i].rightEdge);
1627 
1628  //Delete current block
1629  osMemmove(socket->sackBlock + i, socket->sackBlock + i + 1,
1630  (TCP_MAX_SACK_BLOCKS - i - 1) * sizeof(TcpSackBlock));
1631 
1632  //Decrement the number of non-contiguous blocks
1633  socket->sackBlockCount--;
1634  }
1635  else
1636  {
1637  //Point to the next block
1638  i++;
1639  }
1640  }
1641 
1642  //Check whether the incoming segment was received out of order
1643  if(TCP_CMP_SEQ(*leftEdge, socket->rcvNxt) > 0)
1644  {
1645  //Make room for the new non-contiguous block
1646  osMemmove(socket->sackBlock + 1, socket->sackBlock,
1647  (TCP_MAX_SACK_BLOCKS - 1) * sizeof(TcpSackBlock));
1648 
1649  //Insert the element in the list
1650  socket->sackBlock[0].leftEdge = *leftEdge;
1651  socket->sackBlock[0].rightEdge = *rightEdge;
1652 
1653  //Increment the number of non-contiguous blocks
1654  if(socket->sackBlockCount < TCP_MAX_SACK_BLOCKS)
1655  {
1656  socket->sackBlockCount++;
1657  }
1658  }
1659 }
1660 
1661 
1662 /**
1663  * @brief Update send window
1664  * @param[in] socket Handle referencing the socket
1665  * @param[in] segment Pointer to the incoming TCP segment
1666  **/
1667 
1669 {
1670  uint32_t window;
1671 
1672 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
1673  //The window field (SEG.WND) in the header of every incoming segment, with
1674  //the exception of SYN segments, MUST be left-shifted by Snd.Wind.Shift bits
1675  //before updating SND.WND (refer to RFC 7323, section 2.3)
1676  window = (uint32_t) segment->window << socket->sndWndShift;
1677 #else
1678  //The maximum unscaled window is 2^16 - 1
1679  window = segment->window;
1680 #endif
1681 
1682  //Case where neither the sequence nor the acknowledgment number is increased
1683  if(segment->seqNum == socket->sndWl1 && segment->ackNum == socket->sndWl2)
1684  {
1685  //TCP may ignore a window update with a smaller window than previously
1686  //offered if neither the sequence number nor the acknowledgment number
1687  //is increased (refer to RFC 1122, section 4.2.2.16)
1688  if(window > socket->sndWnd)
1689  {
1690  //Update the send window and record the sequence number and the
1691  //acknowledgment number used to update SND.WND
1692  socket->sndWnd = window;
1693  socket->sndWl1 = segment->seqNum;
1694  socket->sndWl2 = segment->ackNum;
1695 
1696  //Maximum send window it has seen so far on the connection
1697  socket->maxSndWnd = MAX(socket->maxSndWnd, window);
1698  }
1699  }
1700  //Case where the sequence or the acknowledgment number is increased
1701  else if(TCP_CMP_SEQ(segment->seqNum, socket->sndWl1) >= 0 &&
1702  TCP_CMP_SEQ(segment->ackNum, socket->sndWl2) >= 0)
1703  {
1704  //Check whether the remote host advertises a zero window
1705  if(window == 0 && socket->sndWnd != 0)
1706  {
1707  //Start the persist timer
1708  socket->wndProbeCount = 0;
1709  socket->wndProbeInterval = TCP_DEFAULT_PROBE_INTERVAL;
1710  netStartTimer(&socket->persistTimer, socket->wndProbeInterval);
1711  }
1712 
1713  //Update the send window and record the sequence number and the
1714  //acknowledgment number used to update SND.WND
1715  socket->sndWnd = window;
1716  socket->sndWl1 = segment->seqNum;
1717  socket->sndWl2 = segment->ackNum;
1718 
1719  //Maximum send window it has seen so far on the connection
1720  socket->maxSndWnd = MAX(socket->maxSndWnd, window);
1721  }
1722  else
1723  {
1724  //Just for sanity
1725  }
1726 }
1727 
1728 
1729 /**
1730  * @brief Update receive window so as to avoid Silly Window Syndrome
1731  * @param[in] socket Handle referencing the socket
1732  **/
1733 
1735 {
1736  uint32_t reduction;
1737 
1738  //Space available but not yet advertised
1739  reduction = socket->rxBufferSize - socket->rcvUser - socket->rcvWnd;
1740 
1741  //To avoid SWS, the receiver should not advertise small windows
1742  if((socket->rcvWnd + reduction) >= MIN(socket->rmss, socket->rxBufferSize / 2))
1743  {
1744  //Check whether a window update should be sent
1745  if(socket->rcvWnd < MIN(socket->rmss, socket->rxBufferSize / 2))
1746  {
1747  //Debug message
1748  TRACE_INFO("%s: TCP sending window update...\r\n",
1750 
1751  //Update the receive window
1752  socket->rcvWnd += reduction;
1753 
1754  //Send an ACK segment to advertise the new window size
1755  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt,
1756  0, FALSE);
1757  }
1758  else
1759  {
1760  //The receive window can be updated
1761  socket->rcvWnd += reduction;
1762  }
1763  }
1764 }
1765 
1766 
1767 /**
1768  * @brief Compute retransmission timeout
1769  * @param[in] socket Handle referencing the socket
1770  * @return TRUE if the RTT measurement is complete, else FALSE
1771  **/
1772 
1774 {
1775  bool_t flag;
1776  systime_t r;
1777  systime_t delta;
1778 
1779  //Clear flag
1780  flag = FALSE;
1781 
1782  //TCP implementation takes one RTT measurement at a time
1783  if(socket->rttBusy)
1784  {
1785  //Ensure the incoming ACK number covers the expected sequence number
1786  if(TCP_CMP_SEQ(socket->sndUna, socket->rttSeqNum) > 0)
1787  {
1788  //Calculate round-time trip
1789  r = osGetSystemTime() - socket->rttStartTime;
1790 
1791  //First RTT measurement?
1792  if(socket->srtt == 0 && socket->rttvar == 0)
1793  {
1794  //Initialize RTO calculation algorithm
1795  socket->srtt = r;
1796  socket->rttvar = r / 2;
1797  }
1798  else
1799  {
1800  //Calculate the difference between the measured value and the
1801  //current RTT estimator
1802  delta = (r > socket->srtt) ? (r - socket->srtt) : (socket->srtt - r);
1803 
1804  //Implement Van Jacobson's algorithm (as specified in RFC 6298 2.3)
1805  socket->rttvar = ((socket->rttvar * 3) + delta) / 4;
1806  socket->srtt = ((socket->srtt * 7) + r) / 8;
1807  }
1808 
1809  //Calculate the next retransmission timeout
1810  socket->rto = socket->srtt + (socket->rttvar * 4);
1811 
1812  //Whenever RTO is computed, if it is less than 1 second, then the RTO
1813  //should be rounded up to 1 second
1814  socket->rto = MAX(socket->rto, TCP_MIN_RTO);
1815 
1816  //A maximum value may be placed on RTO provided it is at least 60
1817  //seconds
1818  socket->rto = MIN(socket->rto, TCP_MAX_RTO);
1819 
1820  //Debug message
1821  TRACE_DEBUG("R=%" PRIu32 ", SRTT=%" PRIu32 ", RTTVAR=%" PRIu32 ", RTO=%" PRIu32 "\r\n",
1822  r, socket->srtt, socket->rttvar, socket->rto);
1823 
1824  //RTT measurement is complete
1825  socket->rttBusy = FALSE;
1826  //Set flag
1827  flag = TRUE;
1828  }
1829  }
1830 
1831  //Return TRUE if the RTT measurement is complete
1832  return flag;
1833 }
1834 
1835 
1836 /**
1837  * @brief TCP segment retransmission
1838  * @param[in] socket Handle referencing the socket
1839  * @return Error code
1840  **/
1841 
1843 {
1844  error_t error;
1845  size_t offset;
1846  size_t length;
1847  NetBuffer *buffer;
1848  TcpQueueItem *queueItem;
1849  TcpHeader *segment;
1850  NetTxAncillary ancillary;
1851 
1852  //Initialize error code
1853  error = NO_ERROR;
1854  //Total number of bytes that have been retransmitted
1855  length = 0;
1856 
1857  //Point to the retransmission queue
1858  queueItem = socket->retransmitQueue;
1859 
1860  //Any segment in the retransmission queue?
1861  while(queueItem != NULL)
1862  {
1863  //Total number of bytes that have been retransmitted
1864  length += queueItem->length;
1865 
1866  //The amount of data that can be sent cannot exceed the MSS
1867  if(length > socket->smss)
1868  {
1869  //We are done
1870  error = NO_ERROR;
1871  //Exit immediately
1872  break;
1873  }
1874 
1875  //Allocate a memory buffer to hold the TCP segment
1876  buffer = ipAllocBuffer(TCP_MAX_HEADER_LENGTH, &offset);
1877  //Failed to allocate memory?
1878  if(buffer == NULL)
1879  {
1880  //Report an error
1881  error = ERROR_OUT_OF_MEMORY;
1882  //Exit immediately
1883  break;
1884  }
1885 
1886  //Start of exception handling block
1887  do
1888  {
1889  //Point to the beginning of the TCP segment
1890  segment = netBufferAt(buffer, offset, 0);
1891 
1892  //Copy TCP header
1893  osMemcpy(segment, queueItem->header, TCP_MAX_HEADER_LENGTH);
1894 
1895  //Update ACK number
1896  segment->ackNum = htonl(socket->rcvNxt);
1897 
1898 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
1899  //The window field in a segment where the SYN bit is set must not be
1900  //scaled (refer to RFC 7323, section 2.2)
1901  if((segment->flags & TCP_FLAG_SYN) == 0 &&
1902  socket->wndScaleOptionReceived)
1903  {
1904  //The window field (SEG.WND) of every outgoing segment, with the
1905  //exception of SYN segments, must be right-shifted by Rcv.Wind.Shift
1906  //bits (refer to RFC 7323, section 2.3)
1907  segment->window = htons(socket->rcvWnd >> socket->rcvWndShift);
1908  }
1909  else
1910  {
1911  //The maximum unscaled window is 2^16 - 1
1912  segment->window = htons(MIN(socket->rcvWnd, UINT16_MAX));
1913  }
1914 #else
1915  //The window field indicates the number of data octets beginning with
1916  //the one indicated in the acknowledgment field that the sender of
1917  //this segment is willing to accept (refer to RFC 793, section 3.1)
1918  segment->window = htons(MIN(socket->rcvWnd, UINT16_MAX));
1919 #endif
1920  //The checksum field is replaced with zeros
1921  segment->checksum = 0;
1922 
1923  //Adjust the length of the multi-part buffer
1924  netBufferSetLength(buffer, offset + segment->dataOffset * 4);
1925 
1926  //Copy data from send buffer
1927  error = tcpReadTxBuffer(socket, ntohl(segment->seqNum), buffer,
1928  queueItem->length);
1929  //Any error to report?
1930  if(error)
1931  break;
1932 
1933 #if (IPV4_SUPPORT == ENABLED)
1934  //Destination address is an IPv4 address?
1935  if(queueItem->pseudoHeader.length == sizeof(Ipv4PseudoHeader))
1936  {
1937  //Calculate TCP header checksum
1938  segment->checksum = ipCalcUpperLayerChecksumEx(
1939  &queueItem->pseudoHeader.ipv4Data, sizeof(Ipv4PseudoHeader),
1940  buffer, offset, segment->dataOffset * 4 + queueItem->length);
1941  }
1942  else
1943 #endif
1944 #if (IPV6_SUPPORT == ENABLED)
1945  //Destination address is an IPv6 address?
1946  if(queueItem->pseudoHeader.length == sizeof(Ipv6PseudoHeader))
1947  {
1948  //Calculate TCP header checksum
1949  segment->checksum = ipCalcUpperLayerChecksumEx(
1950  &queueItem->pseudoHeader.ipv6Data, sizeof(Ipv6PseudoHeader),
1951  buffer, offset, segment->dataOffset * 4 + queueItem->length);
1952  }
1953  else
1954 #endif
1955  //Destination address is not valid?
1956  {
1957  //This should never occur...
1958  error = ERROR_INVALID_ADDRESS;
1959  break;
1960  }
1961 
1962  //Total number of segments retransmitted
1963  MIB2_TCP_INC_COUNTER32(tcpRetransSegs, 1);
1964  TCP_MIB_INC_COUNTER32(tcpRetransSegs, 1);
1965 
1966  //Dump TCP header contents for debugging purpose
1967  tcpDumpHeader(segment, queueItem->length, socket->iss, socket->irs);
1968 
1969  //Additional options can be passed to the stack along with the packet
1970  ancillary = NET_DEFAULT_TX_ANCILLARY;
1971  //Set the TTL value to be used
1972  ancillary.ttl = socket->ttl;
1973 
1974 #if (ETH_VLAN_SUPPORT == ENABLED)
1975  //Set VLAN PCP and DEI fields
1976  ancillary.vlanPcp = socket->vlanPcp;
1977  ancillary.vlanDei = socket->vlanDei;
1978 #endif
1979 
1980 #if (ETH_VMAN_SUPPORT == ENABLED)
1981  //Set VMAN PCP and DEI fields
1982  ancillary.vmanPcp = socket->vmanPcp;
1983  ancillary.vmanDei = socket->vmanDei;
1984 #endif
1985  //Retransmit the lost segment without waiting for the retransmission
1986  //timer to expire
1987  error = ipSendDatagram(socket->interface, &queueItem->pseudoHeader,
1988  buffer, offset, &ancillary);
1989 
1990  //End of exception handling block
1991  } while(0);
1992 
1993  //Free previously allocated memory
1994  netBufferFree(buffer);
1995 
1996  //Any error to report?
1997  if(error)
1998  {
1999  //Exit immediately
2000  break;
2001  }
2002 
2003  //Point to the next segment in the queue
2004  queueItem = queueItem->next;
2005  }
2006 
2007  //Return status code
2008  return error;
2009 }
2010 
2011 
2012 /**
2013  * @brief Nagle algorithm implementation
2014  * @param[in] socket Handle referencing the socket
2015  * @param[in] flags Set of flags that influences the behavior of this function
2016  * @return Error code
2017  **/
2018 
2020 {
2021  error_t error;
2022  uint32_t n;
2023  uint32_t u;
2024 
2025  //Initialize status code
2026  error = NO_ERROR;
2027 
2028  //The amount of data that can be sent at any given time is limited by the
2029  //receiver window and the congestion window
2030  n = MIN(socket->sndWnd, socket->txBufferSize);
2031 
2032 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
2033  //Check the congestion window
2034  n = MIN(n, socket->cwnd);
2035 #endif
2036 
2037  //Retrieve the size of the usable window
2038  u = n - (socket->sndNxt - socket->sndUna);
2039 
2040  //The Nagle algorithm discourages sending tiny segments when the data to be
2041  //sent increases in small increments
2042  while(socket->sndUser > 0 && !error)
2043  {
2044  //The usable window size may become zero or negative, preventing packet
2045  //transmission
2046  if((int32_t) u <= 0)
2047  break;
2048 
2049  //Calculate the number of bytes to send at a time
2050  n = MIN(u, socket->sndUser);
2051  n = MIN(n, socket->smss);
2052 
2053  //Disable Nagle algorithm?
2054  if((flags & SOCKET_FLAG_NO_DELAY) != 0)
2055  {
2056  //All packets will be send no matter what size they have
2057  if(n > 0)
2058  {
2059  //Send TCP segment
2061  socket->sndNxt, socket->rcvNxt, n, TRUE);
2062  }
2063  else
2064  {
2065  //We are done
2066  break;
2067  }
2068  }
2069  else if((flags & SOCKET_FLAG_DELAY) != 0)
2070  {
2071  //Transmit data if a maximum-sized segment can be sent
2072  if(MIN(socket->sndUser, u) >= socket->smss)
2073  {
2074  //Send TCP segment
2076  socket->sndNxt, socket->rcvNxt, n, TRUE);
2077  }
2078  else
2079  {
2080  //Prevent the sender from sending tiny segments
2081  break;
2082  }
2083  }
2084  else
2085  {
2086  //Transmit data if a maximum-sized segment can be sent
2087  if(MIN(socket->sndUser, u) >= socket->smss)
2088  {
2089  //Send TCP segment
2091  socket->sndNxt, socket->rcvNxt, n, TRUE);
2092  }
2093  //Or if all queued data can be sent now
2094  else if(socket->sndNxt == socket->sndUna && socket->sndUser <= u)
2095  {
2096  //Send TCP segment
2098  socket->sndNxt, socket->rcvNxt, n, TRUE);
2099  }
2100  //Or if at least a fraction of the maximum window can be sent
2101  else if(MIN(socket->sndUser, u) >= (socket->maxSndWnd / 2))
2102  {
2103  //Send TCP segment
2105  socket->sndNxt, socket->rcvNxt, n, TRUE);
2106  }
2107  else
2108  {
2109  //Prevent the sender from sending tiny segments
2110  break;
2111  }
2112  }
2113 
2114  //Check status code
2115  if(!error)
2116  {
2117  //Advance SND.NXT pointer
2118  socket->sndNxt += n;
2119  //Update the number of data buffered but not yet sent
2120  socket->sndUser -= n;
2121  //Update the size of the usable window
2122  u -= n;
2123  }
2124  }
2125 
2126  //Check whether the transmitter can accept more data
2128 
2129  //Return status code
2130  return error;
2131 }
2132 
2133 
2134 /**
2135  * @brief Update TCP FSM current state
2136  * @param[in] socket Handle referencing the socket
2137  * @param[in] newState New TCP state to switch to
2138  **/
2139 
2141 {
2142  //Enter CLOSED state?
2143  if(newState == TCP_STATE_CLOSED)
2144  {
2145  //Check previous state
2146  if(socket->state == TCP_STATE_LAST_ACK ||
2147  socket->state == TCP_STATE_TIME_WAIT)
2148  {
2149  //The connection has been closed properly
2150  socket->closedFlag = TRUE;
2151  }
2152  else
2153  {
2154  //The connection has been reset by the peer
2155  socket->resetFlag = TRUE;
2156  }
2157  }
2158 
2159  //Enter the desired state
2160  socket->state = newState;
2161  //Update TCP related events
2163 }
2164 
2165 
2166 /**
2167  * @brief Update TCP related events
2168  * @param[in] socket Handle referencing the socket
2169  **/
2170 
2172 {
2173  //Clear event flags
2174  socket->eventFlags = 0;
2175 
2176  //Check current TCP state
2177  switch(socket->state)
2178  {
2179  //ESTABLISHED or FIN-WAIT-1 state?
2180  case TCP_STATE_ESTABLISHED:
2181  case TCP_STATE_FIN_WAIT_1:
2182  socket->eventFlags |= SOCKET_EVENT_CONNECTED;
2183  break;
2184 
2185  //FIN-WAIT-2 state?
2186  case TCP_STATE_FIN_WAIT_2:
2187  socket->eventFlags |= SOCKET_EVENT_CONNECTED;
2188  socket->eventFlags |= SOCKET_EVENT_TX_SHUTDOWN;
2189  break;
2190 
2191  //CLOSE-WAIT, LAST-ACK or CLOSING state?
2192  case TCP_STATE_CLOSE_WAIT:
2193  case TCP_STATE_LAST_ACK:
2194  case TCP_STATE_CLOSING:
2195  socket->eventFlags |= SOCKET_EVENT_CONNECTED;
2196  socket->eventFlags |= SOCKET_EVENT_RX_SHUTDOWN;
2197  break;
2198 
2199  //TIME-WAIT or CLOSED state?
2200  case TCP_STATE_TIME_WAIT:
2201  case TCP_STATE_CLOSED:
2202  socket->eventFlags |= SOCKET_EVENT_CLOSED;
2203  socket->eventFlags |= SOCKET_EVENT_TX_SHUTDOWN;
2204  socket->eventFlags |= SOCKET_EVENT_RX_SHUTDOWN;
2205  break;
2206 
2207  //Any other state
2208  default:
2209  break;
2210  }
2211 
2212  //Handle TX specific events
2213  if(socket->state == TCP_STATE_SYN_SENT ||
2214  socket->state == TCP_STATE_SYN_RECEIVED)
2215  {
2216  //Disallow write operations until the connection is established
2217  socket->eventFlags |= SOCKET_EVENT_TX_DONE;
2218  socket->eventFlags |= SOCKET_EVENT_TX_ACKED;
2219  }
2220  else if(socket->state == TCP_STATE_ESTABLISHED ||
2221  socket->state == TCP_STATE_CLOSE_WAIT)
2222  {
2223  //Check whether the send buffer is full or not
2224  if((socket->sndUser + socket->sndNxt - socket->sndUna) < socket->txBufferSize)
2225  {
2226  socket->eventFlags |= SOCKET_EVENT_TX_READY;
2227  }
2228 
2229  //Check whether all the data in the send buffer has been transmitted
2230  if(socket->sndUser == 0)
2231  {
2232  //All the pending data has been sent out
2233  socket->eventFlags |= SOCKET_EVENT_TX_DONE;
2234 
2235  //Check whether an acknowledgment has been received
2236  if(TCP_CMP_SEQ(socket->sndUna, socket->sndNxt) >= 0)
2237  {
2238  socket->eventFlags |= SOCKET_EVENT_TX_ACKED;
2239  }
2240  }
2241  }
2242  else if(socket->state != TCP_STATE_LISTEN)
2243  {
2244  //Unblock user task if the connection is being closed
2245  socket->eventFlags |= SOCKET_EVENT_TX_READY;
2246  socket->eventFlags |= SOCKET_EVENT_TX_DONE;
2247  socket->eventFlags |= SOCKET_EVENT_TX_ACKED;
2248  }
2249 
2250  //Handle RX specific events
2251  if(socket->state == TCP_STATE_ESTABLISHED ||
2252  socket->state == TCP_STATE_FIN_WAIT_1 ||
2253  socket->state == TCP_STATE_FIN_WAIT_2)
2254  {
2255  //Data is available for reading?
2256  if(socket->rcvUser > 0)
2257  {
2258  socket->eventFlags |= SOCKET_EVENT_RX_READY;
2259  }
2260  }
2261  else if(socket->state == TCP_STATE_LISTEN)
2262  {
2263  //If the socket is currently in the listen state, it will be marked
2264  //as readable if an incoming connection request has been received
2265  if(socket->synQueue != NULL)
2266  {
2267  socket->eventFlags |= SOCKET_EVENT_ACCEPT;
2268  socket->eventFlags |= SOCKET_EVENT_RX_READY;
2269  }
2270  }
2271  else if(socket->state != TCP_STATE_SYN_SENT &&
2272  socket->state != TCP_STATE_SYN_RECEIVED)
2273  {
2274  //Readability can also indicate that a request to close
2275  //the socket has been received from the peer
2276  socket->eventFlags |= SOCKET_EVENT_RX_READY;
2277  }
2278 
2279  //Check whether the socket is bound to a particular network interface
2280  if(socket->interface != NULL)
2281  {
2282  //Handle link up and link down events
2283  if(socket->interface->linkState)
2284  {
2285  socket->eventFlags |= SOCKET_EVENT_LINK_UP;
2286  }
2287  else
2288  {
2289  socket->eventFlags |= SOCKET_EVENT_LINK_DOWN;
2290  }
2291  }
2292 
2293  //Mask unused events
2294  socket->eventFlags &= socket->eventMask;
2295 
2296  //Any event to signal?
2297  if(socket->eventFlags)
2298  {
2299  //Unblock I/O operations currently in waiting state
2300  osSetEvent(&socket->event);
2301 
2302  //Set user event to signaled state if necessary
2303  if(socket->userEvent != NULL)
2304  {
2305  osSetEvent(socket->userEvent);
2306  }
2307  }
2308 }
2309 
2310 
2311 /**
2312  * @brief Wait for a particular TCP event
2313  * @param[in] socket Handle referencing the socket
2314  * @param[in] eventMask Logic OR of all the TCP events that will complete the wait
2315  * @param[in] timeout Maximum time to wait
2316  * @return Logic OR of all the TCP events that satisfied the wait
2317  **/
2318 
2320 {
2321  //Sanity check
2322  if(socket == NULL)
2323  return 0;
2324 
2325  //Only one of the events listed here may complete the wait
2326  socket->eventMask = eventMask;
2327  //Update TCP related events
2329 
2330  //No event is signaled?
2331  if(socket->eventFlags == 0)
2332  {
2333  //Reset the event object
2334  osResetEvent(&socket->event);
2335 
2336  //Release exclusive access
2337  netUnlock(socket->netContext);
2338  //Wait until an event is triggered
2339  osWaitForEvent(&socket->event, timeout);
2340  //Get exclusive access
2341  netLock(socket->netContext);
2342  }
2343 
2344  //Return the list of TCP events that satisfied the wait
2345  return socket->eventFlags;
2346 }
2347 
2348 
2349 /**
2350  * @brief Copy incoming data to the send buffer
2351  * @param[in] socket Handle referencing the socket
2352  * @param[in] seqNum First sequence number occupied by the incoming data
2353  * @param[in] data Data to write
2354  * @param[in] length Number of data to write
2355  **/
2356 
2358  const uint8_t *data, size_t length)
2359 {
2360  //Offset of the first byte to write in the circular buffer
2361  size_t offset = (seqNum - socket->iss - 1) % socket->txBufferSize;
2362 
2363  //Check whether the specified data crosses buffer boundaries
2364  if((offset + length) <= socket->txBufferSize)
2365  {
2366  //Copy the payload
2367  netBufferWrite((NetBuffer *) &socket->txBuffer,
2368  offset, data, length);
2369  }
2370  else
2371  {
2372  //Copy the first part of the payload
2373  netBufferWrite((NetBuffer *) &socket->txBuffer,
2374  offset, data, socket->txBufferSize - offset);
2375 
2376  //Wrap around to the beginning of the circular buffer
2377  netBufferWrite((NetBuffer *) &socket->txBuffer, 0,
2378  data + socket->txBufferSize - offset,
2379  length - socket->txBufferSize + offset);
2380  }
2381 }
2382 
2383 
2384 /**
2385  * @brief Copy data from the send buffer
2386  * @param[in] socket Handle referencing the socket
2387  * @param[in] seqNum Sequence number of the first data to read
2388  * @param[out] buffer Pointer to the output buffer
2389  * @param[in] length Number of data to read
2390  * @return Error code
2391  **/
2392 
2394  NetBuffer *buffer, size_t length)
2395 {
2396  error_t error;
2397 
2398  //Offset of the first byte to read in the circular buffer
2399  size_t offset = (seqNum - socket->iss - 1) % socket->txBufferSize;
2400 
2401  //Check whether the specified data crosses buffer boundaries
2402  if((offset + length) <= socket->txBufferSize)
2403  {
2404  //Copy the payload
2405  error = netBufferConcat(buffer, (NetBuffer *) &socket->txBuffer,
2406  offset, length);
2407  }
2408  else
2409  {
2410  //Copy the first part of the payload
2411  error = netBufferConcat(buffer, (NetBuffer *) &socket->txBuffer,
2412  offset, socket->txBufferSize - offset);
2413 
2414  //Check status code
2415  if(!error)
2416  {
2417  //Wrap around to the beginning of the circular buffer
2418  error = netBufferConcat(buffer, (NetBuffer *) &socket->txBuffer,
2419  0, length - socket->txBufferSize + offset);
2420  }
2421  }
2422 
2423  //Return status code
2424  return error;
2425 }
2426 
2427 
2428 /**
2429  * @brief Copy incoming data to the receive buffer
2430  * @param[in] socket Handle referencing the socket
2431  * @param[in] seqNum First sequence number occupied by the incoming data
2432  * @param[in] data Multi-part buffer containing the incoming data
2433  * @param[in] dataOffset Offset to the first data byte
2434  * @param[in] length Number of data to write
2435  **/
2436 
2438  const NetBuffer *data, size_t dataOffset, size_t length)
2439 {
2440  //Offset of the first byte to write in the circular buffer
2441  size_t offset = (seqNum - socket->irs - 1) % socket->rxBufferSize;
2442 
2443  //Check whether the specified data crosses buffer boundaries
2444  if((offset + length) <= socket->rxBufferSize)
2445  {
2446  //Copy the payload
2447  netBufferCopy((NetBuffer *) &socket->rxBuffer,
2448  offset, data, dataOffset, length);
2449  }
2450  else
2451  {
2452  //Copy the first part of the payload
2453  netBufferCopy((NetBuffer *) &socket->rxBuffer,
2454  offset, data, dataOffset, socket->rxBufferSize - offset);
2455 
2456  //Wrap around to the beginning of the circular buffer
2457  netBufferCopy((NetBuffer *) &socket->rxBuffer, 0, data,
2458  dataOffset + socket->rxBufferSize - offset,
2459  length - socket->rxBufferSize + offset);
2460  }
2461 }
2462 
2463 
2464 /**
2465  * @brief Copy data from the receive buffer
2466  * @param[in] socket Handle referencing the socket
2467  * @param[in] seqNum Sequence number of the first data to read
2468  * @param[out] data Pointer to the output buffer
2469  * @param[in] length Number of data to read
2470  **/
2471 
2472 void tcpReadRxBuffer(Socket *socket, uint32_t seqNum, uint8_t *data,
2473  size_t length)
2474 {
2475  //Offset of the first byte to read in the circular buffer
2476  size_t offset = (seqNum - socket->irs - 1) % socket->rxBufferSize;
2477 
2478  //Check whether the specified data crosses buffer boundaries
2479  if((offset + length) <= socket->rxBufferSize)
2480  {
2481  //Copy the payload
2482  netBufferRead(data, (NetBuffer *) &socket->rxBuffer,
2483  offset, length);
2484  }
2485  else
2486  {
2487  //Copy the first part of the payload
2488  netBufferRead(data, (NetBuffer *) &socket->rxBuffer,
2489  offset, socket->rxBufferSize - offset);
2490 
2491  //Wrap around to the beginning of the circular buffer
2492  netBufferRead(data + socket->rxBufferSize - offset,
2493  (NetBuffer *) &socket->rxBuffer, 0,
2494  length - socket->rxBufferSize + offset);
2495  }
2496 }
2497 
2498 
2499 /**
2500  * @brief Dump TCP header for debugging purpose
2501  * @param[in] segment Pointer to the TCP header
2502  * @param[in] length Length of the segment data
2503  * @param[in] iss Initial send sequence number (needed to compute relative SEQ number)
2504  * @param[in] irs Initial receive sequence number (needed to compute relative ACK number)
2505  **/
2506 
2507 void tcpDumpHeader(const TcpHeader *segment, size_t length, uint32_t iss,
2508  uint32_t irs)
2509 {
2510  //Dump TCP header contents
2511  TRACE_DEBUG("%" PRIu16 " > %" PRIu16 ": %c%c%c%c%c%c seq=%" PRIu32 "(%" PRIu32 ") "
2512  "ack=%" PRIu32 "(%" PRIu32 ") win=%" PRIu16 " len=%" PRIuSIZE "\r\n",
2513  ntohs(segment->srcPort), ntohs(segment->destPort),
2514  (segment->flags & TCP_FLAG_FIN) ? 'F' : '-',
2515  (segment->flags & TCP_FLAG_SYN) ? 'S' : '-',
2516  (segment->flags & TCP_FLAG_RST) ? 'R' : '-',
2517  (segment->flags & TCP_FLAG_PSH) ? 'P' : '-',
2518  (segment->flags & TCP_FLAG_ACK) ? 'A' : '-',
2519  (segment->flags & TCP_FLAG_URG) ? 'U' : '-',
2520  ntohl(segment->seqNum), ntohl(segment->seqNum) - iss,
2521  ntohl(segment->ackNum), ntohl(segment->ackNum) - irs,
2522  ntohs(segment->window), length);
2523 }
2524 
2525 #endif
@ TCP_CONGEST_STATE_IDLE
Definition: tcp.h:295
void tcpUpdateReceiveWindow(Socket *socket)
Update receive window so as to avoid Silly Window Syndrome.
Definition: tcp_misc.c:1734
#define htons(value)
Definition: cpu_endian.h:413
IPv6 (Internet Protocol Version 6)
MIB-II module.
Retransmission queue item.
Definition: tcp.h:393
Date and time management.
void netStartTimer(NetTimer *timer, systime_t interval)
Start timer.
Definition: net_misc.c:798
void netUnlock(NetContext *context)
Release exclusive access to the core of the TCP/IP stack.
Definition: net.c:319
@ TCP_STATE_TIME_WAIT
Definition: tcp.h:285
void tcpComputeWindowScaleFactor(Socket *socket)
Compute the window scale factor to use for the receive window.
Definition: tcp_misc.c:1583
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
Definition: ip.c:716
Ipv6PseudoHeader ipv6Data
Definition: ip.h:118
int bool_t
Definition: compiler_port.h:63
#define TCP_MAX_HEADER_LENGTH
Definition: tcp.h:256
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:70
uint_t sacked
Definition: tcp.h:396
void memPoolFree(void *p)
Release a memory block.
Definition: net_mem.c:166
bool_t netTimerRunning(NetTimer *timer)
Check whether the timer is running.
Definition: net_misc.c:825
#define TCP_MAX_RTO
Definition: tcp.h:131
uint8_t header[TCP_MAX_HEADER_LENGTH]
Definition: tcp.h:398
uint32_t tcpGenerateInitialSeqNum(Socket *socket)
Initial sequence number generation.
Definition: tcp_misc.c:737
#define LOAD32BE(p)
Definition: cpu_endian.h:210
@ TCP_OPTION_END
Definition: tcp.h:322
IP network address.
Definition: ip.h:90
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:690
void tcpFlushSynQueue(Socket *socket)
Flush SYN queue.
Definition: tcp_misc.c:1557
uint8_t delta
Definition: coap_common.h:196
@ TCP_FLAG_FIN
Definition: tcp.h:307
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
@ TCP_STATE_FIN_WAIT_1
Definition: tcp.h:282
uint16_t mss
Definition: tcp.h:414
#define TRUE
Definition: os_port.h:50
IpAddr srcAddr
Definition: tcp.h:410
uint32_t netGenerateRand(NetContext *context)
Generate a random 32-bit value.
Definition: net_misc.c:956
bool_t tcpIsDuplicateSyn(Socket *socket, const IpPseudoHeader *pseudoHeader, const TcpHeader *segment)
Test whether the incoming SYN segment is a duplicate.
Definition: tcp_misc.c:1112
uint8_t data[]
Definition: ethernet.h:224
error_t ipSendDatagram(NetInterface *interface, const IpPseudoHeader *pseudoHeader, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IP datagram.
Definition: ip.c:68
void md5Final(Md5Context *context, uint8_t *digest)
Finish the MD5 message digest.
void tcpUpdateSendWindow(Socket *socket, const TcpHeader *segment)
Update send window.
Definition: tcp_misc.c:1668
Ipv6Addr
Definition: ipv6.h:280
@ TCP_STATE_CLOSE_WAIT
Definition: tcp.h:280
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
IpAddr destAddr
Definition: tcp.h:412
error_t tcpSendResetSegment(Socket *socket, uint32_t seqNum)
Send a TCP reset segment.
Definition: tcp_misc.c:421
void tcpFastLossRecovery(Socket *socket, const TcpHeader *segment)
Fast loss recovery procedure.
Definition: tcp_misc.c:1319
#define ipv6CompAddr(ipAddr1, ipAddr2)
Definition: ipv6.h:134
error_t tcpRejectSegment(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const TcpHeader *segment, size_t length)
Send a TCP reset in response to an invalid segment.
Definition: tcp_misc.c:454
uint16_t totalLength
Definition: ipv4.h:347
void * memPoolAlloc(size_t size)
Allocate a memory block.
Definition: net_mem.c:100
uint16_t srcPort
Definition: tcp.h:411
struct _TcpSynQueueItem * next
Definition: tcp.h:408
size_t length
Definition: ip.h:111
const char_t * formatSystemTime(systime_t time, char_t *str)
Format system time.
Definition: date_time.c:77
@ TCP_FLAG_ACK
Definition: tcp.h:311
uint16_t window
Definition: tcp.h:361
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:322
void tcpUpdateRetransmitQueue(Socket *socket)
Remove acknowledged segments from retransmission queue.
Definition: tcp_misc.c:1446
uint_t length
Definition: tcp.h:395
uint8_t r
Definition: ndp.h:346
@ SOCKET_FLAG_DELAY
Definition: socket.h:144
@ TCP_OPTION_WINDOW_SCALE_FACTOR
Definition: tcp.h:325
const TcpOption * tcpGetOption(const TcpHeader *segment, uint8_t kind)
Search the TCP header for a given option.
Definition: tcp_misc.c:667
IP pseudo header.
Definition: ip.h:110
error_t netBufferConcat(NetBuffer *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Concatenate two multi-part buffers.
Definition: net_mem.c:460
void md5Init(Md5Context *context)
Initialize MD5 message digest context.
void tcpDeleteControlBlock(Socket *socket)
Delete TCB structure.
Definition: tcp_misc.c:1425
#define TCP_MAX_SACK_BLOCKS
Definition: tcp.h:250
@ IPV4_PROTOCOL_TCP
Definition: ipv4.h:277
void tcpWriteTxBuffer(Socket *socket, uint32_t seqNum, const uint8_t *data, size_t length)
Copy incoming data to the send buffer.
Definition: tcp_misc.c:2357
TcpState
TCP FSM states.
Definition: tcp.h:274
#define FALSE
Definition: os_port.h:46
Helper functions for TCP.
@ TCP_OPTION_SACK_PERMITTED
Definition: tcp.h:326
#define htonl(value)
Definition: cpu_endian.h:414
void tcpChangeState(Socket *socket, TcpState newState)
Update TCP FSM current state.
Definition: tcp_misc.c:2140
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
#define HTONL(value)
Definition: cpu_endian.h:411
error_t
Error codes.
Definition: error.h:43
uint32_t seqNum
Definition: tcp.h:348
struct _TcpQueueItem * next
Definition: tcp.h:394
#define Ipv6PseudoHeader
Definition: ipv6.h:42
void netStopTimer(NetTimer *timer)
Stop timer.
Definition: net_misc.c:812
@ TCP_CONGEST_STATE_LOSS_RECOVERY
Definition: tcp.h:297
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
@ SOCKET_EVENT_TX_READY
Definition: socket.h:175
@ ERROR_INVALID_ADDRESS
Definition: error.h:103
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ SOCKET_EVENT_LINK_DOWN
Definition: socket.h:182
error_t tcpRetransmitSegment(Socket *socket)
TCP segment retransmission.
Definition: tcp_misc.c:1842
#define NetInterface
Definition: net.h:40
error_t tcpCheckAck(Socket *socket, const TcpHeader *segment, size_t length)
Test the ACK field of an incoming segment.
Definition: tcp_misc.c:898
bool_t tcpIsDuplicateAck(Socket *socket, const TcpHeader *segment, size_t length)
Test whether the incoming acknowledgment is a duplicate.
Definition: tcp_misc.c:1188
NetInterface * interface
Definition: tcp.h:409
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
error_t tcpCheckSeqNum(Socket *socket, const TcpHeader *segment, size_t length)
Test the sequence number of an incoming segment.
Definition: tcp_misc.c:773
@ SOCKET_EVENT_ACCEPT
Definition: socket.h:172
@ SOCKET_EVENT_RX_SHUTDOWN
Definition: socket.h:180
#define TCP_MIB_INC_COUNTER32(name, value)
@ TCP_CONGEST_STATE_RECOVERY
Definition: tcp.h:296
MD5 algorithm context.
Definition: md5.h:62
#define NetTxAncillary
Definition: net_misc.h:36
TcpOption
Definition: tcp.h:377
void tcpUpdateEvents(Socket *socket)
Update TCP related events.
Definition: tcp_misc.c:2171
bool_t tcpComputeRto(Socket *socket)
Compute retransmission timeout.
Definition: tcp_misc.c:1773
error_t tcpReadTxBuffer(Socket *socket, uint32_t seqNum, NetBuffer *buffer, size_t length)
Copy data from the send buffer.
Definition: tcp_misc.c:2393
@ TCP_STATE_SYN_SENT
Definition: tcp.h:277
uint8_t u
Definition: lldp_ext_med.h:213
@ TCP_FLAG_RST
Definition: tcp.h:309
error_t netBufferCopy(NetBuffer *dest, size_t destOffset, const NetBuffer *src, size_t srcOffset, size_t length)
Copy data between multi-part buffers.
Definition: net_mem.c:522
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define TRACE_INFO(...)
Definition: debug.h:105
@ TCP_FLAG_SYN
Definition: tcp.h:308
uint32_t isn
Definition: tcp.h:413
uint8_t length
Definition: tcp.h:375
@ TCP_STATE_LAST_ACK
Definition: tcp.h:281
void tcpUpdateSackBlocks(Socket *socket, uint32_t *leftEdge, uint32_t *rightEdge)
Update the list of non-contiguous blocks that have been received.
Definition: tcp_misc.c:1613
#define MIN(a, b)
Definition: os_port.h:63
size_t length
Definition: ip.h:91
@ SOCKET_EVENT_TX_DONE
Definition: socket.h:176
#define MD5_DIGEST_SIZE
Definition: md5.h:45
@ TCP_OPTION_NOP
Definition: tcp.h:323
@ TCP_STATE_CLOSING
Definition: tcp.h:284
@ SOCKET_EVENT_LINK_UP
Definition: socket.h:181
error_t tcpAddOption(TcpHeader *segment, uint8_t kind, const void *value, uint8_t length)
Append an option to the TCP header.
Definition: tcp_misc.c:604
uint32_t systime_t
System time.
@ TCP_STATE_CLOSED
Definition: tcp.h:275
#define ntohs(value)
Definition: cpu_endian.h:421
@ TCP_STATE_LISTEN
Definition: tcp.h:276
#define TRACE_WARNING(...)
Definition: debug.h:93
#define TRACE_DEBUG(...)
Definition: debug.h:119
void tcpProcessSegmentData(Socket *socket, const TcpHeader *segment, const NetBuffer *buffer, size_t offset, size_t length)
Process the segment text.
Definition: tcp_misc.c:1357
#define MAX(a, b)
Definition: os_port.h:67
IpPseudoHeader pseudoHeader
Definition: tcp.h:397
void tcpWriteRxBuffer(Socket *socket, uint32_t seqNum, const NetBuffer *data, size_t dataOffset, size_t length)
Copy incoming data to the receive buffer.
Definition: tcp_misc.c:2437
Ipv4Addr ipv4Addr
Definition: ip.h:95
SACK block.
Definition: tcp.h:430
@ SOCKET_EVENT_TX_ACKED
Definition: socket.h:177
uint16_t ipCalcUpperLayerChecksumEx(const void *pseudoHeader, size_t pseudoHeaderLen, const NetBuffer *buffer, size_t offset, size_t length)
Calculate IP upper-layer checksum over a multi-part buffer.
Definition: ip.c:691
void tcpReadRxBuffer(Socket *socket, uint32_t seqNum, uint8_t *data, size_t length)
Copy data from the receive buffer.
Definition: tcp_misc.c:2472
@ TCP_OPTION_SACK
Definition: tcp.h:327
uint32_t ackNum
Definition: tcp.h:349
IPv4 and IPv6 common routines.
@ TCP_FLAG_URG
Definition: tcp.h:312
@ IPV6_TCP_HEADER
Definition: ipv6.h:207
@ SOCKET_FLAG_NO_DELAY
Definition: socket.h:143
@ SOCKET_EVENT_RX_READY
Definition: socket.h:179
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
TCP (Transmission Control Protocol)
TCP MIB module.
@ SOCKET_EVENT_TX_SHUTDOWN
Definition: socket.h:178
#define TCP_MIB_INC_COUNTER64(name, value)
MD5 (Message-Digest Algorithm)
error_t tcpNagleAlgo(Socket *socket, uint_t flags)
Nagle algorithm implementation.
Definition: tcp_misc.c:2019
#define Socket
Definition: socket.h:36
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:322
#define TCP_DEFAULT_PROBE_INTERVAL
Definition: tcp.h:173
@ TCP_STATE_FIN_WAIT_2
Definition: tcp.h:283
uint8_t value[]
Definition: tcp.h:376
size_t netBufferWrite(NetBuffer *dest, size_t destOffset, const void *src, size_t length)
Write data to a multi-part buffer.
Definition: net_mem.c:637
uint8_t dataOffset
Definition: tcp.h:357
Socket API.
@ TCP_STATE_SYN_RECEIVED
Definition: tcp.h:278
SYN queue item.
Definition: tcp.h:407
void netLock(NetContext *context)
Get exclusive access to the core of the TCP/IP stack.
Definition: net.c:307
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
#define TCP_MIN_RTO
Definition: tcp.h:124
#define NET_RAND_SEED_SIZE
Definition: net.h:171
#define netGetSystemTickCount()
Definition: net.h:197
IPv4 (Internet Protocol Version 4)
uint8_t flags
Definition: tcp.h:358
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:2507
#define MIB2_TCP_INC_COUNTER32(name, value)
Definition: mib2_module.h:155
@ TCP_OPTION_MAX_SEGMENT_SIZE
Definition: tcp.h:324
@ SOCKET_EVENT_CONNECTED
Definition: socket.h:173
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
error_t tcpCheckSyn(Socket *socket, const TcpHeader *segment, size_t length)
Check the SYN bit of an incoming segment.
Definition: tcp_misc.c:864
void tcpFlushRetransmitQueue(Socket *socket)
Flush retransmission queue.
Definition: tcp_misc.c:1528
TCP/IP stack core.
#define TCP_FAST_RETRANSMIT_THRES
Definition: tcp.h:152
@ SOCKET_EVENT_CLOSED
Definition: socket.h:174
TcpHeader
Definition: tcp.h:365
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
void tcpFastRecovery(Socket *socket, const TcpHeader *segment, uint32_t n)
Fast recovery procedure.
Definition: tcp_misc.c:1270
void tcpFastRetransmit(Socket *socket)
Fast retransmit procedure.
Definition: tcp_misc.c:1231
#define ntohl(value)
Definition: cpu_endian.h:422
Ipv4PseudoHeader ipv4Data
Definition: ip.h:115
void md5Update(Md5Context *context, const void *data, size_t length)
Update the MD5 context with a portion of the message being hashed.
@ TCP_STATE_ESTABLISHED
Definition: tcp.h:279
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:150
uint_t tcpWaitForEvents(Socket *socket, uint_t eventMask, systime_t timeout)
Wait for a particular TCP event.
Definition: tcp_misc.c:2319
@ TCP_FLAG_PSH
Definition: tcp.h:310
systime_t osGetSystemTime(void)
Retrieve system time.
#define TCP_CMP_SEQ(a, b)
Definition: tcp.h:261