Fix TCP sequence number error

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3136 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo
2010-11-27 18:01:54 +00:00
parent cb4c3a6c93
commit 15ae42fe55
2 changed files with 89 additions and 57 deletions
+11 -2
View File
@@ -233,6 +233,8 @@ static uint16_t send_interrupt(struct uip_driver_s *dev, void *pvconn,
if ((flags & UIP_NEWDATA) == 0 && pstate->snd_sent < pstate->snd_buflen) if ((flags & UIP_NEWDATA) == 0 && pstate->snd_sent < pstate->snd_buflen)
{ {
uint32_t seqno;
/* Get the amount of data that we can send in the next packet */ /* Get the amount of data that we can send in the next packet */
uint32_t sndlen = pstate->snd_buflen - pstate->snd_sent; uint32_t sndlen = pstate->snd_buflen - pstate->snd_sent;
@@ -241,9 +243,16 @@ static uint16_t send_interrupt(struct uip_driver_s *dev, void *pvconn,
sndlen = uip_mss(conn); sndlen = uip_mss(conn);
} }
/* Set the sequence number for this packet */ /* Set the sequence number for this packet. NOTE: uIP updates
* sndseq on recept of ACK *before* this function is called. In that
* case sndseq will point to the next unacknowledge byte (which might
* have already been sent). We will overwrite the value of sndseq
* here before the packet is sent.
*/
uip_tcpsetsequence(conn->sndseq, pstate->snd_sent + pstate->snd_isn); seqno = pstate->snd_sent + pstate->snd_isn;
nllvdbg("SEND: sndseq %08x->%08x\n", conn->sndseq, seqno);
uip_tcpsetsequence(conn->sndseq, seqno);
/* Then send that amount of data */ /* Then send that amount of data */
+78 -55
View File
@@ -261,7 +261,7 @@ void uip_tcpinput(struct uip_driver_s *dev)
/* We do not send resets in response to resets. */ /* We do not send resets in response to resets. */
if (pbuf->flags & TCP_RST) if ((pbuf->flags & TCP_RST) != 0)
{ {
goto drop; goto drop;
} }
@@ -282,7 +282,7 @@ found:
* before we accept the reset. * before we accept the reset.
*/ */
if (pbuf->flags & TCP_RST) if ((pbuf->flags & TCP_RST) != 0)
{ {
conn->tcpstateflags = UIP_CLOSED; conn->tcpstateflags = UIP_CLOSED;
nlldbg("RESET - TCP state: UIP_CLOSED\n"); nlldbg("RESET - TCP state: UIP_CLOSED\n");
@@ -328,62 +328,84 @@ found:
if ((pbuf->flags & TCP_ACK) != 0 && conn->unacked > 0) if ((pbuf->flags & TCP_ACK) != 0 && conn->unacked > 0)
{ {
uint32_t seqno; uint32_t unackseq;
uint32_t ackno; uint32_t ackseq;
/* The next sequence number is equal to the current sequence /* The next sequence number is equal to the current sequence
* number (sndseq) plus the size of the oustanding data (len). * number (sndseq) plus the size of the oustanding, unacknowledged
* data (unacked).
*/ */
seqno = uip_tcpaddsequence(conn->sndseq, conn->unacked); unackseq = uip_tcpaddsequence(conn->sndseq, conn->unacked);
/* Check if all of the outstanding bytes have been acknowledged. For /* Get the sequence number of that has just been acknowledged by this
* a "generic" send operation, this should always be true. However, * incoming packet.
*/
ackseq = uip_tcpgetsequence(pbuf->ackno);
/* Check how many of the outstanding bytes have been acknowledged. For
* a most uIP send operation, this should always be true. However,
* the send() API sends data ahead when it can without waiting for * the send() API sends data ahead when it can without waiting for
* the ACK. In this case, the 'ackno' could be less than then the * the ACK. In this case, the 'ackseq' could be less than then the
* new sequence number. * new sequence number.
*/ */
ackno = uip_tcpgetsequence(pbuf->ackno); if (ackseq <= unackseq)
if (ackno <= seqno)
{ {
/* Update sequence number. */ /* Calculate the new number of oustanding, unacknowledged bytes */
uip_tcpsetsequence(conn->sndseq, seqno); conn->unacked = unackseq - ackseq;
}
/* Do RTT estimation, unless we have done retransmissions. */ else
{
if (conn->nrtx == 0) /* What would it mean if ackseq > unackseq? The peer has ACKed
{ * more bytes than we think we have sent? Someone has lost it.
signed char m; * Complain and reset the number of outstanding, unackowledged
m = conn->rto - conn->timer; * bytes
*/
/* This is taken directly from VJs original code in his paper */
m = m - (conn->sa >> 3);
conn->sa += m;
if (m < 0)
{
m = -m;
}
m = m - (conn->sv >> 2);
conn->sv += m;
conn->rto = (conn->sa >> 3) + conn->sv;
}
/* Set the acknowledged flag. */
flags = UIP_ACKDATA;
/* Reset the retransmission timer. */
conn->timer = conn->rto;
/* Reset length of outstanding data. */
nlldbg("ERROR: ackseq[%08x] > unackseq[%08x]\n", ackseq, unackseq);
conn->unacked = 0; conn->unacked = 0;
} }
/* Update sequence number to the unacknowledge sequence number. If
* there is still outstanding, unacknowledged data, then this will
* be beyond ackseq.
*/
nllvdbg("sndseq: %08x->%08x unackseq: %08x new unacked: %d\n",
conn->sndseq, ackseq, unackseq, conn->unacked);
uip_tcpsetsequence(conn->sndseq, ackseq);
/* Do RTT estimation, unless we have done retransmissions. */
if (conn->nrtx == 0)
{
signed char m;
m = conn->rto - conn->timer;
/* This is taken directly from VJs original code in his paper */
m = m - (conn->sa >> 3);
conn->sa += m;
if (m < 0)
{
m = -m;
}
m = m - (conn->sv >> 2);
conn->sv += m;
conn->rto = (conn->sa >> 3) + conn->sv;
}
/* Set the acknowledged flag. */
flags |= UIP_ACKDATA;
/* Reset the retransmission timer. */
conn->timer = conn->rto;
} }
/* Do different things depending on in what state the connection is. */ /* Do different things depending on in what state the connection is. */
@@ -403,7 +425,7 @@ found:
* flag set. If so, we enter the ESTABLISHED state. * flag set. If so, we enter the ESTABLISHED state.
*/ */
if (flags & UIP_ACKDATA) if ((flags & UIP_ACKDATA) != 0)
{ {
conn->tcpstateflags = UIP_ESTABLISHED; conn->tcpstateflags = UIP_ESTABLISHED;
conn->unacked = 0; conn->unacked = 0;
@@ -431,7 +453,7 @@ found:
* state. * state.
*/ */
if ((flags & UIP_ACKDATA) && (pbuf->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) if ((flags & UIP_ACKDATA) != 0 && (pbuf->flags & TCP_CTL) == (TCP_SYN | TCP_ACK))
{ {
/* Parse the TCP MSS option, if present. */ /* Parse the TCP MSS option, if present. */
@@ -511,7 +533,7 @@ found:
/* We do not send resets in response to resets. */ /* We do not send resets in response to resets. */
if (pbuf->flags & TCP_RST) if ((pbuf->flags & TCP_RST) != 0)
{ {
goto drop; goto drop;
} }
@@ -531,7 +553,7 @@ found:
* sequence numbers will be screwed up. * sequence numbers will be screwed up.
*/ */
if (pbuf->flags & TCP_FIN && !(conn->tcpstateflags & UIP_STOPPED)) if ((pbuf->flags & TCP_FIN) != 0 && (conn->tcpstateflags & UIP_STOPPED) == 0)
{ {
if (conn->unacked > 0) if (conn->unacked > 0)
{ {
@@ -639,7 +661,7 @@ found:
* send, d_len must be set to 0. * send, d_len must be set to 0.
*/ */
if (flags & (UIP_NEWDATA | UIP_ACKDATA)) if ((flags & (UIP_NEWDATA | UIP_ACKDATA)) != 0)
{ {
dev->d_sndlen = 0; dev->d_sndlen = 0;
result = uip_tcpcallback(dev, conn, flags); result = uip_tcpcallback(dev, conn, flags);
@@ -653,7 +675,7 @@ found:
* FIN. This is indicated by the UIP_ACKDATA flag. * FIN. This is indicated by the UIP_ACKDATA flag.
*/ */
if (flags & UIP_ACKDATA) if ((flags & UIP_ACKDATA) != 0)
{ {
conn->tcpstateflags = UIP_CLOSED; conn->tcpstateflags = UIP_CLOSED;
nllvdbg("UIP_LAST_ACK TCP state: UIP_CLOSED\n"); nllvdbg("UIP_LAST_ACK TCP state: UIP_CLOSED\n");
@@ -672,9 +694,10 @@ found:
{ {
uip_incr32(conn->rcvseq, dev->d_len); uip_incr32(conn->rcvseq, dev->d_len);
} }
if (pbuf->flags & TCP_FIN)
if ((pbuf->flags & TCP_FIN) != 0)
{ {
if (flags & UIP_ACKDATA) if ((flags & UIP_ACKDATA) != 0)
{ {
conn->tcpstateflags = UIP_TIME_WAIT; conn->tcpstateflags = UIP_TIME_WAIT;
conn->timer = 0; conn->timer = 0;
@@ -692,7 +715,7 @@ found:
uip_tcpsend(dev, conn, TCP_ACK, UIP_IPTCPH_LEN); uip_tcpsend(dev, conn, TCP_ACK, UIP_IPTCPH_LEN);
return; return;
} }
else if (flags & UIP_ACKDATA) else if ((flags & UIP_ACKDATA) != 0)
{ {
conn->tcpstateflags = UIP_FIN_WAIT_2; conn->tcpstateflags = UIP_FIN_WAIT_2;
conn->unacked = 0; conn->unacked = 0;
@@ -713,7 +736,7 @@ found:
uip_incr32(conn->rcvseq, dev->d_len); uip_incr32(conn->rcvseq, dev->d_len);
} }
if (pbuf->flags & TCP_FIN) if ((pbuf->flags & TCP_FIN) != 0)
{ {
conn->tcpstateflags = UIP_TIME_WAIT; conn->tcpstateflags = UIP_TIME_WAIT;
conn->timer = 0; conn->timer = 0;
@@ -737,7 +760,7 @@ found:
return; return;
case UIP_CLOSING: case UIP_CLOSING:
if (flags & UIP_ACKDATA) if ((flags & UIP_ACKDATA) != 0)
{ {
conn->tcpstateflags = UIP_TIME_WAIT; conn->tcpstateflags = UIP_TIME_WAIT;
conn->timer = 0; conn->timer = 0;