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