Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 2 Apr 2000 21:35:54 +0100 (BST)
From:      dwmalone@maths.tcd.ie
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   kern/17758: Make the sl driver dynamically expandable.
Message-ID:  <200004022135.aa84513@walton.maths.tcd.ie>

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

>Number:         17758
>Category:       kern
>Synopsis:       Make sl driver dynamicallly expandable.
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Apr  2 13:40:01 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     David Malone
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
School of Mathematics, Trinity College, Dublin, Ireland.
>Environment:

4.0 and 5.0 - patch probably applies to 3-STABLE too.

>Description:

Currently you need to give the numbes of slip units in the kernel
config file. I include a patch which allocates units dynamically
as they are required. The patch is based on the tun driver and the
recent ability to delete interfaces which are no longer required.

One or two points of the patch are slightly tricky, so I'll explain
them here. These points relate to the fact that slip driver has an
ioctl which allows you to select what slip unit number you want.

First, if you specifically select a unit number, that unit is marked
as static and will not be handed out dynamically (ie. when SLIPDISC
is first selected for a tty). This used to be stored in the sl_softc
using the SC_STATIC flag, however as the new code now deallocates
sl_softc structs that are no longer in use it seemed a waste to
store a whole softc struct to just remember that it shouldn't be
handed out dynamically. For this reason I just store an array of
unit numbers which are to be considered static. The array is
explanded as necessary.

Second, the unit selecting code had become really complicated. It
swapped the contents of two softcs, and then swapped the contained
if structs back again. It seems these acrobatics aimed to ensure
that the linked list of interfaces didn't get screwed up. However
interfaces can now be deleted, and I wanted to deallocate the struct
softcs while they were no longer in use, so this code is now somewhat
more straight forward. (I don't understand why the cblocks are
reallocated after selecting a new unit number, it may now be
unnecessary).

The other changes just relate to the fact that the old driver got
the softc from sl_softc[ifp->if_unit] instead of ifp->if_softc.
Other than that I've tried to use the old code as much as possible.

