NetBSD Problem Report #4227

Received: (qmail 19013 invoked from network); 6 Oct 1997 17:04:48 -0000
Message-Id: <199710061705.CAA03470@escar.shiota.imasy.or.jp>
Date: Tue, 7 Oct 1997 02:05:13 +0900 (JST)
From: Noriyuki Shiota <nori@shiota.imasy.or.jp>
Reply-To: nori@shiota.imasy.or.jp
To: gnats-bugs@gnats.netbsd.org
Subject: blocked state of hardware flow control is not cleared
X-Send-Pr-Version: 3.95

>Number:         4227
>Category:       kern
>Synopsis:       blocked state of hardware flow control is not cleared
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Oct 06 10:05:01 +0000 1997
>Closed-Date:    
>Last-Modified:  Sun Sep 03 01:16:18 +0000 2006
>Originator:     Noriyuki Shiota
>Release:        NetBSD-current as of October 6, 1997
>Organization:
Noriyuki Shiota		nori@shiota.imasy.or.jp
>Environment:
System: NetBSD escar 1.2G NetBSD 1.2G (ESCAR_BT_BOCA) #15: Mon Oct 6 23:26:37 JST 1997 root@escar:/usr/src/sys/arch/i386/compile/ESCAR_BT_BOCA i386

>Description:
	On establishing ppp connection, I used following command:
		pppd `chat ...` ....
	and chat script is done normally.
	But if the host machine send the long motd message, serial driver
	negates RTS signal line.
	then pppd changes line descipline to ppp, RTS signal is still
	low. (serial driver's state is still blocked.)
	In this situation, pppd never receive PPP packet.

>How-To-Repeat:
	Try to connect ppp to long motd ppp server.
    or
	f = open("/dev/tty00", O_RDWR);

	<receive may characters from serial line.
	 (*tp->t_hwiflow)(tp, 1) is called.
	 serial driver clears RTS signal line and enter block state>

	what = FREAD;
	ioctl(f, TIOCFLUSH, &what);	/* flush receive buffer */

	read(f, buf, sizeof(buf));	<-- block forever...
					    receive no character because
					    RTS is still low.
    or
	f = open("/dev/tty00", O_RDWR);

	<receive may characters from serial line.
	 (*tp->t_hwiflow)(tp, 1) is called.
	 serial driver clears RTS signal line and enter block state>

	ldisc = PPPDISC;
	ioctl(f, TIOCSETD, &ldisc);	/* change to PPP line descipline */

	read(f, buf, sizeof(buf));	<-- block forever...
					    receive no character because
					    RTS is still low.

>Fix:
*** tty.c.ORIG	Fri Jun 20 20:33:34 1997
--- tty.c	Tue Oct  7 02:04:29 1997
***************
*** 1057,1082 ****
--- 1057,1086 ----
  ttyflush(tp, rw)
  	register struct tty *tp;
  	int rw;
  {
  	register int s;

  	s = spltty();
  	if (rw & FREAD) {
  		FLUSHQ(&tp->t_canq);
  		FLUSHQ(&tp->t_rawq);
  		tp->t_rocount = 0;
  		tp->t_rocol = 0;
  		CLR(tp->t_state, TS_LOCAL);
+ 		if (ISSET(tp->t_state, TS_TBLOCK) &&
+ 		    ISSET(tp->t_cflag, CHWFLOW) && tp->t_hwiflow &&
+ 		    (*tp->t_hwiflow)(tp, 0) != 0)
+ 			CLR(tp->t_state, TS_TBLOCK);
  		ttwakeup(tp);
  	}
  	if (rw & FWRITE) {
  		CLR(tp->t_state, TS_TTSTOP);
  		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
  		FLUSHQ(&tp->t_outq);
  		wakeup((caddr_t)&tp->t_outq);
  		selwakeup(&tp->t_wsel);
  	}
  	splx(s);
  }

  /*
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: kern-bug-people->mycroft 
Responsible-Changed-By: mycroft 
Responsible-Changed-When: Thu Oct 9 02:09:52 PDT 1997 
Responsible-Changed-Why:  
The patch isn't quite complete; it doesn't handle the IXOFF case.  I'll fix it 
shortly. 

From: "Charles M. Hannum" <mycroft@mit.edu>
To: nori@shiota.imasy.or.jp
Cc: gnats-bugs@gnats.netbsd.org
Subject: Re: kern/4227: blocked state of hardware flow control is not cleared
Date: Thu, 9 Oct 1997 16:11:33 -0400 (EDT)

 Your patch is more or less correct, but:

 * It doesn't deal with the case of XON/XOFF flow control.  (This also
 requires a slight rearrangement so that we queue the XON character
 *after* flushing the write side.)

 * It could (if the case were actually possible, which it's not
 currently) cause a fairly severe malfunction when an input ring
 becomes full; the input will be unblocked and then immediately blocked
 again.

 * There is a remaining problem that I haven't solved in the following
 patch.  With your change, if the input ring is full, there will be a
 glitch on RTS during close, as it's raised by foohwiflow() and then
 immediately lowered again by fooclose().  This is actually a fairly
 serious error, and needs to be fixed.


 Index: tty.c
 ===================================================================
 RCS file: /cvsroot/src/sys/kern/tty.c,v
 retrieving revision 1.98
 diff -c -2 -r1.98 tty.c
 *** tty.c	1997/10/09 12:59:56	1.98
 --- tty.c	1997/10/09 20:09:31
 ***************
 *** 67,70 ****
 --- 67,72 ----
   static void ttyrubo __P((struct tty *, int));
   static int proc_compare __P((struct proc *, struct proc *));
 + static __inline void ttblock __P((struct tty *));
 + static __inline void ttunblock __P((struct tty *));

   /* Symbolic sleep message strings. */
 ***************
 *** 1014,1017 ****
 --- 1016,1055 ----
   }

 + static __inline void
 + ttblock(tp)
 + 	struct tty *tp;
 + {
 + 
 + 	/* Try to block remote output via software (XON/XOFF) flow control. */
 + 	if (ISSET(tp->t_iflag, IXOFF) &&
 + 	    tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
 + 	    putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
 + 		SET(tp->t_state, TS_TBLOCK);
 + 		ttstart(tp);
 + 	}
 + 	/* Try to block remote output via hardware (CTS/RTS) flow control. */
 + 	if (ISSET(tp->t_cflag, CHWFLOW) && tp->t_hwiflow &&
 + 	    (*tp->t_hwiflow)(tp, 1) != 0)
 + 		SET(tp->t_state, TS_TBLOCK);
 + }
 + 
 + static __inline void
 + ttunblock(tp)
 + 	struct tty *tp;
 + {
 + 
 + 	/* Try to unblock remote output via software (XON/XOFF) flow control. */
 + 	if (ISSET(tp->t_iflag, IXOFF) &&
 + 	    tp->t_cc[VSTART] != _POSIX_VDISABLE &&
 + 	    putc(tp->t_cc[VSTART], &tp->t_outq) == 0) {
 + 		CLR(tp->t_state, TS_TBLOCK);
 + 		ttstart(tp);
 + 	}
 + 	/* Try to unblock remote output via hardware (CTS/RTS) flow control. */
 + 	if (ISSET(tp->t_cflag, CHWFLOW) && tp->t_hwiflow &&
 + 	    (*tp->t_hwiflow)(tp, 0) != 0)
 + 		CLR(tp->t_state, TS_TBLOCK);
 + }
 + 
   /*
    * Wait for output to drain.
 ***************
 *** 1062,1065 ****
 --- 1100,1110 ----

   	s = spltty();
 + 	if (rw & FWRITE) {
 + 		CLR(tp->t_state, TS_TTSTOP);
 + 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
 + 		FLUSHQ(&tp->t_outq);
 + 		wakeup((caddr_t)&tp->t_outq);
 + 		selwakeup(&tp->t_wsel);
 + 	}
   	if (rw & FREAD) {
   		FLUSHQ(&tp->t_canq);
 ***************
 *** 1068,1080 ****
   		tp->t_rocol = 0;
   		CLR(tp->t_state, TS_LOCAL);
   		ttwakeup(tp);
   	}
 - 	if (rw & FWRITE) {
 - 		CLR(tp->t_state, TS_TTSTOP);
 - 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
 - 		FLUSHQ(&tp->t_outq);
 - 		wakeup((caddr_t)&tp->t_outq);
 - 		selwakeup(&tp->t_wsel);
 - 	}
   	splx(s);
   }
 --- 1113,1120 ----
   		tp->t_rocol = 0;
   		CLR(tp->t_state, TS_LOCAL);
 + 		if (ISSET(tp->t_state, TS_TBLOCK))
 + 			ttunblock(tp);
   		ttwakeup(tp);
   	}
   	splx(s);
   }
 ***************
 *** 1102,1107 ****
   	total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
   	if (tp->t_rawq.c_cc > TTYHOG) {
 - 		ttyflush(tp, FREAD | FWRITE);
   		CLR(tp->t_state, TS_TBLOCK);
   	}
   	/*
 --- 1142,1147 ----
   	total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
   	if (tp->t_rawq.c_cc > TTYHOG) {
   		CLR(tp->t_state, TS_TBLOCK);
 + 		ttyflush(tp, FREAD | FWRITE);
   	}
   	/*
 ***************
 *** 1111,1126 ****
   	if ((total >= TTYHOG / 2 &&
   	     !ISSET(tp->t_state, TS_TBLOCK) &&
 ! 	     !ISSET(tp->t_lflag, ICANON)) || tp->t_canq.c_cc > 0) {
 ! 		if (ISSET(tp->t_iflag, IXOFF) &&
 ! 		    tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
 ! 		    putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
 ! 			SET(tp->t_state, TS_TBLOCK);
 ! 			ttstart(tp);
 ! 		}
 ! 		/* Try to block remote output via hardware flow control. */
 ! 		if (ISSET(tp->t_cflag, CHWFLOW) && tp->t_hwiflow &&
 ! 		    (*tp->t_hwiflow)(tp, 1) != 0)
 ! 			SET(tp->t_state, TS_TBLOCK);
 ! 	}
   }

 --- 1151,1156 ----
   	if ((total >= TTYHOG / 2 &&
   	     !ISSET(tp->t_state, TS_TBLOCK) &&
 ! 	     !ISSET(tp->t_lflag, ICANON)) || tp->t_canq.c_cc > 0)
 ! 		ttblock(tp);
   }

 ***************
 *** 1189,1195 ****
   			CLR(tp->t_state, TS_CARR_ON);
   			if (ISSET(tp->t_state, TS_ISOPEN) && !CONNECTED(tp)) {
   				if (tp->t_session && tp->t_session->s_leader)
   					psignal(tp->t_session->s_leader, SIGHUP);
 - 				ttyflush(tp, FREAD | FWRITE);
   				return (0);
   			}
 --- 1219,1225 ----
   			CLR(tp->t_state, TS_CARR_ON);
   			if (ISSET(tp->t_state, TS_ISOPEN) && !CONNECTED(tp)) {
 + 				ttyflush(tp, FREAD | FWRITE);
   				if (tp->t_session && tp->t_session->s_leader)
   					psignal(tp->t_session->s_leader, SIGHUP);
   				return (0);
   			}
 ***************
 *** 1435,1450 ****
   	 */
   	s = spltty();
 ! 	if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
 ! 		if (ISSET(tp->t_iflag, IXOFF) &&
 ! 		    cc[VSTART] != _POSIX_VDISABLE &&
 ! 		    putc(cc[VSTART], &tp->t_outq) == 0) {
 ! 			CLR(tp->t_state, TS_TBLOCK);
 ! 			ttstart(tp);
 ! 		}
 ! 		/* Try to unblock remote output via hardware flow control. */
 ! 		if (ISSET(tp->t_cflag, CHWFLOW) && tp->t_hwiflow &&
 ! 		    (*tp->t_hwiflow)(tp, 0) != 0)
 ! 			CLR(tp->t_state, TS_TBLOCK);
 ! 	}
   	splx(s);
   	return (error);
 --- 1465,1470 ----
   	 */
   	s = spltty();
 ! 	if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5)
 ! 		ttunblock(tp);
   	splx(s);
   	return (error);

