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