[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lwip-devel] [bug #21582] pcb->acked accounting can be wrong when ACKs a

From: Berend Ozceri
Subject: [lwip-devel] [bug #21582] pcb->acked accounting can be wrong when ACKs arrive out-of-order
Date: Wed, 14 Nov 2007 21:24:36 +0000
User-agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv: Gecko/20070309 Firefox/


                 Summary: pcb->acked accounting can be wrong when ACKs arrive
                 Project: lwIP - A Lightweight TCP/IP stack
            Submitted by: berend
            Submitted on: Wednesday 11/14/2007 at 21:24
                Category: TCP
                Severity: 3 - Normal
              Item Group: Faulty Behaviour
                  Status: None
                 Privacy: Public
             Assigned to: None
             Open/Closed: Open
         Discussion Lock: Any
         Planned Release: 



The acked field of every TCP pcb structure is supposed to be set to the
number of new bytes that were ACKed by the remote receiver during the
tcp_receive() function call for incoming TCP packet processing.

The relevant portion of the tcp_receive() code looks something like:

    if (pcb->lastack == ackno) {
      pcb->acked = 0;
      Do duplicate ACK processing (initiate fast retransmit, etc.)
    } else if(TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){
      Handle ACK of data that falls between the last ACKed byte and the end
of the send window
      pcb->acked = ackno - pcb->lastack;

Once tcp_receive() returns back to tcp_process(), the following code is
executed to invoke the "sent data has been ACKed" callback for the connection,
if one is registered:

    if (pcb->acked > 0) {
      TCP_EVENT_SENT(pcb, pcb->acked, err);

The problem is that tcp_receive() does not handle the case where neither of
the two if branches are taken - a case where an ACK arrives for data that's
already been ACKed by virtue of a later ACK arriving before the one ACKing
earlier data. In that case neither pcb->lastack == ackno, nor
TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max) is true, so pcb->acked
simply holds its old value, which may be non-zero. That can result in
tcp_process() mistakenly invoking the callback. While applications that depend
solely on the event-oriented aspect of the callback may not be affected (other
than being notified spuriously), applications that actually track buffer usage
with the call-back length argument can potentially double-count ACKed buffer

The fix is the simple addition of:

    else {
      pcb->acked = 0;

to zero the ACK count in case an out-of-order ACK for already ACKed data

The reason this bug probably does not matter in typical lwIP usage is that
most uses of this callback simply use its event notification aspect, but not
the actual ACKed byte counting aspect for fine-tuned buffer management. The
callback is typically used to check the new value of pcb->snd_buf, to see if
there's send space available, which is accounted for correctly despite the
above bug.



Reply to this item at:


  Message sent via/by Savannah

reply via email to

[Prev in Thread] Current Thread [Next in Thread]