Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 14 Jul 1997 18:51:09 +0300 (EEST)
From:      Ruslan Ermilov <ru@ferrix.ucb.crimea.ua>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   kern/4090: slip driver is incompatible with current version of ifconfig
Message-ID:  <199707141551.SAA11977@ferrix.ucb.crimea.ua>
Resent-Message-ID: <199707141600.JAA28496@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         4090
>Category:       kern
>Synopsis:       slip driver is incompatible with current version of ifconfig
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jul 14 09:00:04 PDT 1997
>Last-Modified:
>Originator:     Ruslan Ermilov
>Organization:
>Release:        FreeBSD 2.2.1-RELEASE i386
>Environment:

	RELENG_2_2

>Description:

	When slattach (sliplogin, startslip) assigns the SLIP
	unit directly (using ioctl SLIOCSUNIT), driver changes
	interface unit number to that specified.

	/sbin/ifconfig doesn't see this change and (as result)
	configures improper interface.


	Explanation:

	The driver code is located in /sys/net/if_sl.c.

	When the kernel boots up, it invokes slattach(), which
	adds NSL slip interfaces to the kernel interface list.

	When slattach switches the line (tty) to slip discipline,
	the slopen() allocates first free (not assigned any tty),
	not SC_STATICized element of sl_softc[].

	Then, when the sltioctl() processes SLIOCSUNIT request,
	it looks if the current SLIP unit of the controlling tty
	is equal to that requested. If not, it searches the element
	of slsoftc[] that has the same unit number as that requested,
	checks if this element has no assigned tty, and (if success)
	swaps SLIP unit numbers (and other fields) of these two
	elements of sl_softc[].

	Kernel's interface list doesn't see this change of units,
	so /sbin/ifconfig will configure improper interface.

>How-To-Repeat:

	Build the kernel with at least two slip interfaces.

	Run /sbin/slattach -S 1 /dev/cuaa0.
	This will allocate sl_softc[0] and then swap SLIP unit
	numbers on sl_softc[0] and sl_softc[1] so that sl_softc[0]
	will be assigned unit 1, and sl_softc[1] - unit 0.

	Configure sl1 with `ifconfig sl1 inet x.x.x.x y.y.y.y'.

	Run `ifconfig -a'.
	The output will show that sl0 has been configured instead of sl1.

>Fix:

	The following patch solves the problem.
	Patch has been applied to the 1.45.2.1 version of if_sl.c.


	Changes:

	slopen() doesn't allocates clists. Driver allocates clists
	when the SLIOCSUNIT or SLIOCGUNIT ioctls are used, thus
	avoiding swap of slip unit numbers.

[********** cut here **********]
--- if_sl.c.orig	Tue Mar 11 21:40:37 1997
+++ if_sl.c	Mon Jul 14 18:37:24 1997
@@ -186,6 +186,7 @@
 static struct mbuf *sl_btom __P((struct sl_softc *, int));
 static timeout_t sl_keepalive;
 static timeout_t sl_outfill;
+static int	slalloc __P((int, struct tty *));
 static int	slclose __P((struct tty *,int));
 static int	slinput __P((int, struct tty *));
 static int	slioctl __P((struct ifnet *, int, caddr_t));
