Subject: Re: kern/34674: Panic in tcp_input() by integer division fault
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Michael van Elst <mlelstv@serpens.de>
List: netbsd-bugs
Date: 10/01/2006 11:25:02
The following reply was made to PR kern/34674; it has been noted by GNATS.

From: Michael van Elst <mlelstv@serpens.de>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: kern/34674: Panic in tcp_input() by integer division fault
Date: Sun, 1 Oct 2006 13:24:00 +0200

 christianbiere@gmx.de (Christian Biere) writes:
 
 > eip points into tcp_input(). I've dumped the assembler code of tcp_input()
 > and uploaded it here:
 > 
 > http://ghostwhitecrab.de/trash/gdb.log.bz2
 
 The division by zero occurs here:
 
                  * When new data is acked, open the congestion window.
                  * If the window gives us less than ssthresh packets
                  * in flight, open exponentially (segsz per packet).
                  * Otherwise open linearly: segsz per window
                  * (segsz^2 / cwnd per packet).
                  *
                  * If we are still in fast recovery (meaning we are using
                  * NewReno and we have only received partial acks), do not
                  * inflate the window yet. 
                  */
                 if (tp->t_partialacks < 0) {
                         u_int cw = tp->snd_cwnd;
                         u_int incr = tp->t_segsz;
 
                         if (cw >= tp->snd_ssthresh)
 -------->                       incr = incr * incr / cw;
                         tp->snd_cwnd = min(cw + incr,
                             TCP_MAXWIN << tp->snd_scale);
                 }
 
 with cw == 0.
 
 
 > The "culprit" is definitely /sys/netinet/tcp_output.c rev. 1.144.
 
 from tcp_output.c:
 [...]
                 *txsegsizep = min((so->so_snd.sb_hiwat -
                         so->so_snd.sb_lowat + 1) >> 1, *txsegsizep); 
 [...]
                         tp->snd_cwnd = max((tp->snd_cwnd / tp->t_segsz)
                                            * *txsegsizep, *txsegsizep);  
                         tp->snd_ssthresh = max((tp->snd_ssthresh / tp->t_segsz)
                                                 * *txsegsizep, *txsegsizep);
 
 With 1.144 txsegsizep can become zero when sb_hiwat and sb_lowat are
 identical. Then snd_cwnd and snd_ssthresh both become zero.
 
 With 1.143 the computation of txsegsize is a bit different:
 
                *txsegsizep = min(so->so_snd.sb_hiwat >> 1, *txsegsizep);
 
 -- 
                                 Michael van Elst
 Internet: mlelstv@serpens.de
                                 "A potential Snark may lurk in every tree."