(The only code which is a bit less efficient would be the code which
finds a free unit number. This could be improved by sorting the list
of static unit numbers and the list of existing slip devices, but it
doesn't seem worth the extra complexity).

I've given this patch some testing configuring one/both of my serial
ports as slip interfaces in various ways, and it seems to work fine.

>How-To-Repeat:

Try to use more slip devices than you have configured.

>Fix:

Index: if_sl.c
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/sys/net/if_sl.c,v
retrieving revision 1.84
diff -u -r1.84 if_sl.c
--- if_sl.c	2000/02/21 08:06:18	1.84
+++ if_sl.c	2000/03/31 22:16:57
@@ -105,6 +105,8 @@
 
 #include <net/bpf.h>
 
+static MALLOC_DEFINE(M_SL, "sl", "SLIP Interface");
+
 static void slattach __P((void *));
 PSEUDO_SET(slattach, if_sl);
 
@@ -168,14 +170,17 @@
 #define	ABT_COUNT	3	/* count of escapes for abort */
 #define	ABT_WINDOW	(ABT_COUNT*2+2)	/* in seconds - time to count */
 
-static struct sl_softc sl_softc[NSL];
+LIST_HEAD(sl_list, sl_softc) sl_list;
 
 #define FRAME_END	 	0xc0		/* Frame End */
 #define FRAME_ESCAPE		0xdb		/* Frame Esc */
 #define TRANS_FRAME_END	 	0xdc		/* transposed frame end */
 #define TRANS_FRAME_ESCAPE 	0xdd		/* transposed frame esc */
 
-static int slinit __P((struct sl_softc *));
+static int slisstatic __P((int));
+static void slmarkstatic __P((int));
+static struct sl_softc *slcreate __P((void));
+static void sldestroy __P((struct sl_softc *sc));
 static struct mbuf *sl_btom __P((struct sl_softc *, int));
 static timeout_t sl_keepalive;
 static timeout_t sl_outfill;
@@ -201,55 +206,110 @@
 slattach(dummy)
 	void *dummy;
 {
-	register struct sl_softc *sc;
-	register int i = 0;
-
 	linesw[SLIPDISC] = slipdisc;
 
-	for (sc = sl_softc; i < NSL; sc++) {
-		sc->sc_if.if_name = "sl";
-		sc->sc_if.if_unit = i++;
-		sc->sc_if.if_mtu = SLMTU;
-		sc->sc_if.if_flags =
-#ifdef SLIP_IFF_OPTS
-		    SLIP_IFF_OPTS;
-#else
-		    IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST;
-#endif
-		sc->sc_if.if_type = IFT_SLIP;
-		sc->sc_if.if_ioctl = slioctl;
-		sc->sc_if.if_output = sloutput;
-		sc->sc_if.if_snd.ifq_maxlen = 50;
-		sc->sc_fastq.ifq_maxlen = 32;
-		sc->sc_if.if_linkmib = sc;
-		sc->sc_if.if_linkmiblen = sizeof *sc;
-		if_attach(&sc->sc_if);
-		bpfattach(&sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
-	}
+	LIST_INIT(&sl_list);
 }
 
-static int
-slinit(sc)
-	register struct sl_softc *sc;
+static int *st_unit_list;
+static size_t st_unit_max = 0;
+
+static
+int slisstatic(unit)
+	int unit;
 {
-	register caddr_t p;
+	size_t i;
 
-	if (sc->sc_ep == (u_char *) 0) {
-		MCLALLOC(p, M_WAIT);
-		if (p)
-			sc->sc_ep = (u_char *)p + SLBUFSIZE;
-		else {
-			printf("sl%ld: can't allocate buffer\n",
-			    (long)(sc - sl_softc));
-			return (0);
-		}
+	for (i = 0; i < st_unit_max; i++)
+		if (st_unit_list[i] == unit)
+			return 1;
+	return 0;
+}
+
+static
+void slmarkstatic(unit)
+	int unit;
+{
+	int *t;
+
+	if (slisstatic(unit))
+		return;
+
+	MALLOC(t, int *, sizeof(int) * (st_unit_max+1), M_SL, M_NOWAIT);
+	if (t == NULL)
+		return;
+
+	if (st_unit_list) {
+		bcopy(st_unit_list, t, sizeof(int) * st_unit_max);
+		FREE(st_unit_list, M_SL);
+	}
+	st_unit_list = t;
+	st_unit_list[st_unit_max] = unit;
+	st_unit_max++;
+}
+
+static struct sl_softc *
+slcreate()
+{
+	struct sl_softc *sc, *nc;
+	int unit;
+	caddr_t p;
+
+	MALLOC(sc, struct sl_softc *, sizeof(*sc), M_SL, M_WAITOK);
+	bzero(sc, sizeof *sc);
+
+	MCLALLOC(p, M_WAIT);
+	if (p)
+		sc->sc_ep = (u_char *)p + SLBUFSIZE;
+	else {
+		printf("sl: can't allocate buffer\n");
+		FREE(sc, M_SL);
+		return (NULL);
 	}
+
 	sc->sc_buf = sc->sc_ep - SLRMAX;
 	sc->sc_mp = sc->sc_buf;
 	sl_compress_init(&sc->sc_comp, -1);
-	return (1);
+
+	sc->sc_if.if_softc = sc;
+	sc->sc_if.if_name = "sl";
+	sc->sc_if.if_mtu = SLMTU;
+	sc->sc_if.if_flags =
+#ifdef SLIP_IFF_OPTS
+	    SLIP_IFF_OPTS;
+#else
+	    IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST;
+#endif
+	sc->sc_if.if_type = IFT_SLIP;
+	sc->sc_if.if_ioctl = slioctl;
+	sc->sc_if.if_output = sloutput;
+	sc->sc_if.if_snd.ifq_maxlen = 50;
+	sc->sc_fastq.ifq_maxlen = 32;
+	sc->sc_if.if_linkmib = sc;
+	sc->sc_if.if_linkmiblen = sizeof *sc;
+
+	/*
+	 * Find a suitable unit number.
+	 */
+	for (unit=0; ; unit++) {
+		if (slisstatic(unit))
+			continue;
+		LIST_FOREACH(nc, &sl_list, sl_next) {
+			if (nc->sc_if.if_unit == unit)
+				continue;
+		}
+		break;
+	}
+	sc->sc_if.if_unit = unit;
+	LIST_INSERT_HEAD(&sl_list, sc, sl_next);
+
+	if_attach(&sc->sc_if);
+	bpfattach(&sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
+
+	return sc;
 }
 
+
 /*
  * Line specific open routine.
  * Attach the given tty to the first available sl unit.
@@ -262,7 +322,6 @@
 {
 	struct proc *p = curproc;		/* XXX */
 	register struct sl_softc *sc;
-	register int nsl;
 	int s, error;
 
 	error = suser(p);
@@ -272,38 +331,44 @@
 	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);
+	if ((sc = slcreate()) == NULL)
+		return (ENOBUFS);
 
-			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);
+	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;
 
-			s = splnet();
-			if_up(&sc->sc_if);
-			splx(s);
-			return (0);
-		}
-	return (ENXIO);
+	/*
+	 * 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);
+}
+
+void
+sldestroy(struct sl_softc *sc) {
+	bpfdetach(&sc->sc_if);
+	if_detach(&sc->sc_if);
+	LIST_REMOVE(sc, sl_next);
+	MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE));
+	FREE(sc, M_SL);
 }
 
 /*
@@ -338,13 +403,9 @@
 			untimeout(sl_keepalive, sc, sc->sc_kahandle);
 		}
 		if_down(&sc->sc_if);
-		sc->sc_flags &= SC_STATIC;
 		sc->sc_ttyp = NULL;
 		tp->t_sc = NULL;
-		MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE));
-		sc->sc_ep = 0;
-		sc->sc_mp = 0;
-		sc->sc_buf = 0;
+		sldestroy(sc);
 	}
 	splx(s);
 	return 0;
@@ -363,8 +424,8 @@
 	int flag;
 	struct proc *p;
 {
-	struct sl_softc *sc = (struct sl_softc *)tp->t_sc, *nc, *tmpnc;
-	int s, nsl;
+	struct sl_softc *sc = (struct sl_softc *)tp->t_sc, *nc;
+	int s, unit, wasup;
 
 	s = splimp();
 	switch (cmd) {
@@ -373,44 +434,36 @@
 		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
-				   ) {
-					tmpnc = malloc(sizeof *tmpnc, M_TEMP,
-						       M_NOWAIT);
-					if (tmpnc == NULL) {
+		unit = *(u_int *)data;
+		if (unit < 0) {
+			splx(s);
+			return (ENXIO);
+		}
+		if (sc->sc_if.if_unit != unit) {
+			LIST_FOREACH(nc, &sl_list, sl_next) {
+				if (nc->sc_if.if_unit == *(u_int *)data) {
 						splx(s);
-						return (ENOMEM);
-					}
-					*tmpnc = *nc;
-					*nc = *sc;
-					nc->sc_if = tmpnc->sc_if;
-					tmpnc->sc_if = sc->sc_if;
-					*sc = *tmpnc;
-					free(tmpnc, M_TEMP);
-					if (sc->sc_if.if_flags & IFF_UP) {
-						if_down(&sc->sc_if);
-						if (!(nc->sc_if.if_flags & IFF_UP))
-							if_up(&nc->sc_if);
-					} else if (nc->sc_if.if_flags & IFF_UP)
-						if_down(&nc->sc_if);
-					sc->sc_flags &= ~SC_STATIC;
-					sc->sc_flags |= (nc->sc_flags & SC_STATIC);
-					tp->t_sc = sc = nc;
-					clist_alloc_cblocks(&tp->t_outq,
-					    SLIP_HIWAT + 2 * sc->sc_if.if_mtu + 1,
-					    SLIP_HIWAT + 2 * sc->sc_if.if_mtu + 1);
-					sl_compress_init(&sc->sc_comp, -1);
-					goto slfound;
+						return (ENXIO);
 				}
 			}
-			splx(s);
-			return (ENXIO);
+
+			wasup = sc->sc_if.if_flags & IFF_UP;
+			bpfdetach(&sc->sc_if);
+			if_detach(&sc->sc_if);
+			LIST_REMOVE(sc, sl_next);
+			sc->sc_if.if_unit = unit;
+			LIST_INSERT_HEAD(&sl_list, sc, sl_next);
+			if_attach(&sc->sc_if);
+			bpfattach(&sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
+			if (wasup)
+				if_up(&sc->sc_if);
+			else
+				if_down(&sc->sc_if);
+			clist_alloc_cblocks(&tp->t_outq,
+			    SLIP_HIWAT + 2 * sc->sc_if.if_mtu + 1,
+			    SLIP_HIWAT + 2 * sc->sc_if.if_mtu + 1);
 		}
-	slfound:
-		sc->sc_flags |= SC_STATIC;
+		slmarkstatic(unit);
 		break;
 
 	case SLIOCSKEEPAL:
@@ -470,7 +523,7 @@
 	struct sockaddr *dst;
 	struct rtentry *rtp;
 {
-	register struct sl_softc *sc = &sl_softc[ifp->if_unit];
+	register struct sl_softc *sc = ifp->if_softc;
 	register struct ip *ip;
 	register struct ifqueue *ifq;
 	int s;
@@ -936,6 +989,7 @@
 	register struct ifaddr *ifa = (struct ifaddr *)data;
 	register struct ifreq *ifr = (struct ifreq *)data;
 	register int s, error = 0;
+	struct sl_softc *sc = ifp->if_softc;
 
 	s = splimp();
 
@@ -946,7 +1000,7 @@
 		 * if.c will set the interface up even if we
 		 * don't want it to.
 		 */
-		if (sl_softc[ifp->if_unit].sc_ttyp == NULL) {
+		if (sc->sc_ttyp == NULL) {
 			ifp->if_flags &= ~IFF_UP;
 		}
 		break;
@@ -956,7 +1010,7 @@
 		 * setting the address.
 		 */
 		if (ifa->ifa_addr->sa_family == AF_INET) {
-			if (sl_softc[ifp->if_unit].sc_ttyp != NULL)
+			if (sc->sc_ttyp != NULL)
 				ifp->if_flags |= IFF_UP;
 		} else {
 			error = EAFNOSUPPORT;
@@ -982,7 +1036,7 @@
 			struct tty *tp;
 
 			ifp->if_mtu = ifr->ifr_mtu;
-			tp = sl_softc[ifp->if_unit].sc_ttyp;
+			tp = sc->sc_ttyp;
 			if (tp != NULL)
 				clist_alloc_cblocks(&tp->t_outq,
 				    SLIP_HIWAT + 2 * ifp->if_mtu + 1,
Index: if_slvar.h
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/sys/net/if_slvar.h,v
retrieving revision 1.16
diff -u -r1.16 if_slvar.h
--- if_slvar.h	1999/08/28 00:48:21	1.16
+++ if_slvar.h	2000/03/30 00:06:28
@@ -67,13 +67,13 @@
 	struct	callout_handle	sc_ofhandle;
 	struct	callout_handle	sc_kahandle;
 	struct	slcompress sc_comp;	/* tcp compression data */
+	LIST_ENTRY(sl_softc) sl_next;
 };
 
 /* internal flags */
 #define	SC_ERROR	0x0001		/* had an input error */
 #define	SC_OUTWAIT	0x0002		/* waiting for output fill */
 #define	SC_KEEPALIVE	0x0004		/* input keepalive */
-#define SC_STATIC       0x0008          /* it is static unit */
 
 /* visible flags */
 #define	SC_COMPRESS	IFF_LINK0	/* compress TCP traffic */

>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




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