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