From brooks@minya.sea.one-eyed-alien.net  Fri Jun  8 19:18:39 2001
Return-Path: <brooks@minya.sea.one-eyed-alien.net>
Received: from minya.sea.one-eyed-alien.net (minya.sea.one-eyed-alien.net [216.39.168.226])
	by hub.freebsd.org (Postfix) with ESMTP id 8E6A037B401
	for <FreeBSD-gnats-submit@freebsd.org>; Fri,  8 Jun 2001 19:18:37 -0700 (PDT)
	(envelope-from brooks@minya.sea.one-eyed-alien.net)
Received: by minya.sea.one-eyed-alien.net (Postfix, from userid 1001)
	id DE1CE24D1F; Fri,  8 Jun 2001 19:20:51 -0700 (PDT)
Message-Id: <20010609022051.DE1CE24D1F@minya.sea.one-eyed-alien.net>
Date: Fri,  8 Jun 2001 19:20:51 -0700 (PDT)
From: Brooks Davis <brooks@one-eyed-alien.net>
Reply-To: Brooks Davis <brooks@one-eyed-alien.net>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [PATCH] make gif fully dynamic
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         27983
>Category:       kern
>Synopsis:       [PATCH] make gif fully dynamic
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    brooks
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jun 08 19:20:01 PDT 2001
>Closed-Date:    Wed Jul 4 14:09:54 PDT 2001
>Last-Modified:  Wed Jul 04 14:10:36 PDT 2001
>Originator:     Brooks Davis
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
The Aerospace Corporation
>Environment:
System: FreeBSD minya.sea.one-eyed-alien.net 5.0-CURRENT FreeBSD 5.0-CURRENT #41: Fri Jun 8 18:53:08 PDT 2001 root@minya.sea.one-eyed-alien.net:/usr/src/sys/compile/MINYA i386


>Description:

Make the gif(4) interface both loadable and demand allocatable.
Add generic ifconfig support to enable similar changes to other pseudo
devices such as lp, faith, ppp, and stf.

>How-To-Repeat:
>Fix:

in /usr/src do "mkdir sys/modules/if_gif" and apply the following patch:

Index: sbin/ifconfig/ifconfig.8
===================================================================
RCS file: /home/ncvs/src/sbin/ifconfig/ifconfig.8,v
retrieving revision 1.41
diff -u -u -r1.41 ifconfig.8
--- sbin/ifconfig/ifconfig.8	2001/06/02 04:09:53	1.41
+++ sbin/ifconfig/ifconfig.8	2001/06/09 01:14:31
@@ -50,6 +50,9 @@
 .Oc
 .Op Ar parameters
 .Nm
+.Fl D
+.Ar interface
+.Nm
 .Fl a
 .Op Fl L
 .Op Fl d
@@ -142,6 +145,16 @@
 .Dq name unit ,
 for example,
 .Dq en0 .
+Generally this device must exist, but some pseudo interfaces support
+creation of demand.
+For those devices, an arbitrary unit number may be specified and the
+interface will be created so long as another parameter is specified.
+Additionally, a wildcard name of the form
+.Dq driver# ,
+for example,
+.Dq gif# ,
+may be specified which will cause a new interface to be created.
+In this case the new interface name will be printed to stdout.
 .El
 .Pp
 The following parameters may be set with 
@@ -537,12 +550,18 @@
 .Nm
 will report only the details specific to that protocol family.
 .Pp
-If the driver does supports the media selection system, the supported
-media list will be included in the output.
+If the
+.Fl D
+flag is passed before an interface name
+.Nm
+will attempt to delete
+the interface via its control device.
 .Pp
 If the
 .Fl m
-flag is passed before an interface name, ifconfig will display all
+flag is passed before an interface name,
+.Nm
+will display all
 of the supported media for the specified interface.
 If
 .Fl L
Index: sbin/ifconfig/ifconfig.c
===================================================================
RCS file: /home/ncvs/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.62
diff -u -u -r1.62 ifconfig.c
--- sbin/ifconfig/ifconfig.c	2001/05/29 09:13:44	1.62
+++ sbin/ifconfig/ifconfig.c	2001/06/09 01:25:27
@@ -104,6 +104,10 @@
 #define	NI_WITHSCOPEID	0
 #endif
 
+#ifndef WILDCARDUNIT
+#define WILDCARDUNIT	'#'
+#endif
+
 struct	ifreq		ifr, ridreq;
 struct	ifaliasreq	addreq;
 #ifdef INET6
@@ -128,6 +132,7 @@
 int	doalias;
 int	clearaddr;
 int	newaddr = 1;
+int	deleteif;
 #ifdef INET6
 static	int ip6lifetime;
 #endif
@@ -150,7 +155,13 @@
 		    struct sockaddr_dl *sdl, struct if_msghdr *ifm,
 		    struct ifa_msghdr *ifam));
 void	usage __P((void));
-void	ifmaybeload __P((char *name));
+void	name2typeunit __P((const char *name, char *type, size_t tlen,
+			    int *unit));
+void	typeunit2name __P((char *name, size_t nlen, const char *type,
+			    int unit));
+void	ifmaybeload __P((const char *name));
+int	ifmaybecreate __P((char *name, size_t len, int trystatic));
+void	ifdelete __P((const char *name));
 
 #ifdef INET6
 int	prefix __P((void *, int));
@@ -350,16 +361,18 @@
 usage()
 {
 #ifndef INET6
-	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
+	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n",
 	"usage: ifconfig interface address_family [address [dest_address]]",
 	"                [parameters]",
+	"       ifconfig -D interface",
 	"       ifconfig -a [-d] [-m] [-u] [address_family]",
 	"       ifconfig -l [-d] [-u] [address_family]",
 	"       ifconfig [-d] [-m] [-u]");
 #else
