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;
103 segment->checksum = 0;
104 segment->urgentPointer = 0;
113 #if (TCP_SACK_SUPPORT == ENABLED)
132 if(
socket->sackBlockCount > 0 &&
141 for(i = 0; i <
socket->sackBlockCount; i++)
175 #if (IPV4_SUPPORT == ENABLED)
193 #if (IPV6_SUPPORT == ENABLED)
202 pseudoHeader.
ipv6Data.reserved[0] = 0;
203 pseudoHeader.
ipv6Data.reserved[1] = 0;
204 pseudoHeader.
ipv6Data.reserved[2] = 0;
225 if(
socket->retransmitQueue == NULL)
230 socket->retransmitQueue = queueItem;
235 queueItem =
socket->retransmitQueue;
238 while(queueItem->
next != NULL)
240 queueItem = queueItem->
next;
246 queueItem = queueItem->
next;
250 if(queueItem == NULL)
259 queueItem->
next = NULL;
278 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
292 socket->retransmitCount = 0;
296 #if (TCP_KEEP_ALIVE_SUPPORT == ENABLED)
298 if(
socket->keepAliveEnabled)
301 if(
socket->keepAliveProbeCount == 0)
336 ancillary.ttl =
socket->ttl;
338 ancillary.tos =
socket->tos;
340 #if (ETH_VLAN_SUPPORT == ENABLED)
342 ancillary.vlanPcp =
socket->vlanPcp;
343 ancillary.vlanDei =
socket->vlanDei;
346 #if (ETH_VMAN_SUPPORT == ENABLED)
348 ancillary.vmanPcp =
socket->vmanPcp;
349 ancillary.vmanDei =
socket->vmanDei;
456 segment2->srcPort =
htons(segment->destPort);
457 segment2->destPort =
htons(segment->srcPort);
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;
468 #if (IPV4_SUPPORT == ENABLED)
476 pseudoHeader2.
ipv4Data.reserved = 0;
486 #if (IPV6_SUPPORT == ENABLED)
495 pseudoHeader2.
ipv6Data.reserved[0] = 0;
496 pseudoHeader2.
ipv6Data.reserved[1] = 0;
497 pseudoHeader2.
ipv6Data.reserved[2] = 0;
524 TRACE_DEBUG(
"%s: Sending TCP reset segment...\r\n",
570 i = (segment->dataOffset * 4) -
sizeof(
TcpHeader);
582 option = (
TcpOption *) (segment->options + i);
593 segment->dataOffset = (
sizeof(
TcpHeader) + i) / 4;
624 if(segment->dataOffset >= (
sizeof(
TcpHeader) / 4))
636 option = (
TcpOption *) (segment->options + i);
656 if(option->length <
sizeof(
TcpOption) || (i + option->length) >
length)
660 if(option->kind == kind)
684 uint16_t localPort,
const IpAddr *remoteIpAddr, uint16_t remotePort)
686 #if (TCP_SECURE_ISN_SUPPORT == ENABLED)
693 md5Update(&md5Context, &localPort,
sizeof(uint16_t));
695 md5Update(&md5Context, &remotePort,
sizeof(uint16_t));
729 if(segment->seqNum ==
socket->rcvNxt)
848 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
858 #if (TCP_KEEP_ALIVE_SUPPORT == ENABLED)
860 if(
socket->keepAliveEnabled)
863 socket->keepAliveProbeCount = 0;
887 (void) duplicateFlag;
895 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
897 n = segment->ackNum -
socket->sndUna;
909 socket->sndUna = segment->ackNum;
919 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
964 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
994 if(ownd <= (3 *
socket->smss))
998 else if(ownd <= (4 *
socket->smss))
1008 if(
socket->dupAckCount >= thresh)
1068 queueItem =
socket->synQueue;
1071 while(queueItem != NULL)
1073 #if (IPV4_SUPPORT == ENABLED)
1084 if(queueItem->
srcPort == segment->srcPort)
1093 #if (IPV6_SUPPORT == ENABLED)
1104 if(queueItem->
srcPort == segment->srcPort)
1118 queueItem = queueItem->
next;
1143 if(
socket->retransmitQueue != NULL)
1153 if(segment->ackNum ==
socket->sndUna)
1157 if(segment->window ==
socket->sndWnd)
1179 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1180 uint32_t flightSize;
1218 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1235 TRACE_INFO(
"TCP partial acknowledgment\r\n");
1267 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1282 TRACE_INFO(
"TCP partial acknowledgment\r\n");
1310 leftEdge = segment->seqNum;
1312 rightEdge = segment->seqNum +
length;
1318 offset +=
socket->rcvNxt - leftEdge;
1320 leftEdge =
socket->rcvNxt;
1347 length = rightEdge - leftEdge;
1400 prevQueueItem = NULL;
1401 queueItem =
socket->retransmitQueue;
1404 while(queueItem != NULL)
1428 if(prevQueueItem == NULL)
1435 queueItem =
socket->retransmitQueue;
1440 prevQueueItem->
next = queueItem->
next;
1444 queueItem = prevQueueItem->
next;
1451 socket->retransmitCount = 0;
1457 prevQueueItem = queueItem;
1458 queueItem = queueItem->
next;
1464 if(
socket->retransmitQueue == NULL)
1480 while(queueItem != NULL)
1487 queueItem = nextQueueItem;
1491 socket->retransmitQueue = NULL;
1509 while(queueItem != NULL)
1516 queueItem = nextQueueItem;
1536 while(i < socket->sackBlockCount)
1543 *leftEdge =
MIN(*leftEdge,
socket->sackBlock[i].leftEdge);
1544 *rightEdge =
MAX(*rightEdge,
socket->sackBlock[i].rightEdge);
1551 socket->sackBlockCount--;
1568 socket->sackBlock[0].leftEdge = *leftEdge;
1569 socket->sackBlock[0].rightEdge = *rightEdge;
1574 socket->sackBlockCount++;
1589 if(segment->seqNum ==
socket->sndWl1 && segment->ackNum ==
socket->sndWl2)
1594 if(segment->window >
socket->sndWnd)
1598 socket->sndWnd = segment->window;
1599 socket->sndWl1 = segment->seqNum;
1600 socket->sndWl2 = segment->ackNum;
1611 if(segment->window == 0 &&
socket->sndWnd != 0)
1614 socket->wndProbeCount = 0;
1621 socket->sndWnd = segment->window;
1622 socket->sndWl1 = segment->seqNum;
1623 socket->sndWl2 = segment->ackNum;
1650 TRACE_INFO(
"%s: TCP sending window update...\r\n",
1654 socket->rcvWnd += reduction;
1663 socket->rcvWnd += reduction;
1723 TRACE_DEBUG(
"R=%" PRIu32
", SRTT=%" PRIu32
", RTTVAR=%" PRIu32
", RTO=%" PRIu32
"\r\n",
1760 queueItem =
socket->retransmitQueue;
1763 while(queueItem != NULL)
1802 segment->checksum = 0;
1814 #if (IPV4_SUPPORT == ENABLED)
1821 buffer, offset, segment->dataOffset * 4 + queueItem->
length);
1825 #if (IPV6_SUPPORT == ENABLED)
1832 buffer, offset, segment->dataOffset * 4 + queueItem->
length);
1853 ancillary.ttl =
socket->ttl;
1855 #if (ETH_VLAN_SUPPORT == ENABLED)
1857 ancillary.vlanPcp =
socket->vlanPcp;
1858 ancillary.vlanDei =
socket->vlanDei;
1861 #if (ETH_VMAN_SUPPORT == ENABLED)
1863 ancillary.vmanPcp =
socket->vmanPcp;
1864 ancillary.vmanDei =
socket->vmanDei;
1869 buffer, offset, &ancillary);
1885 queueItem = queueItem->
next;
1913 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1923 while(
socket->sndUser > 0 && !error)
1927 if((int32_t)
u <= 0)
2041 socket->state = newState;
2146 if(
socket->synQueue != NULL)
2161 if(
socket->interface != NULL)
2164 if(
socket->interface->linkState)
2184 if(
socket->userEvent != NULL)
2207 socket->eventMask = eventMask;
2212 if(
socket->eventFlags == 0)
2226 return socket->eventFlags;
2255 offset,
data,
socket->txBufferSize - offset);
2293 offset,
socket->txBufferSize - offset);
2370 offset,
socket->rxBufferSize - offset);
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),
2401 ntohl(segment->seqNum),
ntohl(segment->seqNum) - iss,
2402 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.
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.
void tcpFastRecovery(Socket *socket, const TcpHeader *segment, uint_t n)
Fast recovery procedure.
uint8_t header[TCP_MAX_HEADER_LENGTH]
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.
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.
const TcpOption * tcpGetOption(const TcpHeader *segment, uint8_t kind)
Search the TCP header for a given option.
uint32_t netGenerateRand(void)
Generate a random 32-bit value.
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)
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
error_t tcpNagleAlgo(Socket *socket, uint_t flags)
Nagle algorithm implementation.
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 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.
uint8_t randSeed[NET_RAND_SEED_SIZE]
Random seed.
void tcpFlushRetransmitQueue(Socket *socket)
Flush retransmission queue.
#define TCP_FAST_RETRANSMIT_THRES
uint32_t tcpGenerateInitialSeqNum(const IpAddr *localIpAddr, uint16_t localPort, const IpAddr *remoteIpAddr, uint16_t remotePort)
Initial sequence number generation.
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 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)