Go to the documentation of this file.
32 #define TRACE_LEVEL TCP_TRACE_LEVEL
51 #if (TCP_SECURE_ISN_SUPPORT == ENABLED)
56 #if (TCP_SUPPORT == ENABLED)
99 segment->reserved1 = 0;
100 segment->dataOffset = 5;
101 segment->flags =
flags;
102 segment->reserved2 = 0;
104 segment->checksum = 0;
105 segment->urgentPointer = 0;
114 #if (TCP_SACK_SUPPORT == ENABLED)
133 if(
socket->sackBlockCount > 0 &&
142 for(i = 0; i <
socket->sackBlockCount; i++)
174 totalLength = segment->dataOffset * 4 +
length;
176 #if (IPV4_SUPPORT == ENABLED)
194 #if (IPV6_SUPPORT == ENABLED)
203 pseudoHeader.
ipv6Data.reserved[0] = 0;
204 pseudoHeader.
ipv6Data.reserved[1] = 0;
205 pseudoHeader.
ipv6Data.reserved[2] = 0;
226 if(
socket->retransmitQueue == NULL)
231 socket->retransmitQueue = queueItem;
236 queueItem =
socket->retransmitQueue;
238 while(queueItem->
next) queueItem = queueItem->
next;
242 queueItem = queueItem->
next;
246 if(queueItem == NULL)
255 queueItem->
next = NULL;
273 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
287 socket->retransmitCount = 0;
291 #if (TCP_KEEP_ALIVE_SUPPORT == ENABLED)
293 if(
socket->keepAliveEnabled)
296 if(
socket->keepAliveProbeCount == 0)
331 ancillary.ttl =
socket->ttl;
333 #if (ETH_VLAN_SUPPORT == ENABLED)
335 ancillary.vlanPcp =
socket->vlanPcp;
336 ancillary.vlanDei =
socket->vlanDei;
339 #if (ETH_VMAN_SUPPORT == ENABLED)
341 ancillary.vmanPcp =
socket->vmanPcp;
342 ancillary.vmanDei =
socket->vmanDei;
448 segment2->srcPort =
htons(segment->destPort);
449 segment2->destPort =
htons(segment->srcPort);
452 segment2->reserved1 = 0;
453 segment2->dataOffset = 5;
454 segment2->flags =
flags;
455 segment2->reserved2 = 0;
456 segment2->window = 0;
457 segment2->checksum = 0;
458 segment2->urgentPointer = 0;
460 #if (IPV4_SUPPORT == ENABLED)
468 pseudoHeader2.
ipv4Data.reserved = 0;
478 #if (IPV6_SUPPORT == ENABLED)
487 pseudoHeader2.
ipv6Data.reserved[0] = 0;
488 pseudoHeader2.
ipv6Data.reserved[1] = 0;
489 pseudoHeader2.
ipv6Data.reserved[2] = 0;
516 TRACE_DEBUG(
"%s: Sending TCP reset segment...\r\n",
562 i = (segment->dataOffset * 4) -
sizeof(
TcpHeader);
574 option = (
TcpOption *) (segment->options + i);
585 segment->dataOffset = (
sizeof(
TcpHeader) + i) / 4;
616 if(segment->dataOffset >= (
sizeof(
TcpHeader) / 4))
628 option = (
TcpOption *) (segment->options + i);
648 if(option->length <
sizeof(
TcpOption) || (i + option->length) >
length)
652 if(option->kind ==
kind)
676 uint16_t localPort,
const IpAddr *remoteIpAddr, uint16_t remotePort)
678 #if (TCP_SECURE_ISN_SUPPORT == ENABLED)
685 md5Update(&md5Context, &localPort,
sizeof(uint16_t));
687 md5Update(&md5Context, &remotePort,
sizeof(uint16_t));
721 if(segment->seqNum ==
socket->rcvNxt)
848 #if (TCP_KEEP_ALIVE_SUPPORT == ENABLED)
850 if(
socket->keepAliveEnabled)
853 socket->keepAliveProbeCount = 0;
884 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
886 n = segment->ackNum -
socket->sndUna;
898 socket->sndUna = segment->ackNum;
907 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
952 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
982 if(ownd <= (3 *
socket->smss))
986 else if(ownd <= (4 *
socket->smss))
996 if(
socket->dupAckCount >= thresh)
1056 queueItem =
socket->synQueue;
1059 while(queueItem != NULL)
1061 #if (IPV4_SUPPORT == ENABLED)
1072 if(queueItem->
srcPort == segment->srcPort)
1081 #if (IPV6_SUPPORT == ENABLED)
1092 if(queueItem->
srcPort == segment->srcPort)
1106 queueItem = queueItem->
next;
1130 if(
socket->retransmitQueue != NULL)
1140 if(segment->ackNum ==
socket->sndUna)
1144 if(segment->window ==
socket->sndWnd)
1166 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1167 uint32_t flightSize;
1205 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1222 TRACE_INFO(
"TCP partial acknowledgment\r\n");
1254 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1269 TRACE_INFO(
"TCP partial acknowledgment\r\n");
1297 leftEdge = segment->seqNum;
1299 rightEdge = segment->seqNum +
length;
1305 offset +=
socket->rcvNxt - leftEdge;
1307 leftEdge =
socket->rcvNxt;
1334 length = rightEdge - leftEdge;
1387 prevQueueItem = NULL;
1388 queueItem =
socket->retransmitQueue;
1391 while(queueItem != NULL)
1415 if(prevQueueItem == NULL)
1422 queueItem =
socket->retransmitQueue;
1427 prevQueueItem->
next = queueItem->
next;
1431 queueItem = prevQueueItem->
next;
1438 socket->retransmitCount = 0;
1444 prevQueueItem = queueItem;
1445 queueItem = queueItem->
next;
1451 if(
socket->retransmitQueue == NULL)
1467 while(queueItem != NULL)
1474 queueItem = nextQueueItem;
1478 socket->retransmitQueue = NULL;
1496 while(queueItem != NULL)
1503 queueItem = nextQueueItem;
1523 while(i < socket->sackBlockCount)
1530 *leftEdge =
MIN(*leftEdge,
socket->sackBlock[i].leftEdge);
1531 *rightEdge =
MAX(*rightEdge,
socket->sackBlock[i].rightEdge);
1538 socket->sackBlockCount--;
1555 socket->sackBlock[0].leftEdge = *leftEdge;
1556 socket->sackBlock[0].rightEdge = *rightEdge;
1561 socket->sackBlockCount++;
1576 if(segment->seqNum ==
socket->sndWl1 && segment->ackNum ==
socket->sndWl2)
1581 if(segment->window >
socket->sndWnd)
1585 socket->sndWnd = segment->window;
1586 socket->sndWl1 = segment->seqNum;
1587 socket->sndWl2 = segment->ackNum;
1598 if(segment->window == 0 &&
socket->sndWnd != 0)
1601 socket->wndProbeCount = 0;
1608 socket->sndWnd = segment->window;
1609 socket->sndWl1 = segment->seqNum;
1610 socket->sndWl2 = segment->ackNum;
1637 TRACE_INFO(
"%s: TCP sending window update...\r\n",
1641 socket->rcvWnd += reduction;
1648 socket->rcvWnd += reduction;
1708 TRACE_DEBUG(
"R=%" PRIu32
", SRTT=%" PRIu32
", RTTVAR=%" PRIu32
", RTO=%" PRIu32
"\r\n",
1745 queueItem =
socket->retransmitQueue;
1748 while(queueItem != NULL)
1802 ancillary.ttl =
socket->ttl;
1804 #if (ETH_VLAN_SUPPORT == ENABLED)
1806 ancillary.vlanPcp =
socket->vlanPcp;
1807 ancillary.vlanDei =
socket->vlanDei;
1810 #if (ETH_VMAN_SUPPORT == ENABLED)
1812 ancillary.vmanPcp =
socket->vmanPcp;
1813 ancillary.vmanDei =
socket->vmanDei;
1818 buffer, offset, &ancillary);
1834 queueItem = queueItem->
next;
1859 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
1869 while(
socket->sndUser > 0)
1873 if((int32_t)
u <= 0)
1998 socket->state = newState;
2103 if(
socket->synQueue != NULL)
2118 if(
socket->interface != NULL)
2121 if(
socket->interface->linkState)
2141 if(
socket->userEvent != NULL)
2164 socket->eventMask = eventMask;
2169 if(
socket->eventFlags == 0)
2183 return socket->eventFlags;
2212 offset,
data,
socket->txBufferSize - offset);
2250 offset,
socket->txBufferSize - offset);
2327 offset,
socket->rxBufferSize - offset);
2349 TRACE_DEBUG(
"%" PRIu16
" > %" PRIu16
": %c%c%c%c%c%c seq=%" PRIu32
"(%" PRIu32
") "
2350 "ack=%" PRIu32
"(%" PRIu32
") win=%" PRIu16
" len=%" PRIuSIZE "\r\n",
2351 ntohs(segment->srcPort),
ntohs(segment->destPort),
2358 ntohl(segment->seqNum),
ntohl(segment->seqNum) - iss,
2359 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.
error_t tcpCheckAck(Socket *socket, TcpHeader *segment, size_t length)
Test the ACK field of an incoming segment.
bool_t netTimerRunning(NetTimer *timer)
Check whether the timer is running.
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.
void tcpProcessSegmentData(Socket *socket, TcpHeader *segment, const NetBuffer *buffer, size_t offset, size_t length)
Process the segment text.
void tcpUpdateSendWindow(Socket *socket, TcpHeader *segment)
Update send window.
void md5Final(Md5Context *context, uint8_t *digest)
Finish the MD5 message digest.
error_t ipSendDatagram(NetInterface *interface, IpPseudoHeader *pseudoHeader, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IP datagram.
error_t tcpSendResetSegment(Socket *socket, uint32_t seqNum)
Send a TCP reset segment.
#define ipv6CompAddr(ipAddr1, ipAddr2)
error_t tcpRejectSegment(NetInterface *interface, IpPseudoHeader *pseudoHeader, 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.
uint32_t netGenerateRand(void)
Generate a random 32-bit value.
void md5Update(Md5Context *context, const void *data, size_t length)
Update the MD5 context with a portion of the message being hashed.
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
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
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_t tcpCheckSyn(Socket *socket, TcpHeader *segment, size_t length)
Check the SYN bit of an incoming segment.
@ ERROR_FAILURE
Generic error code.
__start_packed struct @1 TcpOption
TCP option.
error_t tcpRetransmitSegment(Socket *socket)
TCP segment retransmission.
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
@ SOCKET_EVENT_RX_SHUTDOWN
#define TCP_MIB_INC_COUNTER32(name, value)
@ TCP_CONGEST_STATE_RECOVERY
bool_t tcpIsDuplicateAck(Socket *socket, TcpHeader *segment, size_t length)
Test whether the incoming acknowledgment is a duplicate.
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 tcpCheckSeqNum(Socket *socket, TcpHeader *segment, size_t length)
Test the sequence number of an incoming segment.
void tcpFastLossRecovery(Socket *socket, TcpHeader *segment)
Fast loss recovery procedure.
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(...)
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.
TcpOption * tcpGetOption(TcpHeader *segment, uint8_t kind)
Search the TCP header for a given option.
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.
__start_packed struct @0 TcpHeader
TCP header.
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 netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
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.
#define NET_RAND_SEED_SIZE
#define netGetSystemTickCount()
bool_t tcpIsDuplicateSyn(Socket *socket, IpPseudoHeader *pseudoHeader, TcpHeader *segment)
Test whether the incoming SYN segment is a duplicate.
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
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.
__start_packed struct @0 Ipv6Addr
IPv6 network address.
void tcpFastRecovery(Socket *socket, TcpHeader *segment, uint_t n)
Fast recovery procedure.
void tcpFastRetransmit(Socket *socket)
Fast retransmit procedure.
#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)