From: Noriyuki Shiota <nori@shiota.imasy.or.jp>
To: mycroft@mit.edu
Cc: gnats-bugs@gnats.netbsd.org, nori@escar.shiota.imasy.or.jp
Subject: Re: kern/4227: blocked state of hardware flow control is not cleared
Date: Mon, 13 Oct 1997 06:08:27 +0900

 > Your patch is more or less correct, but:
 > 
 > * It doesn't deal with the case of XON/XOFF flow control.  (This also
 > requires a slight rearrangement so that we queue the XON character
 > *after* flushing the write side.)

 I didn't consider the XON/XOFF flow control case.
 I understand the same treatment is requred for this case.

 > * It could (if the case were actually possible, which it's not
 > currently) cause a fairly severe malfunction when an input ring
 > becomes full; the input will be unblocked and then immediately blocked
 > again.

 Is it a malfunction?  I don't understand what you mean.  After flushing,
 if many characters are received, an input ring and **the line decipline queue**
 are filled up, then to block immediately is normal behavior, isn't it?

 But I think that to add foohwiflush() is ideal.

 > * There is a remaining problem that I haven't solved in the following
 > patch.  With your change, if the input ring is full, there will be a
 > glitch on RTS during close, as it's raised by foohwiflow() and then
 > immediately lowered again by fooclose().  This is actually a fairly
 > serious error, and needs to be fixed.

 I see.  It is necessary to add a mask FCLOSE or FUNBLOCK for the second
 argument of ttyflush(), and if this mask is set then ttyflush() deson't
 call foohwiflow(tp, 0).  (in XON/XOFF case, I think it is better it send
 cc[VSTART] on closing.)
 --- 
 Noriyuki Shiota		nori@shiota.imasy.or.jp
Responsible-Changed-From-To: mycroft->kern-bug-people
Responsible-Changed-By: wiz@netbsd.org
Responsible-Changed-When: Sun, 03 Sep 2006 01:16:18 +0000
Responsible-Changed-Why:
Back to role account, mycroft doesn't have commit access any longer.


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.