Go to the documentation of this file.
32 #define TRACE_LEVEL TCP_TRACE_LEVEL
49 #if (TCP_SECURE_ISN_SUPPORT == ENABLED)
54 #if (TCP_SUPPORT == ENABLED)
98 segment->reserved1 = 0;
99 segment->dataOffset =
sizeof(
TcpHeader) / 4;
100 segment->flags =
flags;
101 segment->reserved2 = 0;
102 segment->checksum = 0;
103 segment->urgentPointer = 0;
113 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
123 &
socket->rcvWndShift,
sizeof(uint8_t));
129 if(
socket->wndScaleOptionReceived)
132 &
socket->rcvWndShift,
sizeof(uint8_t));
143 if(
socket->wndScaleOptionReceived)
163 #if (TCP_SACK_SUPPORT == ENABLED)
182 if(
socket->sackBlockCount > 0 &&
191 for(i = 0; i <
socket->sackBlockCount; i++)
225 #if (IPV4_SUPPORT == ENABLED)
243 #if (IPV6_SUPPORT == ENABLED)
252 pseudoHeader.
ipv6Data.reserved[0] = 0;
253 pseudoHeader.
ipv6Data.reserved[1] = 0;
254 pseudoHeader.
ipv6Data.reserved[2] = 0;
275 if(
socket->retransmitQueue == NULL)
280 socket->retransmitQueue = queueItem;
285 queueItem =
socket->retransmitQueue;
288 while(queueItem->
next != NULL)
290 queueItem = queueItem->
next;
296 queueItem = queueItem->
next;
300 if(queueItem == NULL)
309 queueItem->
next = NULL;
328 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
342 socket->retransmitCount = 0;
346 #if (TCP_KEEP_ALIVE_SUPPORT == ENABLED)
348 if(
socket->keepAliveEnabled)
351 if(
socket->keepAliveProbeCount == 0)
386 ancillary.ttl =
socket->ttl;
388 ancillary.tos =
socket->tos;
390 #if (ETH_VLAN_SUPPORT == ENABLED)
392 ancillary.vlanPcp =
socket->vlanPcp;
393 ancillary.vlanDei =
socket->vlanDei;
396 #if (ETH_VMAN_SUPPORT == ENABLED)
398 ancillary.vmanPcp =
socket->vmanPcp;
399 ancillary.vmanDei =
socket->vmanDei;
506 segment2->srcPort =
htons(segment->destPort);
507 segment2->destPort =
htons(segment->srcPort);
510 segment2->reserved1 = 0;
511 segment2->dataOffset = 5;
512 segment2->flags =
flags;
513 segment2->reserved2 = 0;
514 segment2->window = 0;
515 segment2->checksum = 0;
516 segment2->urgentPointer = 0;
518 #if (IPV4_SUPPORT == ENABLED)
526 pseudoHeader2.
ipv4Data.reserved = 0;
536 #if (IPV6_SUPPORT == ENABLED)
545 pseudoHeader2.
ipv6Data.reserved[0] = 0;
546 pseudoHeader2.
ipv6Data.reserved[1] = 0;
547 pseudoHeader2.
ipv6Data.reserved[2] = 0;
574 TRACE_DEBUG(
"%s: Sending TCP reset segment...\r\n",
620 i = (segment->dataOffset * 4) -
sizeof(
TcpHeader);
632 option = (
TcpOption *) (segment->options + i);
643 segment->dataOffset = (
sizeof(
TcpHeader) + i) / 4;
674 if(segment->dataOffset >= (
sizeof(
TcpHeader) / 4))
686 option = (
TcpOption *) (segment->options + i);
709 (i + option->length) >
length)
715 if(option->kind == kind)
739 #if (TCP_SECURE_ISN_SUPPORT == ENABLED)
783 if(segment->seqNum ==
socket->rcvNxt)
902 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
912 #if (TCP_KEEP_ALIVE_SUPPORT == ENABLED)
914 if(
socket->keepAliveEnabled)
917 socket->keepAliveProbeCount = 0;
941 (void) duplicateFlag;
949 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
951 n = segment->ackNum -
socket->sndUna;
963 socket->sndUna = segment->ackNum;
973 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1018 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1048 if(ownd <= ((uint32_t)
socket->smss * 3))
1052 else if(ownd <= ((uint32_t)
socket->smss * 4))
1062 if(
socket->dupAckCount >= thresh)
1122 queueItem =
socket->synQueue;
1125 while(queueItem != NULL)
1127 #if (IPV4_SUPPORT == ENABLED)
1138 if(queueItem->
srcPort == segment->srcPort)
1147 #if (IPV6_SUPPORT == ENABLED)
1158 if(queueItem->
srcPort == segment->srcPort)
1172 queueItem = queueItem->
next;
1197 if(
socket->retransmitQueue != NULL)
1207 if(segment->ackNum ==
socket->sndUna)
1211 if(segment->window ==
socket->sndWnd)
1233 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1234 uint32_t flightSize;
1272 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1289 TRACE_INFO(
"TCP partial acknowledgment\r\n");
1321 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1336 TRACE_INFO(
"TCP partial acknowledgment\r\n");
1364 leftEdge = segment->seqNum;
1366 rightEdge = segment->seqNum +
length;
1372 offset +=
socket->rcvNxt - leftEdge;
1374 leftEdge =
socket->rcvNxt;
1401 length = rightEdge - leftEdge;
1454 prevQueueItem = NULL;
1455 queueItem =
socket->retransmitQueue;
1458 while(queueItem != NULL)
1482 if(prevQueueItem == NULL)
1489 queueItem =
socket->retransmitQueue;
1494 prevQueueItem->
next = queueItem->
next;
1498 queueItem = prevQueueItem->
next;
1505 socket->retransmitCount = 0;
1511 prevQueueItem = queueItem;
1512 queueItem = queueItem->
next;
1518 if(
socket->retransmitQueue == NULL)
1534 while(queueItem != NULL)
1541 queueItem = nextQueueItem;
1545 socket->retransmitQueue = NULL;
1563 while(queueItem != NULL)
1570 queueItem = nextQueueItem;
1585 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
1595 for(
n = 0;
window > UINT16_MAX;
n++)
1618 while(i < socket->sackBlockCount)
1625 *leftEdge =
MIN(*leftEdge,
socket->sackBlock[i].leftEdge);
1626 *rightEdge =
MAX(*rightEdge,
socket->sackBlock[i].rightEdge);
1633 socket->sackBlockCount--;
1650 socket->sackBlock[0].leftEdge = *leftEdge;
1651 socket->sackBlock[0].rightEdge = *rightEdge;
1656 socket->sackBlockCount++;
1672 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
1676 window = (uint32_t) segment->window <<
socket->sndWndShift;
1679 window = segment->window;
1683 if(segment->seqNum ==
socket->sndWl1 && segment->ackNum ==
socket->sndWl2)
1693 socket->sndWl1 = segment->seqNum;
1694 socket->sndWl2 = segment->ackNum;
1708 socket->wndProbeCount = 0;
1716 socket->sndWl1 = segment->seqNum;
1717 socket->sndWl2 = segment->ackNum;
1748 TRACE_INFO(
"%s: TCP sending window update...\r\n",
1752 socket->rcvWnd += reduction;
1761 socket->rcvWnd += reduction;
1821 TRACE_DEBUG(
"R=%" PRIu32
", SRTT=%" PRIu32
", RTTVAR=%" PRIu32
", RTO=%" PRIu32
"\r\n",
1858 queueItem =
socket->retransmitQueue;
1861 while(queueItem != NULL)
1898 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
1902 socket->wndScaleOptionReceived)
1921 segment->checksum = 0;
1933 #if (IPV4_SUPPORT == ENABLED)
1940 buffer, offset, segment->dataOffset * 4 + queueItem->
length);
1944 #if (IPV6_SUPPORT == ENABLED)
1951 buffer, offset, segment->dataOffset * 4 + queueItem->
length);
1972 ancillary.ttl =
socket->ttl;
1974 #if (ETH_VLAN_SUPPORT == ENABLED)
1976 ancillary.vlanPcp =
socket->vlanPcp;
1977 ancillary.vlanDei =
socket->vlanDei;
1980 #if (ETH_VMAN_SUPPORT == ENABLED)
1982 ancillary.vmanPcp =
socket->vmanPcp;
1983 ancillary.vmanDei =
socket->vmanDei;
1988 buffer, offset, &ancillary);
2004 queueItem = queueItem->
next;
2032 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
2042 while(
socket->sndUser > 0 && !error)
2046 if((int32_t)
u <= 0)
2160 socket->state = newState;
2265 if(
socket->synQueue != NULL)
2280 if(
socket->interface != NULL)
2283 if(
socket->interface->linkState)
2303 if(
socket->userEvent != NULL)
2326 socket->eventMask = eventMask;
2331 if(
socket->eventFlags == 0)
2345 return socket->eventFlags;
2374 offset,
data,
socket->txBufferSize - offset);
2412 offset,
socket->txBufferSize - offset);
2489 offset,
socket->rxBufferSize - offset);
2511 TRACE_DEBUG(
"%" PRIu16
" > %" PRIu16
": %c%c%c%c%c%c seq=%" PRIu32
"(%" PRIu32
") "
2512 "ack=%" PRIu32
"(%" PRIu32
") win=%" PRIu16
" len=%" PRIuSIZE "\r\n",
2513 ntohs(segment->srcPort),
ntohs(segment->destPort),
2520 ntohl(segment->seqNum),
ntohl(segment->seqNum) - iss,
2521 ntohl(segment->ackNum),
ntohl(segment->ackNum) - irs,
void tcpUpdateReceiveWindow(Socket *socket)
Update receive window so as to avoid Silly Window Syndrome.
IPv6 (Internet Protocol Version 6)
Retransmission queue item.
Date and time management.
void netStartTimer(NetTimer *timer, systime_t interval)
Start timer.
void netUnlock(NetContext *context)
Release exclusive access to the core of the TCP/IP stack.
void tcpComputeWindowScaleFactor(Socket *socket)
Compute the window scale factor to use for the receive window.
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
#define TCP_MAX_HEADER_LENGTH
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
void memPoolFree(void *p)
Release a memory block.
bool_t netTimerRunning(NetTimer *timer)
Check whether the timer is running.
uint8_t header[TCP_MAX_HEADER_LENGTH]
uint32_t tcpGenerateInitialSeqNum(Socket *socket)
Initial sequence number generation.
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
void tcpFlushSynQueue(Socket *socket)
Flush SYN queue.
Structure describing a buffer that spans multiple chunks.
uint32_t netGenerateRand(NetContext *context)
Generate a random 32-bit value.
bool_t tcpIsDuplicateSyn(Socket *socket, const IpPseudoHeader *pseudoHeader, const TcpHeader *segment)
Test whether the incoming SYN segment is a duplicate.
error_t ipSendDatagram(NetInterface *interface, const IpPseudoHeader *pseudoHeader, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IP datagram.
void md5Final(Md5Context *context, uint8_t *digest)
Finish the MD5 message digest.
void tcpUpdateSendWindow(Socket *socket, const TcpHeader *segment)
Update send window.
error_t tcpSendResetSegment(Socket *socket, uint32_t seqNum)
Send a TCP reset segment.
void tcpFastLossRecovery(Socket *socket, const TcpHeader *segment)
Fast loss recovery procedure.
#define ipv6CompAddr(ipAddr1, ipAddr2)
error_t tcpRejectSegment(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const TcpHeader *segment, size_t length)
Send a TCP reset in response to an invalid segment.
void * memPoolAlloc(size_t size)
Allocate a memory block.
struct _TcpSynQueueItem * next
const char_t * formatSystemTime(systime_t time, char_t *str)
Format system time.
uint32_t Ipv4Addr
IPv4 network address.
void tcpUpdateRetransmitQueue(Socket *socket)
Remove acknowledged segments from retransmission queue.
@ TCP_OPTION_WINDOW_SCALE_FACTOR
const TcpOption * tcpGetOption(const TcpHeader *segment, uint8_t kind)
Search the TCP header for a given option.
error_t netBufferConcat(NetBuffer *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Concatenate two multi-part buffers.
void md5Init(Md5Context *context)
Initialize MD5 message digest context.
void tcpDeleteControlBlock(Socket *socket)
Delete TCB structure.
#define TCP_MAX_SACK_BLOCKS
void tcpWriteTxBuffer(Socket *socket, uint32_t seqNum, const uint8_t *data, size_t length)
Copy incoming data to the send buffer.
Helper functions for TCP.
@ TCP_OPTION_SACK_PERMITTED
void tcpChangeState(Socket *socket, TcpState newState)
Update TCP FSM current state.
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
#define osMemcpy(dest, src, length)
struct _TcpQueueItem * next
void netStopTimer(NetTimer *timer)
Stop timer.
@ TCP_CONGEST_STATE_LOSS_RECOVERY
int_t socket(int_t family, int_t type, int_t protocol)
Create a socket that is bound to a specific transport service provider.
@ ERROR_FAILURE
Generic error code.
error_t tcpRetransmitSegment(Socket *socket)
TCP segment retransmission.
error_t tcpCheckAck(Socket *socket, const TcpHeader *segment, size_t length)
Test the ACK field of an incoming segment.
bool_t tcpIsDuplicateAck(Socket *socket, const TcpHeader *segment, size_t length)
Test whether the incoming acknowledgment is a duplicate.
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
error_t tcpCheckSeqNum(Socket *socket, const TcpHeader *segment, size_t length)
Test the sequence number of an incoming segment.
@ SOCKET_EVENT_RX_SHUTDOWN
#define TCP_MIB_INC_COUNTER32(name, value)
@ TCP_CONGEST_STATE_RECOVERY
void tcpUpdateEvents(Socket *socket)
Update TCP related events.
bool_t tcpComputeRto(Socket *socket)
Compute retransmission timeout.
error_t tcpReadTxBuffer(Socket *socket, uint32_t seqNum, NetBuffer *buffer, size_t length)
Copy data from the send buffer.
error_t netBufferCopy(NetBuffer *dest, size_t destOffset, const NetBuffer *src, size_t srcOffset, size_t length)
Copy data between multi-part buffers.
void tcpUpdateSackBlocks(Socket *socket, uint32_t *leftEdge, uint32_t *rightEdge)
Update the list of non-contiguous blocks that have been received.
error_t tcpAddOption(TcpHeader *segment, uint8_t kind, const void *value, uint8_t length)
Append an option to the TCP header.
uint32_t systime_t
System time.
#define TRACE_WARNING(...)
void tcpProcessSegmentData(Socket *socket, const TcpHeader *segment, const NetBuffer *buffer, size_t offset, size_t length)
Process the segment text.
IpPseudoHeader pseudoHeader
void tcpWriteRxBuffer(Socket *socket, uint32_t seqNum, const NetBuffer *data, size_t dataOffset, size_t length)
Copy incoming data to the receive buffer.
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.
void tcpReadRxBuffer(Socket *socket, uint32_t seqNum, uint8_t *data, size_t length)
Copy data from the receive buffer.
IPv4 and IPv6 common routines.
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
TCP (Transmission Control Protocol)
@ SOCKET_EVENT_TX_SHUTDOWN
#define TCP_MIB_INC_COUNTER64(name, value)
MD5 (Message-Digest Algorithm)
error_t tcpNagleAlgo(Socket *socket, uint_t flags)
Nagle algorithm implementation.
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
#define TCP_DEFAULT_PROBE_INTERVAL
size_t netBufferWrite(NetBuffer *dest, size_t destOffset, const void *src, size_t length)
Write data to a multi-part buffer.
void netLock(NetContext *context)
Get exclusive access to the core of the TCP/IP stack.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
#define NET_RAND_SEED_SIZE
#define netGetSystemTickCount()
IPv4 (Internet Protocol Version 4)
void tcpDumpHeader(const TcpHeader *segment, size_t length, uint32_t iss, uint32_t irs)
Dump TCP header for debugging purpose.
#define MIB2_TCP_INC_COUNTER32(name, value)
@ TCP_OPTION_MAX_SEGMENT_SIZE
error_t tcpCheckSyn(Socket *socket, const TcpHeader *segment, size_t length)
Check the SYN bit of an incoming segment.
void tcpFlushRetransmitQueue(Socket *socket)
Flush retransmission queue.
#define TCP_FAST_RETRANSMIT_THRES
error_t tcpSendSegment(Socket *socket, uint8_t flags, uint32_t seqNum, uint32_t ackNum, size_t length, bool_t addToQueue)
Send a TCP segment.
void tcpFastRecovery(Socket *socket, const TcpHeader *segment, uint32_t n)
Fast recovery procedure.
void tcpFastRetransmit(Socket *socket)
Fast retransmit procedure.
void md5Update(Md5Context *context, const void *data, size_t length)
Update the MD5 context with a portion of the message being hashed.
#define osMemmove(dest, src, length)
uint_t tcpWaitForEvents(Socket *socket, uint_t eventMask, systime_t timeout)
Wait for a particular TCP event.
systime_t osGetSystemTime(void)
Retrieve system time.
#define TCP_CMP_SEQ(a, b)