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