-	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
+	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n",
 	"usage: ifconfig [-L] interface address_family [address [dest_address]]",
 	"                [parameters]",
+	"       ifconfig -D interface",
 	"       ifconfig -a [-L] [-d] [-m] [-u] [address_family]",
 	"       ifconfig -l [-d] [-u] [address_family]",
 	"       ifconfig [-L] [-d] [-m] [-u]");
@@ -388,7 +401,7 @@
 
 	/* Parse leading line options */
 	all = downonly = uponly = namesonly = 0;
-	while ((c = getopt(argc, argv, "adlmu"
+	while ((c = getopt(argc, argv, "adDlmu"
 #ifdef INET6
 					"L"
 #endif
@@ -411,6 +424,9 @@
 		case 'u':	/* restrict scan to "up" interfaces */
 			uponly++;
 			break;
+		case 'D':	/* delete the specified interface */
+			deleteif++;
+			break;
 		case 'm':	/* show media choices in status */
 			supmedia = 1;
 			break;
@@ -430,10 +446,19 @@
 	if (uponly && downonly)
 		usage();
 
+	/* -D make no sense with any other flags or other then one argument */
+	if (deleteif && (argc != 1 || all || namesonly || uponly ||
+	    downonly || supmedia))
+		usage();
+
 	/* no arguments is equivalent to '-a' */
 	if (!namesonly && argc < 1)
 		all = 1;
 
+	/* -u and -d are meaningless with a specified interface */
+	if (!namesonly && !all && (uponly || downonly))
+		usage();
+
 	/* -a and -l allow an address family arg to limit the output */
 	if (all || namesonly) {
 		if (argc > 1)
@@ -457,8 +482,26 @@
 		strncpy(name, *argv, sizeof(name));
 		argc--, argv++;
 
+		if (deleteif) {
+			ifdelete(name);
+			return 0;
+		}
+
 		/* check and maybe load support for this interface */
 		ifmaybeload(name);
+
+		/*
+		 * If we're actually going to try and do something with
+		 * this device or the user want's a wildcard device, try
+		 * and create it for them.  If we create a wild card
+		 * device and we don't have anything to do with it, just
+		 * return now rather then printing it's status.  This
+		 * insures that wildcard creation prints the device name
+		 * and only the device name.
+		 */
+		if (ifmaybecreate(name, sizeof(name), (argc != 0)) == 2 &&
+		    argc == 0)
+			return 0;
 	}
 
 	/* Check for address family */
@@ -1644,19 +1687,73 @@
 #endif /*INET6*/
 
 void
-ifmaybeload(name)
+name2typeunit(name, type, tlen, unit)
+	const char *name;
+	char *type;
+	size_t tlen;
+	int *unit;
+{
+	char *cp;
+
+	/* copy the type */
+	for (cp = type; !isdigit(name[0]) && name[0] != WILDCARDUNIT &&
+	    name[0] != '\0' && tlen > 0; name++, cp++, tlen--)
+		cp[0] = name[0];
+	if (tlen == 0) {
+		goto error;
+	}
+
+	/* figure out the unit */
+	if (name[0] == WILDCARDUNIT) {
+		*unit = -1;
+		name++;
+	} else if (isdigit(name[0])) {
+		*unit = atoi(name);
+		for (; isdigit(name[0]); name++);
+	} else {
+		goto error;
+	}
+
+	if (name[0] != '\0')
+		goto error;
+
+	return;
+
+error:
+	type[0] = '\0';
+}
+
+void
+typeunit2name(name, nlen, type, unit)
 	char *name;
+	size_t nlen;
+	const char *type;
+	int unit;
+{
+	if(nlen <= 0)
+		return;
+
+	if(snprintf(name, nlen, "%s%d", type, unit) > nlen-1) {
+		/* just null the name if it doesn't fit */
+		name[0] = '\0';
+	}
+}
+
+void
+ifmaybeload(name)
+	const char *name;
 {
 	struct module_stat mstat;
-	int fileid, modid;
-	char ifkind[35], *cp, *dp;
+	int fileid, modid, unit;
+	char ifkind[35], type[35], *cp;
 
 
 	/* turn interface and unit into module name */
-	strcpy(ifkind, "if_");
-	for (cp = name, dp = ifkind + 3; (*cp != 0) && !isdigit(*cp); cp++, dp++)
-		*dp = *cp;
-	*dp = 0;
+	name2typeunit(name, type, sizeof(type), &unit);
+	if (type[0] == '\0')
+		return;
+	if (snprintf(ifkind, sizeof(ifkind), "if_%s", type) >= sizeof(ifkind))
+		return;
 
 	/* scan files in kernel */
 	mstat.version = sizeof(struct module_stat);
@@ -1680,4 +1777,98 @@
 
 	/* not present, we should try to load it */
 	kldload(ifkind);
+}
+
+/*
+ * Try to create the interface through a control node.  If nothing is
+ * created, return 0.  If a static interface is created return 1.  If a
+ * wildcard interface is created, return 2.
+ */
+int
+ifmaybecreate(name, len, trystatic)
+	char *name;
+	size_t len;
+	int trystatic;
+{
+	char if_dev[40];
+	int d;
+	int wildcard = 0;
+	struct if_manage ifman;
+
+	bzero(&ifman, sizeof(ifman));
+
+	/* turn interface and unit into control device name */
+	name2typeunit(name, ifman.ifman_name, sizeof(ifman.ifman_name),
+	    &ifman.ifman_unit);
+	if (ifman.ifman_name[0] == '\0')
+		return (0);
+	if (ifman.ifman_unit >= 0 && !trystatic)
+		return (0);
+	if (snprintf(if_dev, sizeof(if_dev), "/dev/if_%s",
+	    ifman.ifman_name) >= sizeof(if_dev))
+		return (0);
+	if (ifman.ifman_unit < 0)
+		wildcard = 1;
+
+	/* try to open the control device */
+	d = open(if_dev, O_RDWR);
+	if (d == -1)
+		return (0);
+
+	/* try to create the device in question */
+	ifman.ifman_action = IFMAN_CREATE;
+	if (ioctl(d, IOCIFMANAGE, &ifman) == -1) {
+		close(d);
+		return (0);
+	}
+	close(d);
+
+	/*
+	 * our name might have been changed (in the wildcard case) so
+	 * update it.
+	 * XXX: if the device is on crack and mangles non-wildcard
+	 * units, this could be weird.
+	 */
+	typeunit2name(name, len, ifman.ifman_name, ifman.ifman_unit);
+
+	if (name[0] != '\0' && wildcard) {
+		printf("%s\n", name);
+		return (2);
+	}
+
+	return (1);
+}
+
+void
+ifdelete(name)
+	const char *name;
+{
+	char if_dev[40];
+	int d;
+	struct if_manage ifman;
+
+	bzero(&ifman, sizeof(ifman));
+
+	ifman.ifman_action = IFMAN_DELETE;
+	name2typeunit(name, ifman.ifman_name, sizeof(ifman.ifman_name),
+	    &ifman.ifman_unit);
+	if (ifman.ifman_name[0] == '\0')
+		errx(1, "invalid interface");
+	if (ifman.ifman_unit < 0)
+		errx(1, "can't delete wildcard interface");
+	if (snprintf(if_dev, sizeof(if_dev), "/dev/if_%s",
+	    ifman.ifman_name) >= sizeof(if_dev))
+		return;
+
+	/* try to open the control device */
+	d = open(if_dev, O_RDWR);
+	if (d == -1)
+		return;
+
+	/* try to create the device in question */
+	if (ioctl(d, IOCIFMANAGE, &ifman) == -1) {
+		close(d);
+		err(1, "IOCIFMANAGE error");
+	}
+	close(d);
 }
Index: sys/conf/files
===================================================================
RCS file: /home/ncvs/src/sys/conf/files,v
retrieving revision 1.530
diff -u -u -r1.530 files
--- sys/conf/files	2001/06/05 04:26:12	1.530
+++ sys/conf/files	2001/06/08 19:48:21
@@ -881,7 +881,7 @@
 net/if_ethersubr.c	optional ether
 net/if_faith.c		count faith
 net/if_fddisubr.c	optional fddi
-net/if_gif.c		count gif
+net/if_gif.c		optional gif
 net/if_iso88025subr.c	optional token
 net/if_loop.c		optional loop
 net/if_media.c		standard
Index: sys/conf/majors
===================================================================
RCS file: /home/ncvs/src/sys/conf/majors,v
retrieving revision 1.124
diff -u -u -r1.124 majors
--- sys/conf/majors	2001/05/29 18:49:46	1.124
+++ sys/conf/majors	2001/06/07 23:58:18
@@ -179,6 +179,7 @@
 160	spic		Sony Programmable I/O Controller (jogdial)
 161	swdoc		Sitara networks watchdog device
 162	digi		Digiboard
+163	if_gif		Generic Tunneling control device
 200	??		entries from 200-252 are reserved for local use
 252	??		entries from 200-252 are reserved for local use
 254	internal	Used internally by the kernel
Index: sys/i386/conf/GENERIC
===================================================================
RCS file: /home/ncvs/src/sys/i386/conf/GENERIC,v
retrieving revision 1.311
diff -u -u -r1.311 GENERIC
--- sys/i386/conf/GENERIC	2001/05/30 03:18:22	1.311
+++ sys/i386/conf/GENERIC	2001/06/08 23:16:04
@@ -210,7 +210,7 @@
 device		tun		# Packet tunnel.
 device		pty		# Pseudo-ttys (telnet etc)
 device		md		# Memory "disks"
-device		gif	4	# IPv6 and IPv4 tunneling
+device		gif		# IPv6 and IPv4 tunneling
 device		faith	1	# IPv6-to-IPv4 relaying (translation)
 
 # The `bpf' device enables the Berkeley Packet Filter.
Index: sys/ia64/conf/GENERIC
===================================================================
RCS file: /home/ncvs/src/sys/ia64/conf/GENERIC,v
retrieving revision 1.10
diff -u -u -r1.10 GENERIC
--- sys/ia64/conf/GENERIC	2001/05/29 18:49:03	1.10
+++ sys/ia64/conf/GENERIC	2001/06/09 00:55:41
@@ -140,7 +140,7 @@
 device		tun		# Packet tunnel.
 device		pty		# Pseudo-ttys (telnet etc)
 device		md		# Memory "disks"
-device		gif	4	# IPv6 and IPv4 tunneling
+device		gif		# IPv6 and IPv4 tunneling
 device		faith	1	# IPv6-to-IPv4 relaying/(translation)
 
 # The `bpf' device enables the Berkeley Packet Filter.
Index: sys/alpha/conf/GENERIC
===================================================================
RCS file: /home/ncvs/src/sys/alpha/conf/GENERIC,v
retrieving revision 1.113
diff -u -u -r1.113 GENERIC
--- sys/alpha/conf/GENERIC	2001/05/30 03:19:05	1.113
+++ sys/alpha/conf/GENERIC	2001/06/09 00:55:14
@@ -165,7 +165,7 @@
 device		tun		# Packet tunnel.
 device		pty		# Pseudo-ttys (telnet etc)
 device		md		# Memory "disks"
-device		gif	4	# IPv6 and IPv4 tunneling
+device		gif		# IPv6 and IPv4 tunneling
 device		faith	1	# IPv6-to-IPv4 relaying/(translation)
 
 # The `bpf' device enables the Berkeley Packet Filter.
Index: sys/net/if_gif.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_gif.c,v
retrieving revision 1.9
diff -u -u -r1.9 if_gif.c
--- sys/net/if_gif.c	2001/06/03 17:31:11	1.9
+++ sys/net/if_gif.c	2001/06/08 23:52:55
@@ -1,4 +1,4 @@
-/*	$FreeBSD: src/sys/net/if_gif.c,v 1.9 2001/06/03 17:31:11 yar Exp $	*/
+/*	$FreeBSD: src/sys/net/if_gif.c,v 1.9 2001/06/03 17:31:11 yar Exp $ */
 /*	$KAME: if_gif.c,v 1.28 2000/06/20 12:30:03 jinmei Exp $	*/
 
 /*
@@ -44,6 +44,9 @@
 #include <sys/time.h>
 #include <sys/syslog.h>
 #include <sys/protosw.h>
+#include <sys/conf.h>
+#include <machine/bus.h>	/* XXX: Shouldn't really be required! */
+#include <sys/rman.h>
 #include <machine/cpu.h>
 
 #include <net/if.h>
@@ -58,6 +61,8 @@
 #include <netinet/in_var.h>
 #include <netinet/ip.h>
 #include <netinet/in_gif.h>
+#include <netinet/ip_var.h>
+#include <netinet/ipprotosw.h>
 #endif	/* INET */
 
 #ifdef INET6
@@ -74,28 +79,68 @@
 #include <netinet/ip_encap.h>
 #include <net/if_gif.h>
 
-#include "gif.h"
+#if defined(__FreeBSD__)
+#define NBPFILTER	1
+#else
 #include "bpf.h"
 #define NBPFILTER	NBPF
+#endif
 
 #include <net/net_osdep.h>
-
-#if NGIF > 0
 
-void gifattach __P((void *));
+#define GIFNAME		"gif"
+#define GIFDEV		"if_gif"
+#define GIF_MAXUNIT	0x7fff	/* ifp->if_unit is only 15 bits */
+
+static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
+static struct rman gifunits[1];
+TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs);
+
+static int gifcreate __P((int *));
+static int gifdelete __P((int));
+static int gifmodevent __P((module_t, int, void *));
+static struct gif_softc *gifunit2sc __P((int unit));
 static int gif_encapcheck __P((const struct mbuf *, int, int, void *));
-#ifdef INET
-extern struct protosw in_gif_protosw;
-#endif
-#ifdef INET6
-extern struct ip6protosw in6_gif_protosw;
-#endif
 
-/*
- * gif global variable definitions
- */
-static int ngif;		/* number of interfaces */
-static struct gif_softc *gif = 0;
+#ifdef INET
+extern  struct domain inetdomain;
+struct ipprotosw in_gif_protosw =
+{ SOCK_RAW,	&inetdomain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
+  in_gif_input,	rip_output,	0,		rip_ctloutput,
+  0,
+  0,		0,		0,		0,
+  &rip_usrreqs
+};
+#endif
+#ifdef INET6
+extern  struct domain6 inet6domain;
+struct ip6protosw in6_gif_protosw =
+{ SOCK_RAW,	&inet6domain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
+  in6_gif_input, rip6_output,	0,		rip6_ctloutput,
+  0,
+  0,		0,		0,		0,
+  &rip6_usrreqs
+};
+#endif
+
+static d_ioctl_t	gifioctl;
+
+#define CDEV_MAJOR 163
+static struct cdevsw gif_cdevsw = {
+	/* open */	nullopen,
+	/* close */	nullclose,
+	/* read */	noread,
+	/* write */	nowrite,
+	/* ioctl */	gifioctl,
+	/* poll */	nopoll,
+	/* mmap */	nommap,
+	/* strategy */	nostrategy,
+	/* name */	GIFDEV,
+	/* maj */	CDEV_MAJOR,
+	/* dump */	nodump,
+	/* psize */	nopsize,
+	/* flags */	0,
+};
 
 #ifndef MAX_GIF_NEST
 /*
@@ -110,62 +155,252 @@
 #endif
 static int max_gif_nesting = MAX_GIF_NEST;
 
-void
-gifattach(dummy)
-	void *dummy;
+static struct gif_softc *
+gifunit2sc(unit)
+	int unit;
 {
-	register struct gif_softc *sc;
-	register int i;
+	struct gif_softc *sc;
+
+	TAILQ_FOREACH(sc, &gifs, gif_link) {
+		if (sc->gif_if.if_unit == unit)
+			break;
+	}
+	if (sc->gif_if.if_unit != unit)
+		return NULL;
+
+	return sc;
+}
+
+static int
+gifcreate(unit)
+	int *unit;
+{
+	struct resource *r;
+	struct gif_softc *sc;
+
+	if (*unit > GIF_MAXUNIT)
+		return (ENXIO);
 
-	ngif = NGIF;
-	gif = sc = malloc (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
-	bzero(sc, ngif * sizeof(struct gif_softc));
-	for (i = 0; i < ngif; sc++, i++) {
-		sc->gif_if.if_name = "gif";
-		sc->gif_if.if_unit = i;
+	if (*unit < 0) {
+		r = rman_reserve_resource(gifunits, 0, GIF_MAXUNIT, 1,
+		    RF_ALLOCATED | RF_ACTIVE, NULL);
+		if (r == NULL)
+			return (ENOSPC);
+		*unit = rman_get_start(r);
+	} else {
+		r = rman_reserve_resource(gifunits, *unit, *unit, 1,
+		    RF_ALLOCATED | RF_ACTIVE, NULL);
+		if (r == NULL)
+			return (EBUSY);
+	}
+
+	sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK);
+	bzero(sc, sizeof(struct gif_softc));
+	sc->gif_if.if_softc = sc;
+	sc->gif_if.if_name = GIFNAME;
+	sc->gif_if.if_unit = *unit;
+	sc->r_unit = r;
 
-		sc->encap_cookie4 = sc->encap_cookie6 = NULL;
+	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
 #ifdef INET
-		sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
-		    gif_encapcheck, &in_gif_protosw, sc);
-		if (sc->encap_cookie4 == NULL) {
-			printf("%s: attach failed\n", if_name(&sc->gif_if));
-			continue;
-		}
+	sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
+	    gif_encapcheck, &in_gif_protosw, sc);
+	if (sc->encap_cookie4 == NULL) {
+		free(sc, M_GIF);
+		return (ENOMEM);
+	}
 #endif
 #ifdef INET6
-		sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
-		    gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc);
-		if (sc->encap_cookie6 == NULL) {
-			if (sc->encap_cookie4) {
-				encap_detach(sc->encap_cookie4);
-				sc->encap_cookie4 = NULL;
-			}
-			printf("%s: attach failed\n", if_name(&sc->gif_if));
-			continue;
+	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
+	    gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc);
+	if (sc->encap_cookie6 == NULL) {
+		if (sc->encap_cookie4) {
+			encap_detach(sc->encap_cookie4);
+			sc->encap_cookie4 = NULL;
 		}
+		free(sc, M_GIF);
+		return (ENOMEM);
+	}
 #endif
 
-		sc->gif_if.if_mtu    = GIF_MTU;
-		sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
-		sc->gif_if.if_ioctl  = gif_ioctl;
-		sc->gif_if.if_output = gif_output;
-		sc->gif_if.if_type   = IFT_GIF;
-		sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
-		if_attach(&sc->gif_if);
+	sc->gif_if.if_mtu    = GIF_MTU;
+	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
+	sc->gif_if.if_ioctl  = gif_ifioctl;
+	sc->gif_if.if_output = gif_output;
+	sc->gif_if.if_type   = IFT_GIF;
+	sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
+	if_attach(&sc->gif_if);
 #if NBPFILTER > 0
 #ifdef HAVE_OLD_BPF
-		bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
+	bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
 #else
-		bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL, sizeof(u_int));
+	bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL, sizeof(u_int));
+#endif
+#endif
+
+	TAILQ_INSERT_TAIL(&gifs, sc, gif_link);
+
+	return (0);
+}
+
+static int
+gifdelete(unit)
+	int unit;
+{
+	int err;
+	struct gif_softc *sc;
+
+	sc = gifunit2sc(unit);
+	if (sc == NULL)
+		return (ENXIO);
+
+	bpfdetach(&sc->gif_if);
+	if_detach(&sc->gif_if);
+
+	if (sc->encap_cookie4 != NULL) {
+		err = encap_detach(sc->encap_cookie4);
+		KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
+	}
+	if (sc->encap_cookie6 != NULL) {
+		err = encap_detach(sc->encap_cookie6);
+		KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
+	}
+
+	if (sc->gif_psrc)
+		free((caddr_t)sc->gif_psrc, M_IFADDR);
+	if (sc->gif_pdst)
+		free((caddr_t)sc->gif_pdst, M_IFADDR);
+
+	err = rman_release_resource(sc->r_unit);
+	KASSERT(err == 0, ("Unexpected error freeing resource"));
+
+	TAILQ_REMOVE(&gifs, sc, gif_link);
+	free(sc, M_GIF);
+
+	return 0;
+}
+
+static int
+gifmodevent(mod, type, data)
+	module_t mod;
+	int type;
+	void *data;
+{
+	static dev_t dev;
+	int err;
+
+	switch (type) {
+	case MOD_LOAD:
+		if (!devfs_present) {
+			err = cdevsw_add(&gif_cdevsw);
+			if (err != 0) {
+				return (err);
+			}
+		}
+		gifunits->rm_type = RMAN_ARRAY;
+		gifunits->rm_descr = "configurable if_gif units";
+		err = rman_init(gifunits);
+		if (err != 0) {
+			if (!devfs_present)
+				cdevsw_remove(&gif_cdevsw);
+			return (err);
+		}
+		err = rman_manage_region(gifunits, 0, GIF_MAXUNIT);
+		if (err != 0) {
+			printf("%s: gifunits: rman_manage_region: Failed %d\n",
+			    GIFNAME, err);
+			rman_fini(gifunits);
+			if (!devfs_present)
+				cdevsw_remove(&gif_cdevsw);
+			return (err);
+		}
+		dev = make_dev(&gif_cdevsw, unit2minor(0),
+		    UID_ROOT, GID_WHEEL, 0600, GIFDEV, 0);
+
+#ifdef INET6
+		ip6_gif_hlim = GIF_HLIM;
 #endif
+
+		break;
+	case MOD_UNLOAD:
+		destroy_dev(dev);
+
+		while (!TAILQ_EMPTY(&gifs))
+			gifdelete(TAILQ_FIRST(&gifs)->gif_if.if_unit);
+
+		err = rman_fini(gifunits);
+		if (err != 0)
+			return (err);
+
+		if (!devfs_present)
+			cdevsw_remove(&gif_cdevsw);
+
+#ifdef INET6
+		ip6_gif_hlim = 0;
 #endif
+		break;
 	}
+	return 0;
 }
+
+static moduledata_t gif_mod = {
+	"if_gif",
+	gifmodevent,
+	0
+};
 
-PSEUDO_SET(gifattach, if_gif);
+DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
 
 static int
+gifioctl(dev, cmd, data, flag, p)
+	dev_t dev;
+	u_long cmd;
+	caddr_t data;
+	int flag;
+	struct proc *p;
+{
+	int err;
+	struct if_manage *ifman;
+	struct gif_softc *sc;
+
+	/* all actions require root, so check now. */
+	err = suser(p);
+	if (err != 0)
+		return (err);
+
+	switch (cmd) {
+	case IOCIFMANAGE:
+		ifman = (void*)data;
+		switch (ifman->ifman_action) {
+		case IFMAN_CREATE:
+			if (strcmp(GIFNAME, ifman->ifman_name) != 0)
+				return (EINVAL);
+			err = gifcreate(&ifman->ifman_unit);
+			if (err != 0)
+				return (err);
+			break;
+		case IFMAN_DELETE:
+			sc = gifunit2sc(ifman->ifman_unit);
+			if (sc == NULL)
+				return (ENXIO);
+			if (sc->gif_if.if_flags & IFF_UP)
+				return (EBUSY);
+			err = gifdelete(ifman->ifman_unit);
+			if(err != 0)
+				return (err);
+			break;
+		default:
+			return (EINVAL);
+		}
+		break;
+	default:
+		return (ENOTTY);
+	}
+
+	return (0);
+}
+
+static int
 gif_encapcheck(m, off, proto, arg)
 	const struct mbuf *m;
 	int off;
@@ -390,7 +625,7 @@
 
 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
 int
-gif_ioctl(ifp, cmd, data)
+gif_ifioctl(ifp, cmd, data)
 	struct ifnet *ifp;
 	u_long cmd;
 	caddr_t data;
@@ -400,8 +635,8 @@
 	int error = 0, size;
 	struct sockaddr *dst, *src;
 	struct sockaddr *sa;
-	int i;
 	int s;
+	struct ifnet *ifp2;
 	struct gif_softc *sc2;
 		
 	switch (cmd) {
@@ -451,9 +686,12 @@
 			break;
 #endif
 		}
+
+		TAILQ_FOREACH(ifp2, &ifnet, if_link) {
+			if (strcmp(ifp2->if_name, GIFNAME) != 0)
+				continue;
+			sc2 = ifp2->if_softc;
 
-		for (i = 0; i < ngif; i++) {
-			sc2 = gif + i;
 			if (sc2 == sc)
 				continue;
 			if (!sc2->gif_pdst || !sc2->gif_psrc)
@@ -623,4 +861,3 @@
  bad:
 	return error;
 }
-#endif /*NGIF > 0*/
Index: sys/net/if_gif.h
===================================================================
RCS file: /home/ncvs/src/sys/net/if_gif.h,v
retrieving revision 1.3
diff -u -u -r1.3 if_gif.h
--- sys/net/if_gif.h	2000/07/04 16:35:04	1.3
+++ sys/net/if_gif.h	2001/06/08 17:20:27
@@ -62,6 +62,8 @@
 	int		gif_flags;
 	const struct encaptab *encap_cookie4;
 	const struct encaptab *encap_cookie6;
+	struct resource *r_unit;	/* resource allocated for this unit */
+	TAILQ_ENTRY(gif_softc) gif_link; /* all gif's are linked */
 };
 
 #define gif_ro gifsc_gifscr.gifscr_ro
@@ -77,6 +79,6 @@
 void gif_input __P((struct mbuf *, int, struct ifnet *));
 int gif_output __P((struct ifnet *, struct mbuf *,
 		    struct sockaddr *, struct rtentry *));
-int gif_ioctl __P((struct ifnet *, u_long, caddr_t));
+int gif_ifioctl __P((struct ifnet *, u_long, caddr_t));
 
 #endif /* _NET_IF_GIF_H_ */
Index: sys/net/if.h
===================================================================
RCS file: /home/ncvs/src/sys/net/if.h,v
retrieving revision 1.61
diff -u -u -r1.61 if.h
--- sys/net/if.h	2001/02/21 06:39:56	1.61
+++ sys/net/if.h	2001/06/08 02:01:44
@@ -241,6 +241,18 @@
 	struct	sockaddr_storage dstaddr; /* out */
 };
 
+/*
+ * Structure and definiation for IOCIFMANAGE
+ */
+struct if_manage {
+	int	ifman_action;
+#define IFMAN_CREATE	0
+#define IFMAN_DELETE	1
+	char	ifman_name[IFNAMSIZ];
+	int	ifman_unit;
+};
+#define IOCIFMANAGE	_IOWR('i', 190, struct if_manage)
+
 #ifdef _KERNEL
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_IFADDR);
Index: sys/net/if_stf.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_stf.c,v
retrieving revision 1.6
diff -u -u -r1.6 if_stf.c
--- sys/net/if_stf.c	2001/02/03 11:46:35	1.6
+++ sys/net/if_stf.c	2001/06/08 19:41:26
@@ -102,7 +102,6 @@
 
 #include <netinet/ip6.h>
 #include <netinet6/ip6_var.h>
-#include <netinet6/in6_gif.h>
 #include <netinet6/in6_var.h>
 #include <netinet/ip_ecn.h>
 
@@ -115,16 +114,11 @@
 #include "bpf.h"
 #define NBPFILTER	NBPF
 #include "stf.h"
-#include "gif.h"	/*XXX*/
 
 #if NBPFILTER > 0
 #include <net/bpf.h>
 #endif
 
-#if NGIF > 0
-#include <net/if_gif.h>
-#endif
-
 #if NSTF > 0
 #if NSTF != 1
 # error only single stf interface allowed
@@ -146,11 +140,7 @@
 static struct stf_softc *stf;
 static int nstf;
 
-#if NGIF > 0
-extern int ip_gif_ttl;	/*XXX*/
-#else
-static int ip_gif_ttl = 40;	/*XXX*/
-#endif
+static int ip_stf_ttl = 40;
 
 extern struct protosw in_stf_protosw;
 
@@ -364,7 +354,7 @@
 	    &ip->ip_src, sizeof(ip->ip_src));
 	bcopy(GET_V4(&dst6->sin6_addr), &ip->ip_dst, sizeof(ip->ip_dst));
 	ip->ip_p = IPPROTO_IPV6;
-	ip->ip_ttl = ip_gif_ttl;	/*XXX*/
+	ip->ip_ttl = ip_stf_ttl;
 	ip->ip_len = m->m_pkthdr.len;	/*host order*/
 	if (ifp->if_flags & IFF_LINK1)
 		ip_ecn_ingress(ECN_ALLOWED, &ip->ip_tos, &tos);
Index: sys/netinet/in.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in.c,v
retrieving revision 1.53
diff -u -u -r1.53 in.c
--- sys/netinet/in.c	2001/05/11 14:37:34	1.53
+++ sys/netinet/in.c	2001/06/08 19:47:09
@@ -51,11 +51,6 @@
 
 #include <netinet/igmp_var.h>
 
-#include "gif.h"
-#if NGIF > 0
-#include <net/if_gif.h>
-#endif
-
 static MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address");
 
 static int in_mask2len __P((struct in_addr *));
@@ -200,7 +195,6 @@
 	int error, hostIsNew, maskIsNew, s;
 	u_long i;
 
-#if NGIF > 0
         if (ifp && ifp->if_type == IFT_GIF) {
                 switch (cmd) {
                 case SIOCSIFPHYADDR:
@@ -210,10 +204,9 @@
         			return(error);
                 case SIOCGIFPSRCADDR:
                 case SIOCGIFPDSTADDR:
-                        return gif_ioctl(ifp, cmd, data);
+                        return ifp->if_ioctl(ifp, cmd, data);
                 }
         }
-#endif
 
 	switch (cmd) {
 	case SIOCALIFADDR:
Index: sys/netinet/in_gif.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in_gif.c,v
retrieving revision 1.9
diff -u -u -r1.9 in_gif.c
--- sys/netinet/in_gif.c	2001/02/04 16:08:12	1.9
+++ sys/netinet/in_gif.c	2001/06/08 19:53:37
@@ -67,17 +67,11 @@
 
 #include <net/if_gif.h>	
 
-#include "gif.h"
-
 #include <machine/stdarg.h>
 
 #include <net/net_osdep.h>
 
-#if NGIF > 0
 int ip_gif_ttl = GIF_TTL;
-#else
-int ip_gif_ttl = 0;
-#endif
 SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
 	&ip_gif_ttl,	0, "");
 
Index: sys/netinet/in_proto.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in_proto.c,v
retrieving revision 1.55
diff -u -u -r1.55 in_proto.c
--- sys/netinet/in_proto.c	2000/08/03 14:09:52	1.55
+++ sys/netinet/in_proto.c	2001/06/08 19:36:40
@@ -77,11 +77,6 @@
 #endif
 #endif /* IPSEC */
 
-#include "gif.h"
-#if NGIF > 0
-#include <netinet/in_gif.h>
-#endif
-
 #include "stf.h"
 #if NSTF > 0
 #include <net/if_stf.h>
@@ -205,16 +200,6 @@
   &rip_usrreqs
 },
 };
