net/tcp: add out-of-order segment support
Signed-off-by: chao an <anchao@xiaomi.com>
This commit is contained in:
parent
0e7d397553
commit
d175f50f01
@ -135,6 +135,22 @@ config NET_TCP_WINDOW_SCALE_FACTOR
|
||||
|
||||
endif # NET_TCP_WINDOW_SCALE
|
||||
|
||||
config NET_TCP_OUT_OF_ORDER
|
||||
bool "Enable TCP/IP Out Of Order segments"
|
||||
default n
|
||||
---help---
|
||||
TCP will queue segments that arrive out of order.
|
||||
|
||||
if NET_TCP_OUT_OF_ORDER
|
||||
|
||||
config NET_TCP_OUT_OF_ORDER_BUFSIZE
|
||||
int "TCP/IP Out Of Order buffer size"
|
||||
default 16384
|
||||
---help---
|
||||
This is the default value for out-of-order buffer size.
|
||||
|
||||
endif # NET_TCP_OUT_OF_ORDER
|
||||
|
||||
config NET_TCP_NOTIFIER
|
||||
bool "Support TCP notifications"
|
||||
default n
|
||||
|
@ -106,6 +106,10 @@
|
||||
|
||||
#define TCP_WSCALE 0x01U /* Window Scale option enabled */
|
||||
|
||||
/* The Max Range count of TCP Selective ACKs */
|
||||
|
||||
#define TCP_SACK_RANGES_MAX 4
|
||||
|
||||
/* After receiving 3 duplicate ACKs, TCP performs a retransmission
|
||||
* (RFC 5681 (3.2))
|
||||
*/
|
||||
@ -144,6 +148,15 @@ struct tcp_poll_s
|
||||
FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
|
||||
};
|
||||
|
||||
/* Out-of-order segments */
|
||||
|
||||
struct tcp_ofoseg_s
|
||||
{
|
||||
uint32_t left; /* Left edge of segment */
|
||||
uint32_t right; /* Right edge of segment */
|
||||
FAR struct iob_s *data; /* Out-of-order buffering */
|
||||
};
|
||||
|
||||
struct tcp_conn_s
|
||||
{
|
||||
/* Common prologue of all connection structures. */
|
||||
@ -251,6 +264,17 @@ struct tcp_conn_s
|
||||
|
||||
struct iob_s *readahead; /* Read-ahead buffering */
|
||||
|
||||
#ifdef CONFIG_NET_TCP_OUT_OF_ORDER
|
||||
|
||||
/* Number of out-of-order segments */
|
||||
|
||||
uint8_t nofosegs;
|
||||
|
||||
/* This defines a out of order segment block. */
|
||||
|
||||
struct tcp_ofoseg_s ofosegs[TCP_SACK_RANGES_MAX];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
/* Write buffering
|
||||
*
|
||||
@ -2100,6 +2124,25 @@ void tcp_sendbuffer_notify(FAR struct tcp_conn_s *conn);
|
||||
|
||||
uint16_t tcpip_hdrsize(FAR struct tcp_conn_s *conn);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_ofoseg_bufsize
|
||||
*
|
||||
* Description:
|
||||
* Calculate the pending size of out-of-order buffer
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The TCP connection of interest
|
||||
*
|
||||
* Returned Value:
|
||||
* Total size of out-of-order buffer
|
||||
*
|
||||
* Assumptions:
|
||||
* This function must be called with the network locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int tcp_ofoseg_bufsize(FAR struct tcp_conn_s *conn);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -94,10 +94,155 @@ tcp_data_event(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
|
||||
return flags;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_ofoseg_data_event
|
||||
*
|
||||
* Description:
|
||||
* Handle out-of-order segment to readahead poll.
|
||||
*
|
||||
* Assumptions:
|
||||
* - This function must be called with the network locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_TCP_OUT_OF_ORDER
|
||||
static uint16_t tcp_ofoseg_data_event(FAR struct net_driver_s *dev,
|
||||
FAR struct tcp_conn_s *conn,
|
||||
uint16_t flags)
|
||||
{
|
||||
FAR struct tcp_ofoseg_s *seg;
|
||||
uint32_t rcvseq;
|
||||
int i = 0;
|
||||
|
||||
/* Assume that we will ACK the data. The data will be ACKed if it is
|
||||
* placed in the read-ahead buffer -OR- if it zero length
|
||||
*/
|
||||
|
||||
flags |= TCP_SNDACK;
|
||||
|
||||
/* Get the receive sequence number */
|
||||
|
||||
rcvseq = tcp_getsequence(conn->rcvseq);
|
||||
|
||||
ninfo("TCP OFOSEG rcvseq [%" PRIu32 "]\n", rcvseq);
|
||||
|
||||
/* Foreach out-of-order segments */
|
||||
|
||||
while (i < conn->nofosegs)
|
||||
{
|
||||
seg = &conn->ofosegs[i];
|
||||
|
||||
/* rcvseq -->|
|
||||
* ofoseg |------|
|
||||
*/
|
||||
|
||||
if (rcvseq == seg->left)
|
||||
{
|
||||
ninfo("TCP OFOSEG input [%" PRIu32 " : %" PRIu32 " : %u]\n",
|
||||
seg->left, seg->right, seg->data->io_pktlen);
|
||||
rcvseq = TCP_SEQ_ADD(rcvseq,
|
||||
seg->data->io_pktlen);
|
||||
net_incr32(conn->rcvseq, seg->data->io_pktlen);
|
||||
tcp_dataconcat(&conn->readahead, &seg->data);
|
||||
}
|
||||
else if (TCP_SEQ_GT(rcvseq, seg->left))
|
||||
{
|
||||
/* rcvseq -->|
|
||||
* ofoseg |------|
|
||||
*/
|
||||
|
||||
if (TCP_SEQ_GTE(rcvseq, seg->right))
|
||||
{
|
||||
/* Remove stale segments */
|
||||
|
||||
iob_free_chain(seg->data);
|
||||
seg->data = NULL;
|
||||
}
|
||||
|
||||
/* rcvseq -->|
|
||||
* ofoseg |------|
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
seg->data =
|
||||
iob_trimhead(seg->data,
|
||||
TCP_SEQ_SUB(rcvseq, seg->left));
|
||||
seg->left = rcvseq;
|
||||
if (seg->data != NULL)
|
||||
{
|
||||
ninfo("TCP OFOSEG input "
|
||||
"[%" PRIu32 " : %" PRIu32 " : %u]\n",
|
||||
seg->left, seg->right, seg->data->io_pktlen);
|
||||
rcvseq = TCP_SEQ_ADD(rcvseq,
|
||||
seg->data->io_pktlen);
|
||||
net_incr32(conn->rcvseq, seg->data->io_pktlen);
|
||||
tcp_dataconcat(&conn->readahead, &seg->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Rebuild out-of-order pool if segment is consumed */
|
||||
|
||||
if (seg->data == NULL)
|
||||
{
|
||||
for (; i < conn->nofosegs - 1; i++)
|
||||
{
|
||||
conn->ofosegs[i] = conn->ofosegs[i + 1];
|
||||
}
|
||||
|
||||
conn->nofosegs--;
|
||||
|
||||
/* Try segments again */
|
||||
|
||||
i = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP_OUT_OF_ORDER */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_ofoseg_bufsize
|
||||
*
|
||||
* Description:
|
||||
* Calculate the pending size of out-of-order buffer
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The TCP connection of interest
|
||||
*
|
||||
* Returned Value:
|
||||
* Total size of out-of-order buffer
|
||||
*
|
||||
* Assumptions:
|
||||
* This function must be called with the network locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_TCP_OUT_OF_ORDER
|
||||
int tcp_ofoseg_bufsize(FAR struct tcp_conn_s *conn)
|
||||
{
|
||||
int total = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < conn->nofosegs; i++)
|
||||
{
|
||||
total += conn->ofosegs[i].data->io_pktlen;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP_OUT_OF_ORDER */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_callback
|
||||
*
|
||||
@ -112,7 +257,7 @@ tcp_data_event(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
|
||||
uint16_t tcp_callback(FAR struct net_driver_s *dev,
|
||||
FAR struct tcp_conn_s *conn, uint16_t flags)
|
||||
{
|
||||
#ifdef CONFIG_NET_TCP_NOTIFIER
|
||||
#if defined(CONFIG_NET_TCP_NOTIFIER) || defined(CONFIG_NET_TCP_OUT_OF_ORDER)
|
||||
uint16_t orig = flags;
|
||||
#endif
|
||||
|
||||
@ -166,6 +311,15 @@ uint16_t tcp_callback(FAR struct net_driver_s *dev,
|
||||
flags = tcp_data_event(dev, conn, flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_TCP_OUT_OF_ORDER
|
||||
if ((orig & TCP_NEWDATA) != 0 && conn->nofosegs > 0)
|
||||
{
|
||||
/* Try out-of-order pool if new data is coming */
|
||||
|
||||
flags = tcp_ofoseg_data_event(dev, conn, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check if there is a connection-related event and a connection
|
||||
* callback.
|
||||
*/
|
||||
|
@ -806,6 +806,22 @@ void tcp_free(FAR struct tcp_conn_s *conn)
|
||||
iob_free_chain(conn->readahead);
|
||||
conn->readahead = NULL;
|
||||
|
||||
#ifdef CONFIG_NET_TCP_OUT_OF_ORDER
|
||||
/* Release any out-of-order buffers */
|
||||
|
||||
if (conn->nofosegs > 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < conn->nofosegs; i++)
|
||||
{
|
||||
iob_free_chain(conn->ofosegs[i].data);
|
||||
}
|
||||
|
||||
conn->nofosegs = 0;
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP_OUT_OF_ORDER */
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
/* Release any write buffers attached to the connection */
|
||||
|
||||
|
@ -257,6 +257,313 @@ static void tcp_snd_wnd_update(FAR struct tcp_conn_s *conn,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_TCP_OUT_OF_ORDER
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_rebuild_ofosegs
|
||||
*
|
||||
* Description:
|
||||
* Re-build out-of-order pool from incoming segment
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The TCP connection of interest
|
||||
* ofoseg - Pointer to incoming out-of-order segment
|
||||
* start - Index of start postion of segment pool
|
||||
*
|
||||
* Returned Value:
|
||||
* True if incoming data has been consumed
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static bool tcp_rebuild_ofosegs(FAR struct tcp_conn_s *conn,
|
||||
FAR struct tcp_ofoseg_s *ofoseg,
|
||||
int start)
|
||||
{
|
||||
struct tcp_ofoseg_s *seg;
|
||||
int i;
|
||||
|
||||
for (i = start; i < conn->nofosegs && ofoseg->data != NULL; i++)
|
||||
{
|
||||
seg = &conn->ofosegs[i];
|
||||
|
||||
/* ofoseg |~~~
|
||||
* segpool |---|
|
||||
*/
|
||||
|
||||
if (TCP_SEQ_GTE(ofoseg->left, seg->left))
|
||||
{
|
||||
/* ofoseg |---|
|
||||
* segpool |---|
|
||||
*/
|
||||
|
||||
if (TCP_SEQ_GT(ofoseg->left, seg->right))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ofoseg |---|
|
||||
* segpool |---|
|
||||
*/
|
||||
|
||||
else if (ofoseg->left == seg->right)
|
||||
{
|
||||
tcp_dataconcat(&seg->data, &ofoseg->data);
|
||||
seg->right = ofoseg->right;
|
||||
}
|
||||
|
||||
/* ofoseg |--|
|
||||
* segpool |---|
|
||||
*/
|
||||
|
||||
else if (TCP_SEQ_LTE(ofoseg->right, seg->right))
|
||||
{
|
||||
iob_free_chain(ofoseg->data);
|
||||
ofoseg->data = NULL;
|
||||
}
|
||||
|
||||
/* ofoseg |---|
|
||||
* segpool |---|
|
||||
*/
|
||||
|
||||
else if (TCP_SEQ_GT(ofoseg->right, seg->right))
|
||||
{
|
||||
ofoseg->data =
|
||||
iob_trimhead(ofoseg->data,
|
||||
TCP_SEQ_SUB(seg->right, ofoseg->left));
|
||||
tcp_dataconcat(&seg->data, &ofoseg->data);
|
||||
seg->right = ofoseg->right;
|
||||
}
|
||||
}
|
||||
|
||||
/* ofoseg |~~~
|
||||
* segpool |---|
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* ofoseg |---|
|
||||
* segpool |---|
|
||||
*/
|
||||
|
||||
if (ofoseg->right == seg->left)
|
||||
{
|
||||
tcp_dataconcat(&ofoseg->data, &seg->data);
|
||||
seg->data = ofoseg->data;
|
||||
seg->left = ofoseg->left;
|
||||
ofoseg->data = NULL;
|
||||
}
|
||||
|
||||
/* ofoseg |---|
|
||||
* segpool |---|
|
||||
*/
|
||||
|
||||
else if (TCP_SEQ_LT(ofoseg->right, seg->left))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ofoseg |---|~|
|
||||
* segpool |--|
|
||||
*/
|
||||
|
||||
else if (TCP_SEQ_GTE(ofoseg->right, seg->right))
|
||||
{
|
||||
iob_free_chain(seg->data);
|
||||
*seg = *ofoseg;
|
||||
ofoseg->data = NULL;
|
||||
}
|
||||
|
||||
/* ofoseg |---|
|
||||
* segpool |---|
|
||||
*/
|
||||
|
||||
else if (TCP_SEQ_GT(ofoseg->right, seg->left))
|
||||
{
|
||||
ofoseg->data =
|
||||
iob_trimtail(ofoseg->data,
|
||||
ofoseg->right - seg->left);
|
||||
tcp_dataconcat(&ofoseg->data, &seg->data);
|
||||
seg->data = ofoseg->data;
|
||||
seg->left = ofoseg->left;
|
||||
ofoseg->data = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (ofoseg->data == NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_reorder_ofosegs
|
||||
*
|
||||
* Description:
|
||||
* Sort out-of-order segments by left edge
|
||||
*
|
||||
* Input Parameters:
|
||||
* nofosegs - Number of out-of-order semgnets
|
||||
* ofosegs - Pointer to out-of-order segments
|
||||
*
|
||||
* Returned Value:
|
||||
* True if re-order occurs
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static bool tcp_reorder_ofosegs(int nofosegs,
|
||||
FAR struct tcp_ofoseg_s *ofosegs)
|
||||
{
|
||||
struct tcp_ofoseg_s segs;
|
||||
bool reordered = false;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
/* Sort out-of-order segments by left edge */
|
||||
|
||||
for (i = 0; i < nofosegs - 1; i++)
|
||||
{
|
||||
for (j = 0; j < nofosegs - 1 - i; j++)
|
||||
{
|
||||
if (TCP_SEQ_GT(ofosegs[j].left,
|
||||
ofosegs[j + 1].left))
|
||||
{
|
||||
segs = ofosegs[j];
|
||||
ofosegs[j] = ofosegs[j + 1];
|
||||
ofosegs[j + 1] = segs;
|
||||
reordered = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return reordered;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_input_ofosegs
|
||||
*
|
||||
* Description:
|
||||
* Handle incoming TCP data to out-of-order pool
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device driver structure containing the received TCP packet.
|
||||
* conn - The TCP connection of interest
|
||||
* iplen - Length of the IP header (IPv4_HDRLEN or IPv6_HDRLEN).
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void tcp_input_ofosegs(FAR struct net_driver_s *dev,
|
||||
FAR struct tcp_conn_s *conn,
|
||||
unsigned int iplen)
|
||||
{
|
||||
struct tcp_ofoseg_s ofoseg;
|
||||
bool rebuild;
|
||||
int i = 0;
|
||||
int len;
|
||||
|
||||
ofoseg.left =
|
||||
tcp_getsequence(((FAR struct tcp_hdr_s *)IPBUF(iplen))->seqno);
|
||||
|
||||
/* Calculate the pending size of out-of-order cache, if the input edge can
|
||||
* not fill the adjacent segments, drop it
|
||||
*/
|
||||
|
||||
if (tcp_ofoseg_bufsize(conn) > CONFIG_NET_TCP_OUT_OF_ORDER_BUFSIZE &&
|
||||
ofoseg.left >= conn->ofosegs[0].left)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get left/right edge from incoming data */
|
||||
|
||||
len = (dev->d_appdata - dev->d_iob->io_data) - dev->d_iob->io_offset;
|
||||
ofoseg.right = TCP_SEQ_ADD(ofoseg.left, dev->d_iob->io_pktlen - len);
|
||||
|
||||
ninfo("TCP OFOSEG out-of-order "
|
||||
"[%" PRIu32 " : %" PRIu32 " : %" PRIu32 "]\n",
|
||||
ofoseg.left, ofoseg.right, TCP_SEQ_SUB(ofoseg.right, ofoseg.left));
|
||||
|
||||
/* Trim l3/l4 header to reserve appdata */
|
||||
|
||||
dev->d_iob = iob_trimhead(dev->d_iob, len);
|
||||
if (dev->d_iob == NULL)
|
||||
{
|
||||
/* No available data, clear device buffer */
|
||||
|
||||
goto clear;
|
||||
}
|
||||
|
||||
ofoseg.data = dev->d_iob;
|
||||
|
||||
/* Build out-of-order pool */
|
||||
|
||||
rebuild = tcp_rebuild_ofosegs(conn, &ofoseg, 0);
|
||||
|
||||
/* Incoming segment out of order from existing pool, add to new segment */
|
||||
|
||||
if (!rebuild && conn->nofosegs != TCP_SACK_RANGES_MAX)
|
||||
{
|
||||
conn->ofosegs[conn->nofosegs] = ofoseg;
|
||||
conn->nofosegs++;
|
||||
rebuild = true;
|
||||
}
|
||||
|
||||
/* Try Re-order ofosegs */
|
||||
|
||||
if (rebuild &&
|
||||
tcp_reorder_ofosegs(conn->nofosegs, (FAR void *)conn->ofosegs))
|
||||
{
|
||||
/* Re-build out-of-order pool after re-order */
|
||||
|
||||
while (i < conn->nofosegs - 1)
|
||||
{
|
||||
if (tcp_rebuild_ofosegs(conn, &conn->ofosegs[i], i + 1))
|
||||
{
|
||||
for (; i < conn->nofosegs - 1; i++)
|
||||
{
|
||||
conn->ofosegs[i] = conn->ofosegs[i + 1];
|
||||
}
|
||||
|
||||
conn->nofosegs--;
|
||||
|
||||
i = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < conn->nofosegs; i++)
|
||||
{
|
||||
ninfo("TCP OFOSEG [%d][%" PRIu32 " : %" PRIu32 " : %" PRIu32 "]\n", i,
|
||||
conn->ofosegs[i].left, conn->ofosegs[i].right,
|
||||
TCP_SEQ_SUB(conn->ofosegs[i].right, conn->ofosegs[i].left));
|
||||
}
|
||||
|
||||
/* Incoming data has been consumed, re-prepare device buffer to send
|
||||
* response.
|
||||
*/
|
||||
|
||||
if (rebuild)
|
||||
{
|
||||
clear:
|
||||
netdev_iob_clear(dev);
|
||||
netdev_iob_prepare(dev, false, 0);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP_OUT_OF_ORDER */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_input
|
||||
*
|
||||
@ -697,8 +1004,11 @@ found:
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We never queue out-of-order segments. */
|
||||
#ifdef CONFIG_NET_TCP_OUT_OF_ORDER
|
||||
/* Queue out-of-order segments. */
|
||||
|
||||
tcp_input_ofosegs(dev, conn, iplen);
|
||||
#endif
|
||||
tcp_send(dev, conn, TCP_ACK, tcpiplen);
|
||||
return;
|
||||
}
|
||||
|
@ -219,6 +219,36 @@ uint32_t tcp_get_recvwindow(FAR struct net_driver_s *dev,
|
||||
|
||||
recvwndo = tcp_calc_rcvsize(conn, recvwndo);
|
||||
|
||||
#ifdef CONFIG_NET_TCP_OUT_OF_ORDER
|
||||
/* Calculate the minimum desired size */
|
||||
|
||||
if (conn->nofosegs > 0)
|
||||
{
|
||||
uint32_t desire = conn->ofosegs[0].left -
|
||||
tcp_getsequence(conn->rcvseq);
|
||||
int bufsize = tcp_ofoseg_bufsize(conn);
|
||||
|
||||
if (desire < tcp_rx_mss(dev))
|
||||
{
|
||||
desire = tcp_rx_mss(dev);
|
||||
}
|
||||
|
||||
if (TCP_SEQ_LT(recvwndo, bufsize))
|
||||
{
|
||||
recvwndo = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
recvwndo -= bufsize;
|
||||
}
|
||||
|
||||
if (recvwndo < desire)
|
||||
{
|
||||
recvwndo = desire;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP_OUT_OF_ORDER */
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
|
||||
recvwndo >>= conn->rcv_scale;
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user