tcp_input: snd_wnd processing
* Do not accept the window in old segments. Implement SND.WL1/WL2 things in the RFC. * Do not accept the window in the segment w/o ACK bit set. The window is an offset from the ack seq. (maybe it's simpler to just drop segments w/o ACK though) * Subtract snd_wnd by the amount of the ack advancement.
This commit is contained in:
parent
af57d04433
commit
1b82f1c749
@ -202,6 +202,8 @@ struct tcp_conn_s
|
|||||||
uint16_t snd_wnd; /* Sequence and acknowledgement numbers of last
|
uint16_t snd_wnd; /* Sequence and acknowledgement numbers of last
|
||||||
* window update */
|
* window update */
|
||||||
#endif
|
#endif
|
||||||
|
uint32_t snd_wl1;
|
||||||
|
uint32_t snd_wl2;
|
||||||
#if CONFIG_NET_RECV_BUFSIZE > 0
|
#if CONFIG_NET_RECV_BUFSIZE > 0
|
||||||
int32_t rcv_bufs; /* Maximum amount of bytes queued in recv */
|
int32_t rcv_bufs; /* Maximum amount of bytes queued in recv */
|
||||||
#endif
|
#endif
|
||||||
|
@ -190,6 +190,77 @@ static bool tcp_trim_head(FAR struct net_driver_s *dev,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tcp_snd_wnd_init(FAR struct tcp_conn_s *conn,
|
||||||
|
FAR struct tcp_hdr_s *tcp)
|
||||||
|
{
|
||||||
|
/* Just ensure that the next tcp_update_snd_wnd will be accepted. */
|
||||||
|
|
||||||
|
DEBUGASSERT((tcp->flags & TCP_ACK) != 0);
|
||||||
|
conn->snd_wl1 = TCP_SEQ_SUB(tcp_getsequence(tcp->seqno), 1);
|
||||||
|
conn->snd_wl2 = tcp_getsequence(tcp->ackno);
|
||||||
|
conn->snd_wnd = 0;
|
||||||
|
ninfo("snd_wnd init: wl1 %" PRIu32 "\n", conn->snd_wl1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tcp_snd_wnd_update(FAR struct tcp_conn_s *conn,
|
||||||
|
FAR struct tcp_hdr_s *tcp)
|
||||||
|
{
|
||||||
|
uint32_t ackseq = tcp_getsequence(tcp->ackno);
|
||||||
|
uint32_t seq = tcp_getsequence(tcp->seqno);
|
||||||
|
uint16_t unscaled_wnd = ((uint16_t)tcp->wnd[0] << 8) + tcp->wnd[1];
|
||||||
|
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
|
||||||
|
uint32_t wnd = (uint32_t)unscaled_wnd << conn->snd_scale;
|
||||||
|
#else
|
||||||
|
uint16_t wnd = unscaled_wnd;
|
||||||
|
#endif
|
||||||
|
uint32_t wl2 = conn->snd_wl2;
|
||||||
|
|
||||||
|
DEBUGASSERT((tcp->flags & TCP_ACK) != 0);
|
||||||
|
|
||||||
|
if (TCP_SEQ_LT(wl2, ackseq))
|
||||||
|
{
|
||||||
|
uint32_t nacked = TCP_SEQ_SUB(ackseq, wl2);
|
||||||
|
|
||||||
|
ninfo("snd_wnd acked: "
|
||||||
|
"wl2 %" PRIu32 " -> %" PRIu32 " subtracting wnd %" PRIu32
|
||||||
|
" by %" PRIu32 "\n",
|
||||||
|
wl2,
|
||||||
|
ackseq,
|
||||||
|
(uint32_t)conn->snd_wnd,
|
||||||
|
nacked);
|
||||||
|
|
||||||
|
if (nacked > conn->snd_wnd)
|
||||||
|
{
|
||||||
|
conn->snd_wnd = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
conn->snd_wnd -= nacked;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->snd_wl2 = ackseq;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TCP_SEQ_LT(conn->snd_wl1, seq) ||
|
||||||
|
(conn->snd_wl1 == seq && TCP_SEQ_LT(wl2, ackseq)) ||
|
||||||
|
(wl2 == ackseq && conn->snd_wnd < wnd))
|
||||||
|
{
|
||||||
|
ninfo("snd_wnd update: "
|
||||||
|
"wl1 %" PRIu32 " wl2 %" PRIu32 " wnd %" PRIu32 " -> "
|
||||||
|
"wl1 %" PRIu32 " wl2 %" PRIu32 " wnd %" PRIu32 "\n",
|
||||||
|
conn->snd_wl1,
|
||||||
|
wl2,
|
||||||
|
(uint32_t)conn->snd_wnd,
|
||||||
|
seq,
|
||||||
|
ackseq,
|
||||||
|
(uint32_t)wnd);
|
||||||
|
|
||||||
|
conn->snd_wl1 = seq;
|
||||||
|
conn->snd_wl2 = ackseq;
|
||||||
|
conn->snd_wnd = wnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: tcp_input
|
* Name: tcp_input
|
||||||
*
|
*
|
||||||
@ -447,15 +518,6 @@ reset:
|
|||||||
|
|
||||||
found:
|
found:
|
||||||
|
|
||||||
/* Update the connection's window size */
|
|
||||||
|
|
||||||
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
|
|
||||||
conn->snd_wnd = (((uint32_t)tcp->wnd[0] << 8) + (uint32_t)tcp->wnd[1]) <<
|
|
||||||
conn->snd_scale;
|
|
||||||
#else
|
|
||||||
conn->snd_wnd = (((uint16_t)tcp->wnd[0] << 8) + (uint16_t)tcp->wnd[1]);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
|
||||||
/* We do a very naive form of TCP reset processing; we just accept
|
/* We do a very naive form of TCP reset processing; we just accept
|
||||||
@ -680,6 +742,14 @@ found:
|
|||||||
conn->timer = conn->rto;
|
conn->timer = conn->rto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update the connection's window size */
|
||||||
|
|
||||||
|
if ((tcp->flags & TCP_ACK) != 0 &&
|
||||||
|
(conn->tcpstateflags & TCP_STATE_MASK) != TCP_SYN_RCVD)
|
||||||
|
{
|
||||||
|
tcp_snd_wnd_update(conn, tcp);
|
||||||
|
}
|
||||||
|
|
||||||
/* Do different things depending on in what state the connection is. */
|
/* Do different things depending on in what state the connection is. */
|
||||||
|
|
||||||
switch (conn->tcpstateflags & TCP_STATE_MASK)
|
switch (conn->tcpstateflags & TCP_STATE_MASK)
|
||||||
@ -736,6 +806,9 @@ found:
|
|||||||
conn->sndseq_max = 0;
|
conn->sndseq_max = 0;
|
||||||
#endif
|
#endif
|
||||||
conn->tx_unacked = 0;
|
conn->tx_unacked = 0;
|
||||||
|
tcp_snd_wnd_init(conn, tcp);
|
||||||
|
tcp_snd_wnd_update(conn, tcp);
|
||||||
|
|
||||||
flags = TCP_CONNECTED;
|
flags = TCP_CONNECTED;
|
||||||
ninfo("TCP state: TCP_ESTABLISHED\n");
|
ninfo("TCP state: TCP_ESTABLISHED\n");
|
||||||
|
|
||||||
@ -834,6 +907,8 @@ found:
|
|||||||
conn->tcpstateflags = TCP_ESTABLISHED;
|
conn->tcpstateflags = TCP_ESTABLISHED;
|
||||||
memcpy(conn->rcvseq, tcp->seqno, 4);
|
memcpy(conn->rcvseq, tcp->seqno, 4);
|
||||||
conn->rcv_adv = tcp_getsequence(conn->rcvseq);
|
conn->rcv_adv = tcp_getsequence(conn->rcvseq);
|
||||||
|
tcp_snd_wnd_init(conn, tcp);
|
||||||
|
tcp_snd_wnd_update(conn, tcp);
|
||||||
|
|
||||||
net_incr32(conn->rcvseq, 1); /* ack SYN */
|
net_incr32(conn->rcvseq, 1); /* ack SYN */
|
||||||
conn->tx_unacked = 0;
|
conn->tx_unacked = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user