-
-#if NGIF > 0
-struct ipprotosw in_gif_protosw =
-{ SOCK_RAW,	&inetdomain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
-  in_gif_input, rip_output,	0,		rip_ctloutput,
-  0,
-  0,            0,              0,              0,
-  &rip_usrreqs
-};
-#endif /*NGIF*/
 
 #if NSTF > 0
 struct ipprotosw in_stf_protosw =
Index: sys/netinet6/in6.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/in6.c,v
retrieving revision 1.11
diff -u -u -r1.11 in6.c
--- sys/netinet6/in6.c	2001/01/18 06:07:53	1.11
+++ sys/netinet6/in6.c	2001/06/09 00:01:41
@@ -97,11 +97,6 @@
 #include <netinet6/in6_ifattach.h>
 #include <netinet6/scope6_var.h>
 
-#include "gif.h"
-#if NGIF > 0
-#include <net/if_gif.h>
-#endif
-
 #include <net/net_osdep.h>
 
 MALLOC_DEFINE(M_IPMADDR, "in6_multi", "internet multicast address");
@@ -343,7 +338,6 @@
 	/*
 	 * xxx should prevent processes for link-local addresses?
 	 */
-#if NGIF > 0
 	if (ifp && ifp->if_type == IFT_GIF) {
 		switch (cmd) {
 		case SIOCSIFPHYADDR_IN6:
@@ -352,10 +346,10 @@
 			/*fall through*/
 		case SIOCGIFPSRCADDR_IN6:
 		case SIOCGIFPDSTADDR_IN6:
-			return gif_ioctl(ifp, cmd, data);
+			return ifp->if_ioctl(ifp, cmd, data);
 		}
 	}
