tcp_send_buffered.c: Fix snd_wnd
snd_wnd is an offset from the acked sequence number.
This commit is contained in:
parent
1b82f1c749
commit
42f1851ca6
@ -781,6 +781,8 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
{
|
{
|
||||||
FAR struct tcp_wrbuffer_s *wrb;
|
FAR struct tcp_wrbuffer_s *wrb;
|
||||||
uint32_t predicted_seqno;
|
uint32_t predicted_seqno;
|
||||||
|
uint32_t seq;
|
||||||
|
uint32_t snd_wnd_edge;
|
||||||
size_t sndlen;
|
size_t sndlen;
|
||||||
|
|
||||||
/* Peek at the head of the write queue (but don't remove anything
|
/* Peek at the head of the write queue (but don't remove anything
|
||||||
@ -791,28 +793,6 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q);
|
wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q);
|
||||||
DEBUGASSERT(wrb);
|
DEBUGASSERT(wrb);
|
||||||
|
|
||||||
/* Get the amount of data that we can send in the next packet.
|
|
||||||
* We will send either the remaining data in the buffer I/O
|
|
||||||
* buffer chain, or as much as will fit given the MSS and current
|
|
||||||
* window size.
|
|
||||||
*/
|
|
||||||
|
|
||||||
sndlen = TCP_WBPKTLEN(wrb) - TCP_WBSENT(wrb);
|
|
||||||
if (sndlen > conn->mss)
|
|
||||||
{
|
|
||||||
sndlen = conn->mss;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sndlen > conn->snd_wnd)
|
|
||||||
{
|
|
||||||
sndlen = conn->snd_wnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
ninfo("SEND: wrb=%p pktlen=%u sent=%u sndlen=%zu mss=%u "
|
|
||||||
"snd_wnd=%u\n",
|
|
||||||
wrb, TCP_WBPKTLEN(wrb), TCP_WBSENT(wrb), sndlen, conn->mss,
|
|
||||||
conn->snd_wnd);
|
|
||||||
|
|
||||||
/* Set the sequence number for this segment. If we are
|
/* Set the sequence number for this segment. If we are
|
||||||
* retransmitting, then the sequence number will already
|
* retransmitting, then the sequence number will already
|
||||||
* be set for this write buffer.
|
* be set for this write buffer.
|
||||||
@ -823,88 +803,121 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
TCP_WBSEQNO(wrb) = conn->isn + conn->sent;
|
TCP_WBSEQNO(wrb) = conn->isn + conn->sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The TCP stack updates sndseq on receipt of ACK *before*
|
/* Get the amount of data that we can send in the next packet.
|
||||||
* this function is called. In that case sndseq will point
|
* We will send either the remaining data in the buffer I/O
|
||||||
* to the next unacknowledged byte (which might have already
|
* buffer chain, or as much as will fit given the MSS and current
|
||||||
* been sent). We will overwrite the value of sndseq here
|
* window size.
|
||||||
* before the packet is sent.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
tcp_setsequence(conn->sndseq, TCP_WBSEQNO(wrb) + TCP_WBSENT(wrb));
|
seq = TCP_WBSEQNO(wrb) + TCP_WBSENT(wrb);
|
||||||
|
snd_wnd_edge = conn->snd_wl2 + conn->snd_wnd;
|
||||||
#ifdef NEED_IPDOMAIN_SUPPORT
|
if (TCP_SEQ_LT(seq, snd_wnd_edge))
|
||||||
/* If both IPv4 and IPv6 support are enabled, then we will need to
|
|
||||||
* select which one to use when generating the outgoing packet.
|
|
||||||
* If only one domain is selected, then the setup is already in
|
|
||||||
* place and we need do nothing.
|
|
||||||
*/
|
|
||||||
|
|
||||||
send_ipselect(dev, conn);
|
|
||||||
#endif
|
|
||||||
/* Then set-up to send that amount of data with the offset
|
|
||||||
* corresponding to the amount of data already sent. (this
|
|
||||||
* won't actually happen until the polling cycle completes).
|
|
||||||
*/
|
|
||||||
|
|
||||||
devif_iob_send(dev, TCP_WBIOB(wrb), sndlen, TCP_WBSENT(wrb));
|
|
||||||
|
|
||||||
/* Remember how much data we send out now so that we know
|
|
||||||
* when everything has been acknowledged. Just increment
|
|
||||||
* the amount of data sent. This will be needed in sequence
|
|
||||||
* number calculations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
conn->tx_unacked += sndlen;
|
|
||||||
conn->sent += sndlen;
|
|
||||||
|
|
||||||
/* Below prediction will become true,
|
|
||||||
* unless retransmission occurrence
|
|
||||||
*/
|
|
||||||
|
|
||||||
predicted_seqno = tcp_getsequence(conn->sndseq) + sndlen;
|
|
||||||
|
|
||||||
if (TCP_SEQ_GT(predicted_seqno, conn->sndseq_max))
|
|
||||||
{
|
{
|
||||||
conn->sndseq_max = predicted_seqno;
|
uint32_t remaining_snd_wnd;
|
||||||
}
|
|
||||||
|
|
||||||
ninfo("SEND: wrb=%p nrtx=%u tx_unacked=%" PRIu32 " sent=%" PRIu32 "\n",
|
sndlen = TCP_WBPKTLEN(wrb) - TCP_WBSENT(wrb);
|
||||||
wrb, TCP_WBNRTX(wrb), conn->tx_unacked, conn->sent);
|
if (sndlen > conn->mss)
|
||||||
|
{
|
||||||
|
sndlen = conn->mss;
|
||||||
|
}
|
||||||
|
|
||||||
/* Increment the count of bytes sent from this write buffer */
|
remaining_snd_wnd = TCP_SEQ_SUB(snd_wnd_edge, seq);
|
||||||
|
if (sndlen > remaining_snd_wnd)
|
||||||
|
{
|
||||||
|
sndlen = remaining_snd_wnd;
|
||||||
|
}
|
||||||
|
|
||||||
TCP_WBSENT(wrb) += sndlen;
|
ninfo("SEND: wrb=%p seq=%" PRIu32 " pktlen=%u sent=%u sndlen=%zu "
|
||||||
|
"mss=%u snd_wnd=%u seq=%" PRIu32
|
||||||
|
" remaining_snd_wnd=%" PRIu32 "\n",
|
||||||
|
wrb, TCP_WBSEQNO(wrb), TCP_WBPKTLEN(wrb), TCP_WBSENT(wrb),
|
||||||
|
sndlen, conn->mss,
|
||||||
|
conn->snd_wnd, seq, remaining_snd_wnd);
|
||||||
|
|
||||||
ninfo("SEND: wrb=%p sent=%u pktlen=%u\n",
|
/* The TCP stack updates sndseq on receipt of ACK *before*
|
||||||
wrb, TCP_WBSENT(wrb), TCP_WBPKTLEN(wrb));
|
* this function is called. In that case sndseq will point
|
||||||
|
* to the next unacknowledged byte (which might have already
|
||||||
/* Remove the write buffer from the write queue if the
|
* been sent). We will overwrite the value of sndseq here
|
||||||
* last of the data has been sent from the buffer.
|
* before the packet is sent.
|
||||||
*/
|
|
||||||
|
|
||||||
DEBUGASSERT(TCP_WBSENT(wrb) <= TCP_WBPKTLEN(wrb));
|
|
||||||
if (TCP_WBSENT(wrb) >= TCP_WBPKTLEN(wrb))
|
|
||||||
{
|
|
||||||
FAR struct tcp_wrbuffer_s *tmp;
|
|
||||||
|
|
||||||
ninfo("SEND: wrb=%p Move to unacked_q\n", wrb);
|
|
||||||
|
|
||||||
tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q);
|
|
||||||
DEBUGASSERT(tmp == wrb);
|
|
||||||
UNUSED(tmp);
|
|
||||||
|
|
||||||
/* Put the I/O buffer chain in the un-acked queue; the
|
|
||||||
* segment is waiting for ACK again
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
psock_insert_segment(wrb, &conn->unacked_q);
|
tcp_setsequence(conn->sndseq, TCP_WBSEQNO(wrb) + TCP_WBSENT(wrb));
|
||||||
|
|
||||||
|
#ifdef NEED_IPDOMAIN_SUPPORT
|
||||||
|
/* If both IPv4 and IPv6 support are enabled, then we will need to
|
||||||
|
* select which one to use when generating the outgoing packet.
|
||||||
|
* If only one domain is selected, then the setup is already in
|
||||||
|
* place and we need do nothing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
send_ipselect(dev, conn);
|
||||||
|
#endif
|
||||||
|
/* Then set-up to send that amount of data with the offset
|
||||||
|
* corresponding to the amount of data already sent. (this
|
||||||
|
* won't actually happen until the polling cycle completes).
|
||||||
|
*/
|
||||||
|
|
||||||
|
devif_iob_send(dev, TCP_WBIOB(wrb), sndlen, TCP_WBSENT(wrb));
|
||||||
|
|
||||||
|
/* Remember how much data we send out now so that we know
|
||||||
|
* when everything has been acknowledged. Just increment
|
||||||
|
* the amount of data sent. This will be needed in sequence
|
||||||
|
* number calculations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
conn->tx_unacked += sndlen;
|
||||||
|
conn->sent += sndlen;
|
||||||
|
|
||||||
|
/* Below prediction will become true,
|
||||||
|
* unless retransmission occurrence
|
||||||
|
*/
|
||||||
|
|
||||||
|
predicted_seqno = tcp_getsequence(conn->sndseq) + sndlen;
|
||||||
|
|
||||||
|
if (TCP_SEQ_GT(predicted_seqno, conn->sndseq_max))
|
||||||
|
{
|
||||||
|
conn->sndseq_max = predicted_seqno;
|
||||||
|
}
|
||||||
|
|
||||||
|
ninfo("SEND: wrb=%p nrtx=%u tx_unacked=%" PRIu32
|
||||||
|
" sent=%" PRIu32 "\n",
|
||||||
|
wrb, TCP_WBNRTX(wrb), conn->tx_unacked, conn->sent);
|
||||||
|
|
||||||
|
/* Increment the count of bytes sent from this write buffer */
|
||||||
|
|
||||||
|
TCP_WBSENT(wrb) += sndlen;
|
||||||
|
|
||||||
|
ninfo("SEND: wrb=%p sent=%u pktlen=%u\n",
|
||||||
|
wrb, TCP_WBSENT(wrb), TCP_WBPKTLEN(wrb));
|
||||||
|
|
||||||
|
/* Remove the write buffer from the write queue if the
|
||||||
|
* last of the data has been sent from the buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUGASSERT(TCP_WBSENT(wrb) <= TCP_WBPKTLEN(wrb));
|
||||||
|
if (TCP_WBSENT(wrb) >= TCP_WBPKTLEN(wrb))
|
||||||
|
{
|
||||||
|
FAR struct tcp_wrbuffer_s *tmp;
|
||||||
|
|
||||||
|
ninfo("SEND: wrb=%p Move to unacked_q\n", wrb);
|
||||||
|
|
||||||
|
tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q);
|
||||||
|
DEBUGASSERT(tmp == wrb);
|
||||||
|
UNUSED(tmp);
|
||||||
|
|
||||||
|
/* Put the I/O buffer chain in the un-acked queue; the
|
||||||
|
* segment is waiting for ACK again
|
||||||
|
*/
|
||||||
|
|
||||||
|
psock_insert_segment(wrb, &conn->unacked_q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only one data can be sent by low level driver at once,
|
||||||
|
* tell the caller stop polling the other connection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
flags &= ~TCP_POLL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only one data can be sent by low level driver at once,
|
|
||||||
* tell the caller stop polling the other connection.
|
|
||||||
*/
|
|
||||||
|
|
||||||
flags &= ~TCP_POLL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Continue waiting */
|
/* Continue waiting */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user