@@ -265,8 +266,6 @@
 	register struct tty *tp;
 {
 	struct proc *p = curproc;		/* XXX */
-	register struct sl_softc *sc;
-	register int nsl;
 	int s, error;
 
 	error = suser(p->p_ucred, &p->p_acflag);
@@ -276,38 +275,62 @@
 	if (tp->t_line == SLIPDISC)
 		return (0);
 
-	for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++)
-		if (sc->sc_ttyp == NULL && !(sc->sc_flags & SC_STATIC)) {
-			if (slinit(sc) == 0)
-				return (ENOBUFS);
-			tp->t_sc = (caddr_t)sc;
-			sc->sc_ttyp = tp;
-			sc->sc_if.if_baudrate = tp->t_ospeed;
-			ttyflush(tp, FREAD | FWRITE);
-
-			tp->t_line = SLIPDISC;
-			/*
-			 * We don't use t_canq or t_rawq, so reduce their
-			 * cblock resources to 0.  Reserve enough cblocks
-			 * for t_outq to guarantee that we can fit a full
-			 * packet if the SLIP_HIWAT check allows slstart()
-			 * to loop.  Use the same value for the cblock
-			 * limit since the reserved blocks should always
-			 * be enough.  Reserving cblocks probably makes
-			 * the CLISTRESERVE check unnecessary and wasteful.
-			 */
-			clist_alloc_cblocks(&tp->t_canq, 0, 0);
-			clist_alloc_cblocks(&tp->t_outq,
-			    SLIP_HIWAT + 2 * sc->sc_if.if_mtu + 1,
-			    SLIP_HIWAT + 2 * sc->sc_if.if_mtu + 1);
-			clist_alloc_cblocks(&tp->t_rawq, 0, 0);
-
-			s = splnet();
-			if_up(&sc->sc_if);
-			splx(s);
-			return (0);
-		}
-	return (ENXIO);
+	ttyflush(tp, FREAD | FWRITE);
+
+	tp->t_line = SLIPDISC;
+	return (0);
+}
+
+static int
+slalloc(unit, tp)
+	int unit;
+	struct tty *tp;
+{
+	register struct sl_softc *sc;
+	int s, static_unit = 1;
+
+	if (unit == -1) {
+		static_unit = 0;
+		for (unit = 0; unit < NSL; unit++)
+			if (sl_softc[unit].sc_ttyp == NULL &&
+				!(sl_softc[unit].sc_flags & SC_STATIC) )
+				break;
+	}
+
+	if (unit < 0 || unit >= NSL || tp->t_sc != NULL)
+		return (ENXIO);
+
+	sc = &sl_softc[unit];
+	if (sc->sc_ttyp != NULL)
+		return (EBUSY);
+	if (slinit(sc) == 0)
+		return (ENOBUFS);
+	
+	tp->t_sc = (caddr_t)sc;
+	sc->sc_ttyp = tp;
+	sc->sc_if.if_baudrate = tp->t_ospeed;
+	if (static_unit != 0)
+		sc->sc_flags |= SC_STATIC;
+	/*
+	 * We don't use t_canq or t_rawq, so reduce their
+	 * cblock resources to 0.  Reserve enough cblocks
+	 * for t_outq to guarantee that we can fit a full
+	 * packet if the SLIP_HIWAT check allows slstart()
+	 * to loop.  Use the same value for the cblock
+	 * limit since the reserved blocks should always
+	 * be enough.  Reserving cblocks probably makes
+	 * the CLISTRESERVE check unnecessary and wasteful.
+	 */
+	clist_alloc_cblocks(&tp->t_canq, 0, 0);
+	clist_alloc_cblocks(&tp->t_outq,
+	    SLIP_HIWAT + 2 * sc->sc_if.if_mtu + 1,
+	    SLIP_HIWAT + 2 * sc->sc_if.if_mtu + 1);
+	clist_alloc_cblocks(&tp->t_rawq, 0, 0);
+
+	s = splnet();
+	if_up(&sc->sc_if);
+	splx(s);
+	return (0);
 }
 
 /*
@@ -368,34 +391,34 @@
 	struct proc *p;
 {
 	struct sl_softc *sc = (struct sl_softc *)tp->t_sc, *nc;
-	int s, nsl;
+	int s, nsl, ret;
+
+	if (sc == NULL && (cmd != SLIOCGUNIT && cmd != SLIOCSUNIT))
+		return (ENXIO);
 
 	s = splimp();
 	switch (cmd) {
 	case SLIOCGUNIT:
+		if (sc == NULL) {
+			ret = slalloc(-1, tp);
+			if (ret != 0) {
+				splx(s);
+				return (ret);
+			}
+			sc = (struct sl_softc *)tp->t_sc;
+		}
 		*(int *)data = sc->sc_if.if_unit;
 		break;
 
 	case SLIOCSUNIT:
-		if (sc->sc_if.if_unit != *(u_int *)data) {
-			for (nsl = NSL, nc = sl_softc; --nsl >= 0; nc++) {
-				if (   nc->sc_if.if_unit == *(u_int *)data
-				    && nc->sc_ttyp == NULL
-				   ) {
-					nc->sc_if.if_unit = sc->sc_if.if_unit;
-					nc->sc_flags &= ~SC_STATIC;
-					nc->sc_flags |= sc->sc_flags & SC_STATIC;
-					sc->sc_if.if_unit = *(u_int *)data;
-					goto slfound;
-				}
-			}
-			splx(s);
-			return (ENXIO);
-		}
-	slfound:
-		sc->sc_flags |= SC_STATIC;
+		if (sc == NULL)
+			ret = slalloc(*(int *)data, tp);
+		else
+			ret = EEXIST;
+		splx(s);
+		return (ret);
 		break;
-
+			
 	case SLIOCSKEEPAL:
 		sc->sc_keepalive = *(u_int *)data * hz;
 		if (sc->sc_keepalive) {
[********** cut here **********]
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199707141551.SAA11977>