-#endif
+
 	switch (cmd) {
 	case SIOCGETSGCNT_IN6:
 	case SIOCGETMIFCNT_IN6:
Index: sys/netinet6/in6_proto.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/in6_proto.c,v
retrieving revision 1.12
diff -u -u -r1.12 in6_proto.c
--- sys/netinet6/in6_proto.c	2001/06/01 09:51:14	1.12
+++ sys/netinet6/in6_proto.c	2001/06/08 23:31:49
@@ -122,11 +122,6 @@
 
 #include <netinet6/ip6protosw.h>
 
-#include "gif.h"
-#if NGIF > 0
-#include <netinet6/in6_gif.h>
-#endif
-
 #include <net/net_osdep.h>
 
 /*
@@ -244,16 +239,6 @@
 },
 };
 
-#if NGIF > 0
-struct ip6protosw in6_gif_protosw =
-{ SOCK_RAW,	&inet6domain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
-  in6_gif_input, rip6_output,	0,		rip6_ctloutput,
-  0,
-  0,            0,              0,              0,
-  &rip6_usrreqs
-};
-#endif /*NGIF*/
-
 extern int in6_inithead __P((void **, int));
 
 struct domain inet6domain =
@@ -292,11 +277,7 @@
 int	ip6_dad_count = 1;	/* DupAddrDetectionTransmits */
 u_int32_t ip6_flow_seq;
 int	ip6_auto_flowlabel = 1;
-#if NGIF > 0
-int	ip6_gif_hlim = GIF_HLIM;
-#else
 int	ip6_gif_hlim = 0;
-#endif
 int	ip6_use_deprecated = 1;	/* allow deprecated addr (RFC2462 5.5.4) */
 int	ip6_rr_prune = 5;	/* router renumbering prefix
 				 * walk list every 5 sec.    */
Index: sys/netinet6/ip6_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.26
diff -u -u -r1.26 ip6_input.c
--- sys/netinet6/ip6_input.c	2001/05/22 17:32:02	1.26
+++ sys/netinet6/ip6_input.c	2001/06/08 23:41:41
@@ -113,7 +113,6 @@
 #include <netinet6/ip6protosw.h>
 
 #include "faith.h"
-#include "gif.h"
 
 #include <net/net_osdep.h>
 
Index: sys/modules/Makefile
===================================================================
RCS file: /home/ncvs/src/sys/modules/Makefile,v
retrieving revision 1.183
diff -u -u -r1.183 Makefile
--- sys/modules/Makefile	2001/05/31 21:44:19	1.183
+++ sys/modules/Makefile	2001/06/09 01:04:54
@@ -8,6 +8,7 @@
 
 SUBDIR=	3dfx accf_data accf_http agp aha amr an aue \
 	cam ccd cd9660 coda cue dc de dgm digi ed fdescfs fxp if_disc if_ef \
+	if_gif \
 	if_ppp if_sl if_tap if_tun ip6fw ipfilter ipfw ispfw joy kue lge \
 	libmchain linux lnc md mii mlx msdosfs ncp netgraph nfs nge ntfs \
 	nullfs nwfs pcn portalfs procfs ${_random}  \
--- sys/modules/if_gif/Makefile.orig	Fri Jun  8 19:00:25 2001
+++ sys/modules/if_gif/Makefile	Fri Jun  8 19:04:43 2001
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../net ${.CURDIR}/../../netinet ${.CURDIR}/../../netinet6
+
+KMOD=	if_gif
+SRCS=	if_gif.c in_gif.c in6_gif.c opt_inet.h opt_inet6.h opt_mrouting.h
+NOMAN=
+
+opt_inet.h:
+	echo "#define INET 1" > ${.TARGET}
+
+opt_inet6.h:
+	echo "#define INET6 1" > ${.TARGET}
+
+opt_mrouting.h:
+	echo "#define MROUTING 1" > ${.TARGET}
+
+.include <bsd.kmod.mk>
>Release-Note:
>Audit-Trail:

From: Brooks Davis <brooks@one-eyed-alien.net>
To: bugs@freebsd.org
Cc: FreeBSD-gnats-submit@freebsd.org
Subject: Re: kern/27983: [PATCH] make gif fully dynamic
Date: Sat, 9 Jun 2001 21:19:02 -0700

 I've created an updated patch which corrects a return code for the ioctl
 and changes to syntax for creation and deletion to the Solaris like
 plumb and unplumb commands.  It also doesn't break existing scripts like
 the old one did.  As before, apply with:
 
 cd /usr/src
 mkdir sys/modules/if_gif
 patch < /tmp/gif.diff
 
 The patch is online at:
 
 http://www.one-eyed-alien.net/~brooks/FreeBSD/gif.diff
 
 -- Brooks
Responsible-Changed-From-To: freebsd-bugs->brooks 
Responsible-Changed-By: brooks 
Responsible-Changed-When: Thu Jun 21 13:34:24 PDT 2001 
Responsible-Changed-Why:  
Handle my own PR. 

http://www.FreeBSD.org/cgi/query-pr.cgi?pr=27983 
State-Changed-From-To: open->closed 
State-Changed-By: brooks 
State-Changed-When: Wed Jul 4 14:09:54 PDT 2001 
State-Changed-Why:  
Committed a much improved version of the patch. 


http://www.FreeBSD.org/cgi/query-pr.cgi?pr=27983 
>Unformatted:
