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-2025 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.5.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] localIpAddr Local IP address
734  * @param[in] localPort Local port
735  * @param[in] remoteIpAddr Remote IP address
736  * @param[in] remotePort Remote port
737  * @return Value of the initial sequence number
738  **/
739 
740 uint32_t tcpGenerateInitialSeqNum(const IpAddr *localIpAddr,
741  uint16_t localPort, const IpAddr *remoteIpAddr, uint16_t remotePort)
742 {
743 #if (TCP_SECURE_ISN_SUPPORT == ENABLED)
744  uint32_t isn;
745  Md5Context md5Context;
746  uint8_t digest[MD5_DIGEST_SIZE];
747 
748  //Generate the initial sequence number as per RFC 6528
749  md5Init(&md5Context);
750  md5Update(&md5Context, localIpAddr, sizeof(IpAddr));
751  md5Update(&md5Context, &localPort, sizeof(uint16_t));
752  md5Update(&md5Context, remoteIpAddr, sizeof(IpAddr));
753  md5Update(&md5Context, &remotePort, sizeof(uint16_t));
755  md5Final(&md5Context, digest);
756 
757  //Extract the first 32 bits from the digest value
758  isn = LOAD32BE(digest);
759 
760  //Calculate ISN = M + F(localip, localport, remoteip, remoteport, secretkey)
761  return isn + netGetSystemTickCount();
762 #else
763  //Generate a random initial sequence number
764  return netGenerateRand();
765 #endif
766 }
767 
768 
769 /**
770  * @brief Test the sequence number of an incoming segment
771  * @param[in] socket Handle referencing the current socket
772  * @param[in] segment Pointer to the TCP segment to check
773  * @param[in] length Length of the segment data
774  * @return NO_ERROR if the incoming segment is acceptable, ERROR_FAILURE otherwise
775  **/
776 
778 {
779  bool_t acceptable;
780 
781  //Due to zero windows and zero length segments, we have four cases for the
782  //acceptability of an incoming segment (refer to RFC 793, section 3.3)
783  if(length == 0 && socket->rcvWnd == 0)
784  {
785  //If both segment length and receive window are zero, then test if
786  //SEG.SEQ = RCV.NXT
787  if(segment->seqNum == socket->rcvNxt)
788  {
789  acceptable = TRUE;
790  }
791  else
792  {
793  acceptable = FALSE;
794  }
795  }
796  else if(length == 0 && socket->rcvWnd != 0)
797  {
798  //If segment length is zero and receive window is non zero, then test if
799  //RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND
800  if(TCP_CMP_SEQ(segment->seqNum, socket->rcvNxt) >= 0 &&
801  TCP_CMP_SEQ(segment->seqNum, socket->rcvNxt + socket->rcvWnd) < 0)
802  {
803  acceptable = TRUE;
804  }
805  else
806  {
807  acceptable = FALSE;
808  }
809  }
810  else if(length != 0 && socket->rcvWnd == 0)
811  {
812  //If segment length is non zero and receive window is zero, then the
813  //sequence number is not acceptable
814  acceptable = FALSE;
815  }
816  else
817  {
818  //If both segment length and receive window are non zero, then test if
819  //RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND or
820  //RCV.NXT <= SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
821  if(TCP_CMP_SEQ(segment->seqNum, socket->rcvNxt) >= 0 &&
822  TCP_CMP_SEQ(segment->seqNum, socket->rcvNxt + socket->rcvWnd) < 0)
823  {
824  acceptable = TRUE;
825  }
826  else if(TCP_CMP_SEQ(segment->seqNum + length - 1, socket->rcvNxt) >= 0 &&
827  TCP_CMP_SEQ(segment->seqNum + length - 1, socket->rcvNxt + socket->rcvWnd) < 0)
828  {
829  acceptable = TRUE;
830  }
831  else
832  {
833  acceptable = FALSE;
834  }
835  }
836 
837  //Non acceptable sequence number?
838  if(!acceptable)
839  {
840  //Debug message
841  TRACE_WARNING("Sequence number is not acceptable!\r\n");
842 
843  //If an incoming segment is not acceptable, an acknowledgment should
844  //be sent in reply (unless the RST bit is set)
845  if((segment->flags & TCP_FLAG_RST) == 0)
846  {
847  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt,
848  0, FALSE);
849  }
850 
851  //Return status code
852  return ERROR_FAILURE;
853  }
854 
855  //Sequence number is acceptable
856  return NO_ERROR;
857 }
858 
859 
860 /**
861  * @brief Check the SYN bit of an incoming segment
862  * @param[in] socket Handle referencing the current socket
863  * @param[in] segment Pointer to the TCP segment to check
864  * @param[in] length Length of the segment data
865  * @return ERROR_FAILURE if the SYN is in the window, NO_ERROR otherwise
866  **/
867 
868 error_t tcpCheckSyn(Socket *socket, const TcpHeader *segment, size_t length)
869 {
870  //Check whether the SYN bit is set
871  if((segment->flags & TCP_FLAG_SYN) != 0)
872  {
873  //If this step is reached, the SYN is in the window. It is an error
874  //and a reset shall be sent in response
875  if((segment->flags & TCP_FLAG_ACK) != 0)
876  {
877  tcpSendResetSegment(socket, segment->ackNum);
878  }
879  else
880  {
882  segment->seqNum + length + 1, 0, FALSE);
883  }
884 
885  //Return immediately
886  return ERROR_FAILURE;
887  }
888 
889  //No error to report
890  return NO_ERROR;
891 }
892 
893 
894 /**
895  * @brief Test the ACK field of an incoming segment
896  * @param[in] socket Handle referencing the current socket
897  * @param[in] segment Pointer to the TCP segment to check
898  * @param[in] length Length of the segment data
899  * @return NO_ERROR if the acknowledgment is acceptable, ERROR_FAILURE otherwise
900  **/
901 
902 error_t tcpCheckAck(Socket *socket, const TcpHeader *segment, size_t length)
903 {
904  bool_t duplicateFlag;
905  bool_t updateFlag;
906 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
907  uint32_t n;
908  uint32_t ownd;
909  uint32_t thresh;
910 #endif
911 
912  //If the ACK bit is off drop the segment and return
913  if((segment->flags & TCP_FLAG_ACK) == 0)
914  return ERROR_FAILURE;
915 
916 #if (TCP_KEEP_ALIVE_SUPPORT == ENABLED)
917  //Check whether TCP keep-alive mechanism is enabled
918  if(socket->keepAliveEnabled)
919  {
920  //Reset keep-alive probe counter
921  socket->keepAliveProbeCount = 0;
922  }
923 #endif
924 
925  //Test the case where SEG.ACK < SND.UNA
926  if(TCP_CMP_SEQ(segment->ackNum, socket->sndUna) < 0)
927  {
928  //An old duplicate ACK has been received
929  return NO_ERROR;
930  }
931  //Test the case where SEG.ACK > SND.NXT
932  else if(TCP_CMP_SEQ(segment->ackNum, socket->sndNxt) > 0)
933  {
934  //Send an ACK segment indicating the current send sequence number
935  //and the acknowledgment number expected to be received
936  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0,
937  FALSE);
938 
939  //The ACK segment acknowledges something not yet sent
940  return ERROR_FAILURE;
941  }
942 
943  //Check whether the ACK is a duplicate
944  duplicateFlag = tcpIsDuplicateAck(socket, segment, length);
945  (void) duplicateFlag;
946 
947  //The send window should be updated
948  tcpUpdateSendWindow(socket, segment);
949 
950  //The incoming ACK segment acknowledges new data?
951  if(TCP_CMP_SEQ(segment->ackNum, socket->sndUna) > 0)
952  {
953 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
954  //Compute the number of bytes acknowledged by the incoming ACK
955  n = segment->ackNum - socket->sndUna;
956 
957  //Check whether the ACK segment acknowledges our SYN
958  if(socket->sndUna == socket->iss)
959  {
960  n--;
961  }
962 
963  //Total number of bytes acknowledged during the whole round-trip
964  socket->n += n;
965 #endif
966  //Update SND.UNA pointer
967  socket->sndUna = segment->ackNum;
968 
969  //Compute retransmission timeout
970  updateFlag = tcpComputeRto(socket);
971  (void) updateFlag;
972 
973  //Any segments on the retransmission queue which are thereby entirely
974  //acknowledged are removed
976 
977 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
978  //Check congestion state
979  if(socket->congestState == TCP_CONGEST_STATE_RECOVERY)
980  {
981  //Invoke fast recovery (refer to RFC 6582)
982  tcpFastRecovery(socket, segment, n);
983  }
984  else
985  {
986  //Reset duplicate ACK counter
987  socket->dupAckCount = 0;
988 
989  //Check congestion state
990  if(socket->congestState == TCP_CONGEST_STATE_LOSS_RECOVERY)
991  {
992  //Invoke fast loss recovery
993  tcpFastLossRecovery(socket, segment);
994  }
995 
996  //Slow start algorithm is used when cwnd is lower than ssthresh
997  if(socket->cwnd < socket->ssthresh)
998  {
999  //During slow start, TCP increments cwnd by at most SMSS bytes
1000  //for each ACK received that cumulatively acknowledges new data
1001  socket->cwnd += MIN(n, socket->smss);
1002  }
1003  //Congestion avoidance algorithm is used when cwnd exceeds ssthres
1004  else
1005  {
1006  //Congestion window is updated once per RTT
1007  if(updateFlag)
1008  {
1009  //TCP must not increment cwnd by more than SMSS bytes
1010  socket->cwnd += MIN(socket->n, socket->smss);
1011  }
1012  }
1013  }
1014 
1015  //Limit the size of the congestion window
1016  socket->cwnd = MIN(socket->cwnd, socket->txBufferSize);
1017 #endif
1018  }
1019  //The incoming ACK segment does not acknowledge new data?
1020  else
1021  {
1022 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1023  //Check whether the acknowledgment is a duplicate
1024  if(duplicateFlag)
1025  {
1026  //Increment duplicate ACK counter
1027  socket->dupAckCount++;
1028  //Debug message
1029  TRACE_INFO("TCP duplicate ACK #%u\r\n", socket->dupAckCount);
1030  }
1031  else
1032  {
1033  //Reset duplicate ACK counter
1034  socket->dupAckCount = 0;
1035  }
1036 
1037  //Check congestion state
1038  if(socket->congestState == TCP_CONGEST_STATE_IDLE)
1039  {
1040  //Use default duplicate ACK threshold
1041  thresh = TCP_FAST_RETRANSMIT_THRES;
1042  //Amount of data sent but not yet acknowledged
1043  ownd = socket->sndNxt - socket->sndUna;
1044 
1045  //Test if there is either no unsent data ready for transmission at
1046  //the sender, or the advertised receive window does not permit new
1047  //segments to be transmitted (refer to RFC 5827 section 3.1)
1048  if(socket->sndUser == 0 || socket->sndWnd <= (socket->sndNxt - socket->sndUna))
1049  {
1050  //Compute the duplicate ACK threshold used to trigger a
1051  //retransmission
1052  if(ownd <= ((uint32_t) socket->smss * 3))
1053  {
1054  thresh = 1;
1055  }
1056  else if(ownd <= ((uint32_t) socket->smss * 4))
1057  {
1058  thresh = 2;
1059  }
1060  else
1061  {
1062  }
1063  }
1064 
1065  //Check the number of duplicate ACKs that have been received
1066  if(socket->dupAckCount >= thresh)
1067  {
1068  //The TCP sender first checks the value of recover to see if the
1069  //cumulative acknowledgment field covers more than recover
1070  if(TCP_CMP_SEQ(segment->ackNum, socket->recover + 1) > 0)
1071  {
1072  //Invoke Fast Retransmit (refer to RFC 6582)
1074  }
1075  else
1076  {
1077  //If not, the TCP does not enter fast retransmit and does not
1078  //reset ssthres...
1079  }
1080  }
1081  }
1082  else if(socket->congestState == TCP_CONGEST_STATE_RECOVERY)
1083  {
1084  //Duplicate ACK received?
1085  if(duplicateFlag)
1086  {
1087  //For each additional duplicate ACK received (after the third),
1088  //cwnd must be incremented by SMSS. This artificially inflates
1089  //the congestion window in order to reflect the additional
1090  //segment that has left the network
1091  socket->cwnd += socket->smss;
1092  }
1093  }
1094 
1095  //Limit the size of the congestion window
1096  socket->cwnd = MIN(socket->cwnd, socket->txBufferSize);
1097 #endif
1098  }
1099 
1100  //Update TX events
1102 
1103  //No error to report
1104  return NO_ERROR;
1105 }
1106 
1107 
1108 /**
1109  * @brief Test whether the incoming SYN segment is a duplicate
1110  * @param[in] socket Handle referencing the current socket
1111  * @param[in] pseudoHeader TCP pseudo header
1112  * @param[in] segment Pointer to the TCP segment to check
1113  * @return TRUE if the SYN segment is duplicate, else FALSE
1114  **/
1115 
1117  const TcpHeader *segment)
1118 {
1119  bool_t flag;
1120  TcpSynQueueItem *queueItem;
1121 
1122  //Initialize flag
1123  flag = FALSE;
1124 
1125  //Point to the very first item
1126  queueItem = socket->synQueue;
1127 
1128  //Loop through the SYN queue
1129  while(queueItem != NULL)
1130  {
1131 #if (IPV4_SUPPORT == ENABLED)
1132  //IPv4 packet received?
1133  if(queueItem->srcAddr.length == sizeof(Ipv4Addr) &&
1134  queueItem->destAddr.length == sizeof(Ipv4Addr) &&
1135  pseudoHeader->length == sizeof(Ipv4PseudoHeader))
1136  {
1137  //Check source and destination addresses
1138  if(queueItem->srcAddr.ipv4Addr == pseudoHeader->ipv4Data.srcAddr &&
1139  queueItem->destAddr.ipv4Addr == pseudoHeader->ipv4Data.destAddr)
1140  {
1141  //Check source port
1142  if(queueItem->srcPort == segment->srcPort)
1143  {
1144  //Duplicate SYN
1145  flag = TRUE;
1146  }
1147  }
1148  }
1149  else
1150 #endif
1151 #if (IPV6_SUPPORT == ENABLED)
1152  //IPv6 packet received?
1153  if(queueItem->srcAddr.length == sizeof(Ipv6Addr) &&
1154  queueItem->destAddr.length == sizeof(Ipv6Addr) &&
1155  pseudoHeader->length == sizeof(Ipv6PseudoHeader))
1156  {
1157  //Check source and destination addresses
1158  if(ipv6CompAddr(&queueItem->srcAddr.ipv6Addr, &pseudoHeader->ipv6Data.srcAddr) &&
1159  ipv6CompAddr(&queueItem->destAddr.ipv6Addr, &pseudoHeader->ipv6Data.destAddr))
1160  {
1161  //Check source port
1162  if(queueItem->srcPort == segment->srcPort)
1163  {
1164  //Duplicate SYN
1165  flag = TRUE;
1166  }
1167  }
1168  }
1169  else
1170 #endif
1171  {
1172  //Just for sanity
1173  }
1174 
1175  //Next item
1176  queueItem = queueItem->next;
1177  }
1178 
1179  //Return TRUE if the SYN segment is a duplicate
1180  return flag;
1181 }
1182 
1183 
1184 /**
1185  * @brief Test whether the incoming acknowledgment is a duplicate
1186  * @param[in] socket Handle referencing the current socket
1187  * @param[in] segment Pointer to the TCP segment to check
1188  * @param[in] length Length of the segment data
1189  * @return TRUE if the ACK is duplicate, else FALSE
1190  **/
1191 
1193  size_t length)
1194 {
1195  bool_t flag;
1196 
1197  //An ACK is considered a duplicate when the following conditions are met
1198  flag = FALSE;
1199 
1200  //The receiver of the ACK has outstanding data
1201  if(socket->retransmitQueue != NULL)
1202  {
1203  //The incoming acknowledgment carries no data
1204  if(length == 0)
1205  {
1206  //The SYN and FIN bits are both off
1207  if((segment->flags & (TCP_FLAG_SYN | TCP_FLAG_FIN)) == 0)
1208  {
1209  //The acknowledgment number is equal to the greatest acknowledgment
1210  //received on the given connection
1211  if(segment->ackNum == socket->sndUna)
1212  {
1213  //The advertised window in the incoming acknowledgment equals
1214  //the advertised window in the last incoming acknowledgment
1215  if(segment->window == socket->sndWnd)
1216  {
1217  //Duplicate ACK
1218  flag = TRUE;
1219  }
1220  }
1221  }
1222  }
1223  }
1224 
1225  //Return TRUE if the acknowledgment is a duplicate
1226  return flag;
1227 }
1228 
1229 
1230 /**
1231  * @brief Fast retransmit procedure
1232  * @param[in] socket Handle referencing the current socket
1233  **/
1234 
1236 {
1237 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1238  uint32_t flightSize;
1239 
1240  //Amount of data that has been sent but not yet acknowledged
1241  flightSize = socket->sndNxt - socket->sndUna;
1242  //After receiving 3 duplicate ACKs, ssthresh must be adjusted
1243  socket->ssthresh = MAX(flightSize / 2, (uint32_t) socket->smss * 2);
1244 
1245  //The value of recover is incremented to the value of the highest
1246  //sequence number transmitted by the TCP so far
1247  socket->recover = socket->sndNxt - 1;
1248 
1249  //Debug message
1250  TRACE_INFO("TCP fast retransmit...\r\n");
1251 
1252  //TCP performs a retransmission of what appears to be the missing segment,
1253  //without waiting for the retransmission timer to expire
1255 
1256  //cwnd must set to ssthresh plus 3*SMSS. This artificially inflates the
1257  //congestion window by the number of segments (three) that have left the
1258  //network and which the receiver has buffered
1259  socket->cwnd = socket->ssthresh + (socket->smss * TCP_FAST_RETRANSMIT_THRES);
1260 
1261  //Enter the fast recovery procedure
1262  socket->congestState = TCP_CONGEST_STATE_RECOVERY;
1263 #endif
1264 }
1265 
1266 
1267 /**
1268  * @brief Fast recovery procedure
1269  * @param[in] socket Handle referencing the current socket
1270  * @param[in] segment Pointer to the incoming TCP segment
1271  * @param[in] n Number of bytes acknowledged by the incoming ACK
1272  **/
1273 
1274 void tcpFastRecovery(Socket *socket, const TcpHeader *segment, uint32_t n)
1275 {
1276 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1277  //Check whether this ACK acknowledges all of the data up to and including
1278  //recover
1279  if(TCP_CMP_SEQ(segment->ackNum, socket->recover) > 0)
1280  {
1281  //This is a full acknowledgment
1282  TRACE_INFO("TCP full acknowledgment\r\n");
1283 
1284  //Set cwnd to ssthresh
1285  socket->cwnd = socket->ssthresh;
1286  //Exit the fast recovery procedure
1287  socket->congestState = TCP_CONGEST_STATE_IDLE;
1288  }
1289  else
1290  {
1291  //If this ACK does not acknowledge all of the data up to and including
1292  //recover, then this is a partial ACK
1293  TRACE_INFO("TCP partial acknowledgment\r\n");
1294 
1295  //Retransmit the first unacknowledged segment
1297 
1298  //Deflate the congestion window by the amount of new data acknowledged
1299  //by the cumulative acknowledgment field
1300  if(socket->cwnd > n)
1301  socket->cwnd -= n;
1302 
1303  //If the partial ACK acknowledges at least one SMSS of new data, then
1304  //add back SMSS bytes to the congestion window. This artificially
1305  //inflates the congestion window in order to reflect the additional
1306  //segment that has left the network
1307  if(n >= socket->smss)
1308  socket->cwnd += socket->smss;
1309 
1310  //Do not exit the fast recovery procedure...
1311  socket->congestState = TCP_CONGEST_STATE_RECOVERY;
1312  }
1313 #endif
1314 }
1315 
1316 
1317 /**
1318  * @brief Fast loss recovery procedure
1319  * @param[in] socket Handle referencing the current socket
1320  * @param[in] segment Pointer to the incoming TCP segment
1321  **/
1322 
1324 {
1325 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1326  //Check whether this ACK acknowledges all of the data up to and
1327  //including recover
1328  if(TCP_CMP_SEQ(segment->ackNum, socket->recover) > 0)
1329  {
1330  //This is a full acknowledgment
1331  TRACE_INFO("TCP full acknowledgment\r\n");
1332 
1333  //Exit the fast loss recovery procedure
1334  socket->congestState = TCP_CONGEST_STATE_IDLE;
1335  }
1336  else
1337  {
1338  //If this ACK does not acknowledge all of the data up to and including
1339  //recover, then this is a partial ACK
1340  TRACE_INFO("TCP partial acknowledgment\r\n");
1341 
1342  //Retransmit the first unacknowledged segment
1344 
1345  //Do not exit the fast loss recovery procedure...
1346  socket->congestState = TCP_CONGEST_STATE_LOSS_RECOVERY;
1347  }
1348 #endif
1349 }
1350 
1351 
1352 /**
1353  * @brief Process the segment text
1354  * @param[in] socket Handle referencing the current socket
1355  * @param[in] segment Pointer to the TCP header
1356  * @param[in] buffer Multi-part buffer containing the incoming TCP segment
1357  * @param[in] offset Offset to the first data byte
1358  * @param[in] length Length of the segment data
1359  **/
1360 
1362  const NetBuffer *buffer, size_t offset, size_t length)
1363 {
1364  uint32_t leftEdge;
1365  uint32_t rightEdge;
1366 
1367  //First sequence number occupied by the incoming segment
1368  leftEdge = segment->seqNum;
1369  //Sequence number immediately following the incoming segment
1370  rightEdge = segment->seqNum + length;
1371 
1372  //Check whether some data falls outside the receive window
1373  if(TCP_CMP_SEQ(leftEdge, socket->rcvNxt) < 0)
1374  {
1375  //Position of the first byte to be read
1376  offset += socket->rcvNxt - leftEdge;
1377  //Ignore the data that falls outside the receive window
1378  leftEdge = socket->rcvNxt;
1379  }
1380 
1381  if(TCP_CMP_SEQ(rightEdge, socket->rcvNxt + socket->rcvWnd) > 0)
1382  {
1383  //Ignore the data that falls outside the receive window
1384  rightEdge = socket->rcvNxt + socket->rcvWnd;
1385  }
1386 
1387  //Copy the incoming data to the receive buffer
1388  tcpWriteRxBuffer(socket, leftEdge, buffer, offset, rightEdge - leftEdge);
1389 
1390  //Update the list of non-contiguous blocks of data that have been received
1391  //and queued
1392  tcpUpdateSackBlocks(socket, &leftEdge, &rightEdge);
1393 
1394  //Check whether the segment was received out of order
1395  if(TCP_CMP_SEQ(leftEdge, socket->rcvNxt) > 0)
1396  {
1397  //Out of order data segments should be acknowledged immediately, in order
1398  //to accelerate loss recovery
1399  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0,
1400  FALSE);
1401  }
1402  else
1403  {
1404  //Number of contiguous bytes that have been received
1405  length = rightEdge - leftEdge;
1406 
1407  //Next sequence number expected on incoming segments
1408  socket->rcvNxt += length;
1409  //Number of data available in the receive buffer
1410  socket->rcvUser += length;
1411  //Update the receive window
1412  socket->rcvWnd -= length;
1413 
1414  //Acknowledge the received data (delayed ACK not supported)
1415  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0,
1416  FALSE);
1417 
1418  //Notify user task that data is available
1420  }
1421 }
1422 
1423 
1424 /**
1425  * @brief Delete TCB structure
1426  * @param[in] socket Handle referencing the socket
1427  **/
1428 
1430 {
1431  //Delete retransmission queue
1433 
1434  //Delete SYN queue
1436 
1437  //Release transmit buffer
1438  netBufferSetLength((NetBuffer *) &socket->txBuffer, 0);
1439 
1440  //Release receive buffer
1441  netBufferSetLength((NetBuffer *) &socket->rxBuffer, 0);
1442 }
1443 
1444 
1445 /**
1446  * @brief Remove acknowledged segments from retransmission queue
1447  * @param[in] socket Handle referencing the socket
1448  **/
1449 
1451 {
1452  size_t length;
1453  TcpQueueItem *prevQueueItem;
1454  TcpQueueItem *queueItem;
1455  TcpHeader *header;
1456 
1457  //Point to the first item of the retransmission queue
1458  prevQueueItem = NULL;
1459  queueItem = socket->retransmitQueue;
1460 
1461  //Loop through retransmission queue
1462  while(queueItem != NULL)
1463  {
1464  //Point to the TCP header
1465  header = (TcpHeader *) queueItem->header;
1466 
1467  //Calculate the length of the TCP segment
1468  if(header->flags & TCP_FLAG_SYN)
1469  {
1470  length = 1;
1471  }
1472  else if(header->flags & TCP_FLAG_FIN)
1473  {
1474  length = queueItem->length + 1;
1475  }
1476  else
1477  {
1478  length = queueItem->length;
1479  }
1480 
1481  //If an acknowledgment is received for a segment before its timer
1482  //expires, the segment is removed from the retransmission queue
1483  if(TCP_CMP_SEQ(socket->sndUna, ntohl(header->seqNum) + length) >= 0)
1484  {
1485  //First item of the queue?
1486  if(prevQueueItem == NULL)
1487  {
1488  //Remove the current item from the queue
1489  socket->retransmitQueue = queueItem->next;
1490  //The item can now be safely deleted
1491  memPoolFree(queueItem);
1492  //Point to the next item
1493  queueItem = socket->retransmitQueue;
1494  }
1495  else
1496  {
1497  //Remove the current item from the queue
1498  prevQueueItem->next = queueItem->next;
1499  //The item can now be safely deleted
1500  memPoolFree(queueItem);
1501  //Point to the next item
1502  queueItem = prevQueueItem->next;
1503  }
1504 
1505  //When an ACK is received that acknowledges new data, restart the
1506  //retransmission timer so that it will expire after RTO seconds
1507  netStartTimer(&socket->retransmitTimer, socket->rto);
1508  //Reset retransmission counter
1509  socket->retransmitCount = 0;
1510  }
1511  //No acknowledgment received for the current segment...
1512  else
1513  {
1514  //Point to the next item
1515  prevQueueItem = queueItem;
1516  queueItem = queueItem->next;
1517  }
1518  }
1519 
1520  //When all outstanding data has been acknowledged,
1521  //turn off the retransmission timer
1522  if(socket->retransmitQueue == NULL)
1523  netStopTimer(&socket->retransmitTimer);
1524 }
1525 
1526 
1527 /**
1528  * @brief Flush retransmission queue
1529  * @param[in] socket Handle referencing the socket
1530  **/
1531 
1533 {
1534  //Point to the first item in the retransmission queue
1535  TcpQueueItem *queueItem = socket->retransmitQueue;
1536 
1537  //Loop through retransmission queue
1538  while(queueItem != NULL)
1539  {
1540  //Keep track of the next item in the queue
1541  TcpQueueItem *nextQueueItem = queueItem->next;
1542  //Free previously allocated memory
1543  memPoolFree(queueItem);
1544  //Point to the next item
1545  queueItem = nextQueueItem;
1546  }
1547 
1548  //The retransmission queue is now flushed
1549  socket->retransmitQueue = NULL;
1550 
1551  //Turn off the retransmission timer
1552  netStopTimer(&socket->retransmitTimer);
1553 }
1554 
1555 
1556 /**
1557  * @brief Flush SYN queue
1558  * @param[in] socket Handle referencing the socket
1559  **/
1560 
1562 {
1563  //Point to the first item in the SYN queue
1564  TcpSynQueueItem *queueItem = socket->synQueue;
1565 
1566  //Loop through SYN queue
1567  while(queueItem != NULL)
1568  {
1569  //Keep track of the next item in the queue
1570  TcpSynQueueItem *nextQueueItem = queueItem->next;
1571  //Free previously allocated memory
1572  memPoolFree(queueItem);
1573  //Point to the next item
1574  queueItem = nextQueueItem;
1575  }
1576 
1577  //SYN queue was successfully flushed
1578  socket->synQueue = NULL;
1579 }
1580 
1581 
1582 /**
1583  * @brief Compute the window scale factor to use for the receive window
1584  * @param[in] socket Handle referencing the socket
1585  **/
1586 
1588 {
1589 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
1590  uint32_t n;
1591  uint32_t window;
1592 
1593  //The window scale extension expands the definition of the TCP window to
1594  //30 bits and then uses an implicit scale factor to carry this 30-bit
1595  //value in the 16-bit window field of the TCP header
1596  window = socket->rxBufferSize;
1597 
1598  //The scale factor is determined by the maximum receive buffer space
1599  for(n = 0; window > UINT16_MAX; n++)
1600  {
1601  window >>= 1;
1602  }
1603 
1604  //The window scale is fixed in each direction when a connection is opened
1605  socket->rcvWndShift = n;
1606 #endif
1607 }
1608 
1609 
1610 /**
1611  * @brief Update the list of non-contiguous blocks that have been received
1612  * @param[in] socket Handle referencing the socket
1613  * @param[in,out] leftEdge First sequence number occupied by the incoming data
1614  * @param[in,out] rightEdge Sequence number immediately following the incoming data
1615  **/
1616 
1617 void tcpUpdateSackBlocks(Socket *socket, uint32_t *leftEdge, uint32_t *rightEdge)
1618 {
1619  uint_t i = 0;
1620 
1621  //Loop through the blocks
1622  while(i < socket->sackBlockCount)
1623  {
1624  //Find each block that overlaps the specified one
1625  if(TCP_CMP_SEQ(*rightEdge, socket->sackBlock[i].leftEdge) >= 0 &&
1626  TCP_CMP_SEQ(*leftEdge, socket->sackBlock[i].rightEdge) <= 0)
1627  {
1628  //Merge blocks to form a contiguous one
1629  *leftEdge = MIN(*leftEdge, socket->sackBlock[i].leftEdge);
1630  *rightEdge = MAX(*rightEdge, socket->sackBlock[i].rightEdge);
1631 
1632  //Delete current block
1633  osMemmove(socket->sackBlock + i, socket->sackBlock + i + 1,
1634  (TCP_MAX_SACK_BLOCKS - i - 1) * sizeof(TcpSackBlock));
1635 
1636  //Decrement the number of non-contiguous blocks
1637  socket->sackBlockCount--;
1638  }
1639  else
1640  {
1641  //Point to the next block
1642  i++;
1643  }
1644  }
1645 
1646  //Check whether the incoming segment was received out of order
1647  if(TCP_CMP_SEQ(*leftEdge, socket->rcvNxt) > 0)
1648  {
1649  //Make room for the new non-contiguous block
1650  osMemmove(socket->sackBlock + 1, socket->sackBlock,
1651  (TCP_MAX_SACK_BLOCKS - 1) * sizeof(TcpSackBlock));
1652 
1653  //Insert the element in the list
1654  socket->sackBlock[0].leftEdge = *leftEdge;
1655  socket->sackBlock[0].rightEdge = *rightEdge;
1656 
1657  //Increment the number of non-contiguous blocks
1658  if(socket->sackBlockCount < TCP_MAX_SACK_BLOCKS)
1659  {
1660  socket->sackBlockCount++;
1661  }
1662  }
1663 }
1664 
1665 
1666 /**
1667  * @brief Update send window
1668  * @param[in] socket Handle referencing the socket
1669  * @param[in] segment Pointer to the incoming TCP segment
1670  **/
1671 
1673 {
1674  uint32_t window;
1675 
1676 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
1677  //The window field (SEG.WND) in the header of every incoming segment, with
1678  //the exception of SYN segments, MUST be left-shifted by Snd.Wind.Shift bits
1679  //before updating SND.WND (refer to RFC 7323, section 2.3)
1680  window = (uint32_t) segment->window << socket->sndWndShift;
1681 #else
1682  //The maximum unscaled window is 2^16 - 1
1683  window = segment->window;
1684 #endif
1685 
1686  //Case where neither the sequence nor the acknowledgment number is increased
1687  if(segment->seqNum == socket->sndWl1 && segment->ackNum == socket->sndWl2)
1688  {
1689  //TCP may ignore a window update with a smaller window than previously
1690  //offered if neither the sequence number nor the acknowledgment number
1691  //is increased (refer to RFC 1122, section 4.2.2.16)
1692  if(window > socket->sndWnd)
1693  {
1694  //Update the send window and record the sequence number and the
1695  //acknowledgment number used to update SND.WND
1696  socket->sndWnd = window;
1697  socket->sndWl1 = segment->seqNum;
1698  socket->sndWl2 = segment->ackNum;
1699 
1700  //Maximum send window it has seen so far on the connection
1701  socket->maxSndWnd = MAX(socket->maxSndWnd, window);
1702  }
1703  }
1704  //Case where the sequence or the acknowledgment number is increased
1705  else if(TCP_CMP_SEQ(segment->seqNum, socket->sndWl1) >= 0 &&
1706  TCP_CMP_SEQ(segment->ackNum, socket->sndWl2) >= 0)
1707  {
1708  //Check whether the remote host advertises a zero window
1709  if(window == 0 && socket->sndWnd != 0)
1710  {
1711  //Start the persist timer
1712  socket->wndProbeCount = 0;
1713  socket->wndProbeInterval = TCP_DEFAULT_PROBE_INTERVAL;
1714  netStartTimer(&socket->persistTimer, socket->wndProbeInterval);
1715  }
1716 
1717  //Update the send window and record the sequence number and the
1718  //acknowledgment number used to update SND.WND
1719  socket->sndWnd = window;
1720  socket->sndWl1 = segment->seqNum;
1721  socket->sndWl2 = segment->ackNum;
1722 
1723  //Maximum send window it has seen so far on the connection
1724  socket->maxSndWnd = MAX(socket->maxSndWnd, window);
1725  }
1726  else
1727  {
1728  //Just for sanity
1729  }
1730 }
1731 
1732 
1733 /**
1734  * @brief Update receive window so as to avoid Silly Window Syndrome
1735  * @param[in] socket Handle referencing the socket
1736  **/
1737 
1739 {
1740  uint32_t reduction;
1741 
1742  //Space available but not yet advertised
1743  reduction = socket->rxBufferSize - socket->rcvUser - socket->rcvWnd;
1744 
1745  //To avoid SWS, the receiver should not advertise small windows
1746  if((socket->rcvWnd + reduction) >= MIN(socket->rmss, socket->rxBufferSize / 2))
1747  {
1748  //Check whether a window update should be sent
1749  if(socket->rcvWnd < MIN(socket->rmss, socket->rxBufferSize / 2))
1750  {
1751  //Debug message
1752  TRACE_INFO("%s: TCP sending window update...\r\n",
1754 
1755  //Update the receive window
1756  socket->rcvWnd += reduction;
1757 
1758  //Send an ACK segment to advertise the new window size
1759  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt,
1760  0, FALSE);
1761  }
1762  else
1763  {
1764  //The receive window can be updated
1765  socket->rcvWnd += reduction;
1766  }
1767  }
1768 }
1769 
1770 
1771 /**
1772  * @brief Compute retransmission timeout
1773  * @param[in] socket Handle referencing the socket
1774  * @return TRUE if the RTT measurement is complete, else FALSE
1775  **/
1776 
1778 {
1779  bool_t flag;
1780  systime_t r;
1781  systime_t delta;
1782 
1783  //Clear flag
1784  flag = FALSE;
1785 
1786  //TCP implementation takes one RTT measurement at a time
1787  if(socket->rttBusy)
1788  {
1789  //Ensure the incoming ACK number covers the expected sequence number
1790  if(TCP_CMP_SEQ(socket->sndUna, socket->rttSeqNum) > 0)
1791  {
1792  //Calculate round-time trip
1793  r = osGetSystemTime() - socket->rttStartTime;
1794 
1795  //First RTT measurement?
1796  if(socket->srtt == 0 && socket->rttvar == 0)
1797  {
1798  //Initialize RTO calculation algorithm
1799  socket->srtt = r;
1800  socket->rttvar = r / 2;
1801  }
1802  else
1803  {
1804  //Calculate the difference between the measured value and the
1805  //current RTT estimator
1806  delta = (r > socket->srtt) ? (r - socket->srtt) : (socket->srtt - r);
1807 
1808  //Implement Van Jacobson's algorithm (as specified in RFC 6298 2.3)
1809  socket->rttvar = ((socket->rttvar * 3) + delta) / 4;
1810  socket->srtt = ((socket->srtt * 7) + r) / 8;
1811  }
1812 
1813  //Calculate the next retransmission timeout
1814  socket->rto = socket->srtt + (socket->rttvar * 4);
1815 
1816  //Whenever RTO is computed, if it is less than 1 second, then the RTO
1817  //should be rounded up to 1 second
1818  socket->rto = MAX(socket->rto, TCP_MIN_RTO);
1819 
1820  //A maximum value may be placed on RTO provided it is at least 60
1821  //seconds
1822  socket->rto = MIN(socket->rto, TCP_MAX_RTO);
1823 
1824  //Debug message
1825  TRACE_DEBUG("R=%" PRIu32 ", SRTT=%" PRIu32 ", RTTVAR=%" PRIu32 ", RTO=%" PRIu32 "\r\n",
1826  r, socket->srtt, socket->rttvar, socket->rto);
1827 
1828  //RTT measurement is complete
1829  socket->rttBusy = FALSE;
1830  //Set flag
1831  flag = TRUE;
1832  }
1833  }
1834 
1835  //Return TRUE if the RTT measurement is complete
1836  return flag;
1837 }
1838 
1839 
1840 /**
1841  * @brief TCP segment retransmission
1842  * @param[in] socket Handle referencing the socket
1843  * @return Error code
1844  **/
1845 
1847 {
1848  error_t error;
1849  size_t offset;
1850  size_t length;
1851  NetBuffer *buffer;
1852  TcpQueueItem *queueItem;
1853  TcpHeader *segment;
1854  NetTxAncillary ancillary;
1855 
1856  //Initialize error code
1857  error = NO_ERROR;
1858  //Total number of bytes that have been retransmitted
1859  length = 0;
1860 
1861  //Point to the retransmission queue
1862  queueItem = socket->retransmitQueue;
1863 
1864  //Any segment in the retransmission queue?
1865  while(queueItem != NULL)
1866  {
1867  //Total number of bytes that have been retransmitted
1868  length += queueItem->length;
1869 
1870  //The amount of data that can be sent cannot exceed the MSS
1871  if(length > socket->smss)
1872  {
1873  //We are done
1874  error = NO_ERROR;
1875  //Exit immediately
1876  break;
1877  }
1878 
1879  //Allocate a memory buffer to hold the TCP segment
1880  buffer = ipAllocBuffer(TCP_MAX_HEADER_LENGTH, &offset);
1881  //Failed to allocate memory?
1882  if(buffer == NULL)
1883  {
1884  //Report an error
1885  error = ERROR_OUT_OF_MEMORY;
1886  //Exit immediately
1887  break;
1888  }
1889 
1890  //Start of exception handling block
1891  do
1892  {
1893  //Point to the beginning of the TCP segment
1894  segment = netBufferAt(buffer, offset, 0);
1895 
1896  //Copy TCP header
1897  osMemcpy(segment, queueItem->header, TCP_MAX_HEADER_LENGTH);
1898 
1899  //Update ACK number
1900  segment->ackNum = htonl(socket->rcvNxt);
1901 
1902 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
1903  //The window field in a segment where the SYN bit is set must not be
1904  //scaled (refer to RFC 7323, section 2.2)
1905  if((segment->flags & TCP_FLAG_SYN) == 0 &&
1906  socket->wndScaleOptionReceived)
1907  {
1908  //The window field (SEG.WND) of every outgoing segment, with the
1909  //exception of SYN segments, must be right-shifted by Rcv.Wind.Shift
1910  //bits (refer to RFC 7323, section 2.3)
1911  segment->window = htons(socket->rcvWnd >> socket->rcvWndShift);
1912  }
1913  else
1914  {
1915  //The maximum unscaled window is 2^16 - 1
1916  segment->window = htons(MIN(socket->rcvWnd, UINT16_MAX));
1917  }
1918 #else
1919  //The window field indicates the number of data octets beginning with
1920  //the one indicated in the acknowledgment field that the sender of
1921  //this segment is willing to accept (refer to RFC 793, section 3.1)
1922  segment->window = htons(MIN(socket->rcvWnd, UINT16_MAX));
1923 #endif
1924  //The checksum field is replaced with zeros
1925  segment->checksum = 0;
1926 
1927  //Adjust the length of the multi-part buffer
1928  netBufferSetLength(buffer, offset + segment->dataOffset * 4);
1929 
1930  //Copy data from send buffer
1931  error = tcpReadTxBuffer(socket, ntohl(segment->seqNum), buffer,
1932  queueItem->length);
1933  //Any error to report?
1934  if(error)
1935  break;
1936 
1937 #if (IPV4_SUPPORT == ENABLED)
1938  //Destination address is an IPv4 address?
1939  if(queueItem->pseudoHeader.length == sizeof(Ipv4PseudoHeader))
1940  {
1941  //Calculate TCP header checksum
1942  segment->checksum = ipCalcUpperLayerChecksumEx(
1943  &queueItem->pseudoHeader.ipv4Data, sizeof(Ipv4PseudoHeader),
1944  buffer, offset, segment->dataOffset * 4 + queueItem->length);
1945  }
1946  else
1947 #endif
1948 #if (IPV6_SUPPORT == ENABLED)
1949  //Destination address is an IPv6 address?
1950  if(queueItem->pseudoHeader.length == sizeof(Ipv6PseudoHeader))
1951  {
1952  //Calculate TCP header checksum
1953  segment->checksum = ipCalcUpperLayerChecksumEx(
1954  &queueItem->pseudoHeader.ipv6Data, sizeof(Ipv6PseudoHeader),
1955  buffer, offset, segment->dataOffset * 4 + queueItem->length);
1956  }
1957  else
1958 #endif
1959  //Destination address is not valid?
1960  {
1961  //This should never occur...
1962  error = ERROR_INVALID_ADDRESS;
1963  break;
1964  }
1965 
1966  //Total number of segments retransmitted
1967  MIB2_TCP_INC_COUNTER32(tcpRetransSegs, 1);
1968  TCP_MIB_INC_COUNTER32(tcpRetransSegs, 1);
1969 
1970  //Dump TCP header contents for debugging purpose
1971  tcpDumpHeader(segment, queueItem->length, socket->iss, socket->irs);
1972 
1973  //Additional options can be passed to the stack along with the packet
1974  ancillary = NET_DEFAULT_TX_ANCILLARY;
1975  //Set the TTL value to be used
1976  ancillary.ttl = socket->ttl;
1977 
1978 #if (ETH_VLAN_SUPPORT == ENABLED)
1979  //Set VLAN PCP and DEI fields
1980  ancillary.vlanPcp = socket->vlanPcp;
1981  ancillary.vlanDei = socket->vlanDei;
1982 #endif
1983 
1984 #if (ETH_VMAN_SUPPORT == ENABLED)
1985  //Set VMAN PCP and DEI fields
1986  ancillary.vmanPcp = socket->vmanPcp;
1987  ancillary.vmanDei = socket->vmanDei;
1988 #endif
1989  //Retransmit the lost segment without waiting for the retransmission
1990  //timer to expire
1991  error = ipSendDatagram(socket->interface, &queueItem->pseudoHeader,
1992  buffer, offset, &ancillary);
1993 
1994  //End of exception handling block
1995  } while(0);
1996 
1997  //Free previously allocated memory
1998  netBufferFree(buffer);
1999 
2000  //Any error to report?
2001  if(error)
2002  {
2003  //Exit immediately
2004  break;
2005  }
2006 
2007  //Point to the next segment in the queue
2008  queueItem = queueItem->next;
2009  }
2010 
2011  //Return status code
2012  return error;
2013 }
2014 
2015 
2016 /**
2017  * @brief Nagle algorithm implementation
2018  * @param[in] socket Handle referencing the socket
2019  * @param[in] flags Set of flags that influences the behavior of this function
2020  * @return Error code
2021  **/
2022 
2024 {
2025  error_t error;
2026  uint32_t n;
2027  uint32_t u;
2028 
2029  //Initialize status code
2030  error = NO_ERROR;
2031 
2032  //The amount of data that can be sent at any given time is limited by the
2033  //receiver window and the congestion window
2034  n = MIN(socket->sndWnd, socket->txBufferSize);
2035 
2036 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
2037  //Check the congestion window
2038  n = MIN(n, socket->cwnd);
2039 #endif
2040 
2041  //Retrieve the size of the usable window
2042  u = n - (socket->sndNxt - socket->sndUna);
2043 
2044  //The Nagle algorithm discourages sending tiny segments when the data to be
2045  //sent increases in small increments
2046  while(socket->sndUser > 0 && !error)
2047  {
2048  //The usable window size may become zero or negative, preventing packet
2049  //transmission
2050  if((int32_t) u <= 0)
2051  break;
2052 
2053  //Calculate the number of bytes to send at a time
2054  n = MIN(u, socket->sndUser);
2055  n = MIN(n, socket->smss);
2056 
2057  //Disable Nagle algorithm?
2058  if((flags & SOCKET_FLAG_NO_DELAY) != 0)
2059  {
2060  //All packets will be send no matter what size they have
2061  if(n > 0)
2062  {
2063  //Send TCP segment
2065  socket->sndNxt, socket->rcvNxt, n, TRUE);
2066  }
2067  else
2068  {
2069  //We are done
2070  break;
2071  }
2072  }
2073  else if((flags & SOCKET_FLAG_DELAY) != 0)
2074  {
2075  //Transmit data if a maximum-sized segment can be sent
2076  if(MIN(socket->sndUser, u) >= socket->smss)
2077  {
2078  //Send TCP segment
2080  socket->sndNxt, socket->rcvNxt, n, TRUE);
2081  }
2082  else
2083  {
2084  //Prevent the sender from sending tiny segments
2085  break;
2086  }
2087  }
2088  else
2089  {
2090  //Transmit data if a maximum-sized segment can be sent
2091  if(MIN(socket->sndUser, u) >= socket->smss)
2092  {
2093  //Send TCP segment
2095  socket->sndNxt, socket->rcvNxt, n, TRUE);
2096  }
2097  //Or if all queued data can be sent now
2098  else if(socket->sndNxt == socket->sndUna && socket->sndUser <= u)
2099  {
2100  //Send TCP segment
2102  socket->sndNxt, socket->rcvNxt, n, TRUE);
2103  }
2104  //Or if at least a fraction of the maximum window can be sent
2105  else if(MIN(socket->sndUser, u) >= (socket->maxSndWnd / 2))
2106  {
2107  //Send TCP segment
2109  socket->sndNxt, socket->rcvNxt, n, TRUE);
2110  }
2111  else
2112  {
2113  //Prevent the sender from sending tiny segments
2114  break;
2115  }
2116  }
2117 
2118  //Check status code
2119  if(!error)
2120  {
2121  //Advance SND.NXT pointer
2122  socket->sndNxt += n;
2123  //Update the number of data buffered but not yet sent
2124  socket->sndUser -= n;
2125  //Update the size of the usable window
2126  u -= n;
2127  }
2128  }
2129 
2130  //Check whether the transmitter can accept more data
2132 
2133  //Return status code
2134  return error;
2135 }
2136 
2137 
2138 /**
2139  * @brief Update TCP FSM current state
2140  * @param[in] socket Handle referencing the socket
2141  * @param[in] newState New TCP state to switch to
2142  **/
2143 
2145 {
2146  //Enter CLOSED state?
2147  if(newState == TCP_STATE_CLOSED)
2148  {
2149  //Check previous state
2150  if(socket->state == TCP_STATE_LAST_ACK ||
2151  socket->state == TCP_STATE_TIME_WAIT)
2152  {
2153  //The connection has been closed properly
2154  socket->closedFlag = TRUE;
2155  }
2156  else
2157  {
2158  //The connection has been reset by the peer
2159  socket->resetFlag = TRUE;
2160  }
2161  }
2162 
2163  //Enter the desired state
2164  socket->state = newState;
2165  //Update TCP related events
2167 }
2168 
2169 
2170 /**
2171  * @brief Update TCP related events
2172  * @param[in] socket Handle referencing the socket
2173  **/
2174 
2176 {
2177  //Clear event flags
2178  socket->eventFlags = 0;
2179 
2180  //Check current TCP state
2181  switch(socket->state)
2182  {
2183  //ESTABLISHED or FIN-WAIT-1 state?
2184  case TCP_STATE_ESTABLISHED:
2185  case TCP_STATE_FIN_WAIT_1:
2186  socket->eventFlags |= SOCKET_EVENT_CONNECTED;
2187  break;
2188 
2189  //FIN-WAIT-2 state?
2190  case TCP_STATE_FIN_WAIT_2:
2191  socket->eventFlags |= SOCKET_EVENT_CONNECTED;
2192  socket->eventFlags |= SOCKET_EVENT_TX_SHUTDOWN;
2193  break;
2194 
2195  //CLOSE-WAIT, LAST-ACK or CLOSING state?
2196  case TCP_STATE_CLOSE_WAIT:
2197  case TCP_STATE_LAST_ACK:
2198  case TCP_STATE_CLOSING:
2199  socket->eventFlags |= SOCKET_EVENT_CONNECTED;
2200  socket->eventFlags |= SOCKET_EVENT_RX_SHUTDOWN;
2201  break;
2202 
2203  //TIME-WAIT or CLOSED state?
2204  case TCP_STATE_TIME_WAIT:
2205  case TCP_STATE_CLOSED:
2206  socket->eventFlags |= SOCKET_EVENT_CLOSED;
2207  socket->eventFlags |= SOCKET_EVENT_TX_SHUTDOWN;
2208  socket->eventFlags |= SOCKET_EVENT_RX_SHUTDOWN;
2209  break;
2210 
2211  //Any other state
2212  default:
2213  break;
2214  }
2215 
2216  //Handle TX specific events
2217  if(socket->state == TCP_STATE_SYN_SENT ||
2218  socket->state == TCP_STATE_SYN_RECEIVED)
2219  {
2220  //Disallow write operations until the connection is established
2221  socket->eventFlags |= SOCKET_EVENT_TX_DONE;
2222  socket->eventFlags |= SOCKET_EVENT_TX_ACKED;
2223  }
2224  else if(socket->state == TCP_STATE_ESTABLISHED ||
2225  socket->state == TCP_STATE_CLOSE_WAIT)
2226  {
2227  //Check whether the send buffer is full or not
2228  if((socket->sndUser + socket->sndNxt - socket->sndUna) < socket->txBufferSize)
2229  {
2230  socket->eventFlags |= SOCKET_EVENT_TX_READY;
2231  }
2232 
2233  //Check whether all the data in the send buffer has been transmitted
2234  if(socket->sndUser == 0)
2235  {
2236  //All the pending data has been sent out
2237  socket->eventFlags |= SOCKET_EVENT_TX_DONE;
2238 
2239  //Check whether an acknowledgment has been received
2240  if(TCP_CMP_SEQ(socket->sndUna, socket->sndNxt) >= 0)
2241  {
2242  socket->eventFlags |= SOCKET_EVENT_TX_ACKED;
2243  }
2244  }
2245  }
2246  else if(socket->state != TCP_STATE_LISTEN)
2247  {
2248  //Unblock user task if the connection is being closed
2249  socket->eventFlags |= SOCKET_EVENT_TX_READY;
2250  socket->eventFlags |= SOCKET_EVENT_TX_DONE;
2251  socket->eventFlags |= SOCKET_EVENT_TX_ACKED;
2252  }
2253 
2254  //Handle RX specific events
2255  if(socket->state == TCP_STATE_ESTABLISHED ||
2256  socket->state == TCP_STATE_FIN_WAIT_1 ||
2257  socket->state == TCP_STATE_FIN_WAIT_2)
2258  {
2259  //Data is available for reading?
2260  if(socket->rcvUser > 0)
2261  {
2262  socket->eventFlags |= SOCKET_EVENT_RX_READY;
2263  }
2264  }
2265  else if(socket->state == TCP_STATE_LISTEN)
2266  {
2267  //If the socket is currently in the listen state, it will be marked
2268  //as readable if an incoming connection request has been received
2269  if(socket->synQueue != NULL)
2270  {
2271  socket->eventFlags |= SOCKET_EVENT_ACCEPT;
2272  socket->eventFlags |= SOCKET_EVENT_RX_READY;
2273  }
2274  }
2275  else if(socket->state != TCP_STATE_SYN_SENT &&
2276  socket->state != TCP_STATE_SYN_RECEIVED)
2277  {
2278  //Readability can also indicate that a request to close
2279  //the socket has been received from the peer
2280  socket->eventFlags |= SOCKET_EVENT_RX_READY;
2281  }
2282 
2283  //Check whether the socket is bound to a particular network interface
2284  if(socket->interface != NULL)
2285  {
2286  //Handle link up and link down events
2287  if(socket->interface->linkState)
2288  {
2289  socket->eventFlags |= SOCKET_EVENT_LINK_UP;
2290  }
2291  else
2292  {
2293  socket->eventFlags |= SOCKET_EVENT_LINK_DOWN;
2294  }
2295  }
2296 
2297  //Mask unused events
2298  socket->eventFlags &= socket->eventMask;
2299 
2300  //Any event to signal?
2301  if(socket->eventFlags)
2302  {
2303  //Unblock I/O operations currently in waiting state
2304  osSetEvent(&socket->event);
2305 
2306  //Set user event to signaled state if necessary
2307  if(socket->userEvent != NULL)
2308  {
2309  osSetEvent(socket->userEvent);
2310  }
2311  }
2312 }
2313 
2314 
2315 /**
2316  * @brief Wait for a particular TCP event
2317  * @param[in] socket Handle referencing the socket
2318  * @param[in] eventMask Logic OR of all the TCP events that will complete the wait
2319  * @param[in] timeout Maximum time to wait
2320  * @return Logic OR of all the TCP events that satisfied the wait
2321  **/
2322 
2324 {
2325  //Sanity check
2326  if(socket == NULL)
2327  return 0;
2328 
2329  //Only one of the events listed here may complete the wait
2330  socket->eventMask = eventMask;
2331  //Update TCP related events
2333 
2334  //No event is signaled?
2335  if(socket->eventFlags == 0)
2336  {
2337  //Reset the event object
2338  osResetEvent(&socket->event);
2339 
2340  //Release exclusive access
2342  //Wait until an event is triggered
2343  osWaitForEvent(&socket->event, timeout);
2344  //Get exclusive access
2346  }
2347 
2348  //Return the list of TCP events that satisfied the wait
2349  return socket->eventFlags;
2350 }
2351 
2352 
2353 /**
2354  * @brief Copy incoming data to the send buffer
2355  * @param[in] socket Handle referencing the socket
2356  * @param[in] seqNum First sequence number occupied by the incoming data
2357  * @param[in] data Data to write
2358  * @param[in] length Number of data to write
2359  **/
2360 
2362  const uint8_t *data, size_t length)
2363 {
2364  //Offset of the first byte to write in the circular buffer
2365  size_t offset = (seqNum - socket->iss - 1) % socket->txBufferSize;
2366 
2367  //Check whether the specified data crosses buffer boundaries
2368  if((offset + length) <= socket->txBufferSize)
2369  {
2370  //Copy the payload
2371  netBufferWrite((NetBuffer *) &socket->txBuffer,
2372  offset, data, length);
2373  }
2374  else
2375  {
2376  //Copy the first part of the payload
2377  netBufferWrite((NetBuffer *) &socket->txBuffer,
2378  offset, data, socket->txBufferSize - offset);
2379 
2380  //Wrap around to the beginning of the circular buffer
2381  netBufferWrite((NetBuffer *) &socket->txBuffer, 0,
2382  data + socket->txBufferSize - offset,
2383  length - socket->txBufferSize + offset);
2384  }
2385 }
2386 
2387 
2388 /**
2389  * @brief Copy data from the send buffer
2390  * @param[in] socket Handle referencing the socket
2391  * @param[in] seqNum Sequence number of the first data to read
2392  * @param[out] buffer Pointer to the output buffer
2393  * @param[in] length Number of data to read
2394  * @return Error code
2395  **/
2396 
2398  NetBuffer *buffer, size_t length)
2399 {
2400  error_t error;
2401 
2402  //Offset of the first byte to read in the circular buffer
2403  size_t offset = (seqNum - socket->iss - 1) % socket->txBufferSize;
2404 
2405  //Check whether the specified data crosses buffer boundaries
2406  if((offset + length) <= socket->txBufferSize)
2407  {
2408  //Copy the payload
2409  error = netBufferConcat(buffer, (NetBuffer *) &socket->txBuffer,
2410  offset, length);
2411  }
2412  else
2413  {
2414  //Copy the first part of the payload
2415  error = netBufferConcat(buffer, (NetBuffer *) &socket->txBuffer,
2416  offset, socket->txBufferSize - offset);
2417 
2418  //Check status code
2419  if(!error)
2420  {
2421  //Wrap around to the beginning of the circular buffer
2422  error = netBufferConcat(buffer, (NetBuffer *) &socket->txBuffer,
2423  0, length - socket->txBufferSize + offset);
2424  }
2425  }
2426 
2427  //Return status code
2428  return error;
2429 }
2430 
2431 
2432 /**
2433  * @brief Copy incoming data to the receive buffer
2434  * @param[in] socket Handle referencing the socket
2435  * @param[in] seqNum First sequence number occupied by the incoming data
2436  * @param[in] data Multi-part buffer containing the incoming data
2437  * @param[in] dataOffset Offset to the first data byte
2438  * @param[in] length Number of data to write
2439  **/
2440 
2442  const NetBuffer *data, size_t dataOffset, size_t length)
2443 {
2444  //Offset of the first byte to write in the circular buffer
2445  size_t offset = (seqNum - socket->irs - 1) % socket->rxBufferSize;
2446 
2447  //Check whether the specified data crosses buffer boundaries
2448  if((offset + length) <= socket->rxBufferSize)
2449  {
2450  //Copy the payload
2451  netBufferCopy((NetBuffer *) &socket->rxBuffer,
2452  offset, data, dataOffset, length);
2453  }
2454  else
2455  {
2456  //Copy the first part of the payload
2457  netBufferCopy((NetBuffer *) &socket->rxBuffer,
2458  offset, data, dataOffset, socket->rxBufferSize - offset);
2459 
2460  //Wrap around to the beginning of the circular buffer
2461  netBufferCopy((NetBuffer *) &socket->rxBuffer, 0, data,
2462  dataOffset + socket->rxBufferSize - offset,
2463  length - socket->rxBufferSize + offset);
2464  }
2465 }
2466 
2467 
2468 /**
2469  * @brief Copy data from the receive buffer
2470  * @param[in] socket Handle referencing the socket
2471  * @param[in] seqNum Sequence number of the first data to read
2472  * @param[out] data Pointer to the output buffer
2473  * @param[in] length Number of data to read
2474  **/
2475 
2476 void tcpReadRxBuffer(Socket *socket, uint32_t seqNum, uint8_t *data,
2477  size_t length)
2478 {
2479  //Offset of the first byte to read in the circular buffer
2480  size_t offset = (seqNum - socket->irs - 1) % socket->rxBufferSize;
2481 
2482  //Check whether the specified data crosses buffer boundaries
2483  if((offset + length) <= socket->rxBufferSize)
2484  {
2485  //Copy the payload
2486  netBufferRead(data, (NetBuffer *) &socket->rxBuffer,
2487  offset, length);
2488  }
2489  else
2490  {
2491  //Copy the first part of the payload
2492  netBufferRead(data, (NetBuffer *) &socket->rxBuffer,
2493  offset, socket->rxBufferSize - offset);
2494 
2495  //Wrap around to the beginning of the circular buffer
2496  netBufferRead(data + socket->rxBufferSize - offset,
2497  (NetBuffer *) &socket->rxBuffer, 0,
2498  length - socket->rxBufferSize + offset);
2499  }
2500 }
2501 
2502 
2503 /**
2504  * @brief Dump TCP header for debugging purpose
2505  * @param[in] segment Pointer to the TCP header
2506  * @param[in] length Length of the segment data
2507  * @param[in] iss Initial send sequence number (needed to compute relative SEQ number)
2508  * @param[in] irs Initial receive sequence number (needed to compute relative ACK number)
2509  **/
2510 
2511 void tcpDumpHeader(const TcpHeader *segment, size_t length, uint32_t iss,
2512  uint32_t irs)
2513 {
2514  //Dump TCP header contents
2515  TRACE_DEBUG("%" PRIu16 " > %" PRIu16 ": %c%c%c%c%c%c seq=%" PRIu32 "(%" PRIu32 ") "
2516  "ack=%" PRIu32 "(%" PRIu32 ") win=%" PRIu16 " len=%" PRIuSIZE "\r\n",
2517  ntohs(segment->srcPort), ntohs(segment->destPort),
2518  (segment->flags & TCP_FLAG_FIN) ? 'F' : '-',
2519  (segment->flags & TCP_FLAG_SYN) ? 'S' : '-',
2520  (segment->flags & TCP_FLAG_RST) ? 'R' : '-',
2521  (segment->flags & TCP_FLAG_PSH) ? 'P' : '-',
2522  (segment->flags & TCP_FLAG_ACK) ? 'A' : '-',
2523  (segment->flags & TCP_FLAG_URG) ? 'U' : '-',
2524  ntohl(segment->seqNum), ntohl(segment->seqNum) - iss,
2525  ntohl(segment->ackNum), ntohl(segment->ackNum) - irs,
2526  ntohs(segment->window), length);
2527 }
2528 
2529 #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:1738
#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:781
@ 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:1587
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
Definition: ip.c:710
Ipv6PseudoHeader ipv6Data
Definition: ip.h:118
int bool_t
Definition: compiler_port.h:61
#define TCP_MAX_HEADER_LENGTH
Definition: tcp.h:256
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:72
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:808
#define TCP_MAX_RTO
Definition: tcp.h:131
uint8_t header[TCP_MAX_HEADER_LENGTH]
Definition: tcp.h:398
#define netMutex
Definition: net_legacy.h:195
#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:1561
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
bool_t tcpIsDuplicateSyn(Socket *socket, const IpPseudoHeader *pseudoHeader, const TcpHeader *segment)
Test whether the incoming SYN segment is a duplicate.
Definition: tcp_misc.c:1116
uint8_t data[]
Definition: ethernet.h:222
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:1672
Ipv6Addr
Definition: ipv6.h:260
@ 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:1323
#define ipv6CompAddr(ipAddr1, ipAddr2)
Definition: ipv6.h:127
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
NetContext netContext
Definition: net.c:75
uint16_t totalLength
Definition: ipv4.h:323
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:298
void tcpUpdateRetransmitQueue(Socket *socket)
Remove acknowledged segments from retransmission queue.
Definition: tcp_misc.c:1450
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
uint32_t netGenerateRand(void)
Generate a random 32-bit value.
Definition: net_misc.c:937
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:1429
#define TCP_MAX_SACK_BLOCKS
Definition: tcp.h:250
@ IPV4_PROTOCOL_TCP
Definition: ipv4.h:253
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:2361
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:2144
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:795
@ 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:1846
#define NetInterface
Definition: net.h:36
error_t tcpCheckAck(Socket *socket, const TcpHeader *segment, size_t length)
Test the ACK field of an incoming segment.
Definition: tcp_misc.c:902
bool_t tcpIsDuplicateAck(Socket *socket, const TcpHeader *segment, size_t length)
Test whether the incoming acknowledgment is a duplicate.
Definition: tcp_misc.c:1192
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:777
@ 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:2175
bool_t tcpComputeRto(Socket *socket)
Compute retransmission timeout.
Definition: tcp_misc.c:1777
error_t tcpReadTxBuffer(Socket *socket, uint32_t seqNum, NetBuffer *buffer, size_t length)
Copy data from the send buffer.
Definition: tcp_misc.c:2397
@ 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:1617
#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
uint8_t flags
Definition: tcp.h:358
#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:1361
#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:2441
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:685
void tcpReadRxBuffer(Socket *socket, uint32_t seqNum, uint8_t *data, size_t length)
Copy data from the receive buffer.
Definition: tcp_misc.c:2476
@ 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:187
@ 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)
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
error_t tcpNagleAlgo(Socket *socket, uint_t flags)
Nagle algorithm implementation.
Definition: tcp_misc.c:2023
#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 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:157
#define netGetSystemTickCount()
Definition: net.h:183
IPv4 (Internet Protocol Version 4)
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:2511
#define MIB2_TCP_INC_COUNTER32(name, value)
Definition: mib2_module.h:178
@ 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:868
uint8_t randSeed[NET_RAND_SEED_SIZE]
Random seed.
Definition: net.h:330
void tcpFlushRetransmitQueue(Socket *socket)
Flush retransmission queue.
Definition: tcp_misc.c:1532
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
uint32_t tcpGenerateInitialSeqNum(const IpAddr *localIpAddr, uint16_t localPort, const IpAddr *remoteIpAddr, uint16_t remotePort)
Initial sequence number generation.
Definition: tcp_misc.c:740
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:1274
void tcpFastRetransmit(Socket *socket)
Fast retransmit procedure.
Definition: tcp_misc.c:1235
#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:2323
@ TCP_FLAG_PSH
Definition: tcp.h:310
systime_t osGetSystemTime(void)
Retrieve system time.
#define TCP_CMP_SEQ(a, b)
Definition: tcp.h:261