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