? modules/ipdivert
Index: kern/uipc_domain.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/uipc_domain.c,v
retrieving revision 1.36
diff -u -p -r1.36 uipc_domain.c
--- kern/uipc_domain.c	5 Apr 2004 21:03:36 -0000	1.36
+++ kern/uipc_domain.c	18 Oct 2004 21:24:35 -0000
@@ -70,8 +70,22 @@ struct mtx dom_mtx;		/* domain list lock
 MTX_SYSINIT(domain, &dom_mtx, "domain list", MTX_DEF);
 
 /*
+ * Dummy protocol specific user requests function pointer array.
+ * All functions return EOPNOTSUPP.
+ */
+struct pr_usrreqs nousrreqs = {
+        pru_abort_notsupp, pru_accept_notsupp, pru_attach_notsupp,
+        pru_bind_notsupp, pru_connect_notsupp, pru_connect2_notsupp,
+        pru_control_notsupp, pru_detach_notsupp, pru_disconnect_notsupp,
+        pru_listen_notsupp, pru_peeraddr_notsupp, pru_rcvd_notsupp,
+        pru_rcvoob_notsupp, pru_send_notsupp, pru_sense_null,
+        pru_shutdown_notsupp, pru_sockaddr_notsupp, pru_sosend_notsupp,
+        pru_soreceive_notsupp, pru_sopoll_notsupp, pru_sosetlabel_null
+};
+
+/*
  * Add a new protocol domain to the list of supported domains
- * Note: you cant unload it again because  a socket may be using it.
+ * Note: you cant unload it again because a socket may be using it.
  * XXX can't fail at this time.
  */
 static void
@@ -98,7 +112,7 @@ net_init_domain(struct domain *dp)
 
 /*
  * Add a new protocol domain to the list of supported domains
- * Note: you cant unload it again because  a socket may be using it.
+ * Note: you cant unload it again because a socket may be using it.
  * XXX can't fail at this time.
  */
 void
@@ -188,6 +202,126 @@ found:
 			maybe = pr;
 	}
 	return (maybe);
+}
+
+/*
+ * The caller must make sure that the new protocol is fully set up and ready to
+ * accept requests before it is registered.
+ */
+int
+pf_proto_register(family, npr)
+	int family;
+	struct protosw *npr;
+{
+	struct domain *dp;
+	struct protosw *pr, *fpr;
+
+	/* Sanity checks. */
+	if (family == 0)
+		return (EPFNOSUPPORT);
+	if (npr->pr_type == 0)
+		return (EPROTOTYPE);
+	if (npr->pr_protocol == 0)
+		return (EPROTONOSUPPORT);
+	if (npr->pr_usrreqs == NULL)
+		return (ENXIO);
+
+	/* Try to find the specified domain based on the family. */
+	for (dp = domains; dp; dp = dp->dom_next)
+		if (dp->dom_family == family)
+			goto found;
+	return (EPFNOSUPPORT);
+
+found:
+	/* Initialize backpointer to struct domain. */
+	npr->pr_domain = dp;
+	fpr = NULL;
+
+	/* The new protocol must not yet exist. */
+	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
+		if ((pr->pr_type == npr->pr_type) &&
+		    (pr->pr_protocol == npr->pr_protocol))
+			return (EEXIST);	/* XXX: Check only protocol? */
+		/* While here, remember the first free spacer. */
+		if ((fpr == NULL) && (pr->pr_protocol == PROTO_SPACER))
+			fpr = pr;
+	}
+
+	/* If no free spacer is found we can't add the new protocol. */
+	if (fpr == NULL)
+		return (ENOMEM);
+
+	/* Copy the new struct protosw over the spacer. */
+	bcopy(npr, fpr, sizeof(*fpr));
+
+	/* Initialize and activate the protocol. */
+	if (fpr->pr_init)
+		(fpr->pr_init)();
+
+	return (0);
+}
+
+/*
+ * The caller must make sure the protocol and its functions correctly shut down
+ * all sockets and release all locks and memory references.
+ */
+int
+pf_proto_unregister(family, protocol, type)
+	int family;
+	int protocol;
+	int type;
+{
+	struct domain *dp;
+	struct protosw *pr, *dpr;
+
+	/* Sanity checks. */
+	if (family == 0)
+		return (EPFNOSUPPORT);
+	if (protocol == 0)
+		return (EPROTONOSUPPORT);
+	if (type == 0)
+		return (EPROTOTYPE);
+
+	/* Try to find the specified domain based on the family type. */
+	for (dp = domains; dp; dp = dp->dom_next)
+		if (dp->dom_family == family)
+			goto found;
+	return (EPFNOSUPPORT);
+
+found:
+	dpr = NULL;
+
+	/* The protocol must exist and only once. */
+	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
+		if ((pr->pr_type == type) && (pr->pr_protocol == protocol)) {
+			if (dpr != NULL)
+				return (EMLINK);   /* Should not happen! */
+			else
+				dpr = pr;
+		}
+	}
+
+	/* Protocol does not exist. */
+	if (dpr == NULL)
+		return (EPROTONOSUPPORT);
+
+	/* De-orbit the protocol and make the slot available again. */
+	dpr->pr_type = 0;
+	dpr->pr_domain = dp;
+	dpr->pr_protocol = PROTO_SPACER;
+	dpr->pr_flags = 0;
+	dpr->pr_input = NULL;
+	dpr->pr_output = NULL;
+	dpr->pr_ctlinput = NULL;
+	dpr->pr_ctloutput = NULL;
+	dpr->pr_ousrreq = NULL;
+	dpr->pr_init = NULL;
+	dpr->pr_fasttimo = NULL;
+	dpr->pr_slowtimo = NULL;
+	dpr->pr_drain = NULL;
+	dpr->pr_usrreqs = &nousrreqs;
+
+	return (0);
 }
 
 void
Index: kern/uipc_socket2.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/uipc_socket2.c,v
retrieving revision 1.137
diff -u -p -r1.137 uipc_socket2.c
--- kern/uipc_socket2.c	15 Aug 2004 06:24:41 -0000	1.137
+++ kern/uipc_socket2.c	18 Oct 2004 21:24:35 -0000
@@ -1277,12 +1277,30 @@ sbcreatecontrol(p, size, type, level)
  * supported by a protocol.  Fill in as needed.
  */
 int
+pru_abort_notsupp(struct socket *so)
+{
+	return EOPNOTSUPP;
+}
+
+int
 pru_accept_notsupp(struct socket *so, struct sockaddr **nam)
 {
 	return EOPNOTSUPP;
 }
 
 int
+pru_attach_notsupp(struct socket *so, int proto, struct thread *td)
+{
+	return EOPNOTSUPP;
+}
+
+int
+pru_bind_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td)
+{
+	return EOPNOTSUPP;
+}
+
+int
 pru_connect_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td)
 {
 	return EOPNOTSUPP;
@@ -1296,7 +1314,19 @@ pru_connect2_notsupp(struct socket *so1,
 
 int
 pru_control_notsupp(struct socket *so, u_long cmd, caddr_t data,
-		    struct ifnet *ifp, struct thread *td)
+	struct ifnet *ifp, struct thread *td)
+{
+	return EOPNOTSUPP;
+}
+
+int
+pru_detach_notsupp(struct socket *so)
+{
+	return EOPNOTSUPP;
+}
+
+int
+pru_disconnect_notsupp(struct socket *so)
 {
 	return EOPNOTSUPP;
 }
@@ -1308,6 +1338,12 @@ pru_listen_notsupp(struct socket *so, st
 }
 
 int
+pru_peeraddr_notsupp(struct socket *so, struct sockaddr **nam)
+{
+	return EOPNOTSUPP;
+}
+
+int
 pru_rcvd_notsupp(struct socket *so, int flags)
 {
 	return EOPNOTSUPP;
@@ -1319,6 +1355,13 @@ pru_rcvoob_notsupp(struct socket *so, st
 	return EOPNOTSUPP;
 }
 
+int
+pru_send_notsupp(struct socket *so, int flags, struct mbuf *m,
+	struct sockaddr *addr, struct mbuf *control, struct thread *td)
+{
+	return EOPNOTSUPP;
+}
+
 /*
  * This isn't really a ``null'' operation, but it's the default one
  * and doesn't do anything destructive.
@@ -1328,6 +1371,40 @@ pru_sense_null(struct socket *so, struct
 {
 	sb->st_blksize = so->so_snd.sb_hiwat;
 	return 0;
+}
+
+int
+pru_shutdown_notsupp(struct socket *so)
+{
+	return EOPNOTSUPP;
+}
+
+int
+pru_sockaddr_notsupp(struct socket *so, struct sockaddr **nam)
+{
+	return EOPNOTSUPP;
+}
+
+int
+pru_sosend_notsupp(struct socket *so, struct sockaddr *addr, struct uio *uio,
+	struct mbuf *top, struct mbuf *control, int flags, struct thread *td)
+{
+	return EOPNOTSUPP;
+}
+
+int
+pru_soreceive_notsupp(struct socket *so, struct sockaddr **paddr,
+	struct uio *uio, struct mbuf **mp0, struct mbuf **controlp,
+	int *flagsp)
+{
+	return EOPNOTSUPP;
+}
+
+int
+pru_sopoll_notsupp(struct socket *so, int events, struct ucred *cred,
+	struct thread *td)
+{
+	return EOPNOTSUPP;
 }
 
 /*
Index: modules/Makefile
===================================================================
RCS file: /home/ncvs/src/sys/modules/Makefile,v
retrieving revision 1.402
diff -u -p -r1.402 Makefile
--- modules/Makefile	9 Oct 2004 07:31:03 -0000	1.402
+++ modules/Makefile	18 Oct 2004 21:24:35 -0000
@@ -105,6 +105,7 @@ SUBDIR=	${_3dfx} \
 	${_iir} \
 	${_io} \
 	ip6fw \
+	ipdivert \
 	${_ipfilter} \
 	ipfw \
 	ip_mroute_mod \
Index: netinet/in.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in.h,v
retrieving revision 1.87
diff -u -p -r1.87 in.h
--- netinet/in.h	16 Aug 2004 18:32:07 -0000	1.87
+++ netinet/in.h	18 Oct 2004 21:24:37 -0000
@@ -244,6 +244,12 @@ __END_DECLS
 #define	IPPROTO_DIVERT		258		/* divert pseudo-protocol */
 
 /*
+ * Only defined to avoid confusion, the actual value is defined as
+ * PROTO_SPACER in sys/protosw.h.
+ */
+#define	IPPROTO_SPACER		32767		/* spacer for loadable protos */
+
+/*
  * Local port number conventions:
  *
  * When a user does a bind(2) or connect(2) with a port number of zero,
Index: netinet/in_pcb.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in_pcb.h,v
retrieving revision 1.76
diff -u -p -r1.76 in_pcb.h
--- netinet/in_pcb.h	16 Aug 2004 18:32:07 -0000	1.76
+++ netinet/in_pcb.h	18 Oct 2004 21:24:37 -0000
@@ -250,6 +250,7 @@ struct inpcbinfo {		/* XXX documentation
 
 #define INP_INFO_LOCK_INIT(ipi, d) \
 	mtx_init(&(ipi)->ipi_mtx, (d), NULL, MTX_DEF | MTX_RECURSE)
+#define INP_INFO_LOCK_DESTROY(ipi)  mtx_destroy(&(ipi)->ipi_mtx)
 #define INP_INFO_RLOCK(ipi)	mtx_lock(&(ipi)->ipi_mtx)
 #define INP_INFO_WLOCK(ipi)	mtx_lock(&(ipi)->ipi_mtx)
 #define INP_INFO_RUNLOCK(ipi)	mtx_unlock(&(ipi)->ipi_mtx)
Index: netinet/in_proto.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in_proto.c,v
retrieving revision 1.73
diff -u -p -r1.73 in_proto.c
--- netinet/in_proto.c	16 Aug 2004 18:32:07 -0000	1.73
+++ netinet/in_proto.c	18 Oct 2004 21:24:37 -0000
@@ -30,7 +30,6 @@
  * $FreeBSD: src/sys/netinet/in_proto.c,v 1.73 2004/08/16 18:32:07 rwatson Exp $
  */
 
-#include "opt_ipdivert.h"
 #include "opt_ipx.h"
 #include "opt_mrouting.h"
 #include "opt_ipsec.h"
@@ -93,7 +92,17 @@
 #endif
 
 extern	struct domain inetdomain;
-static	struct pr_usrreqs nousrreqs;
+
+/*
+ * Spacer n-times for loadable protocols.
+ */
+#define IPPROTOSPACER   \
+{ 0,		&inetdomain,	IPPROTO_SPACER,	0,	\
+  NULL,		NULL,		NULL,		NULL,	\
+  NULL,							\
+  NULL,		NULL,		NULL,		NULL,	\
+  &nousrreqs						\
+}
 
 struct protosw inetsw[] = {
 { 0,		&inetdomain,	0,		0,
@@ -207,14 +216,6 @@ struct protosw inetsw[] = {
   &rip_usrreqs
 },
 #endif
-#ifdef IPDIVERT
-{ SOCK_RAW,	&inetdomain,	IPPROTO_DIVERT,	PR_ATOMIC|PR_ADDR,
-  div_input,	0,		div_ctlinput,	ip_ctloutput,
-  0,
-  div_init,	0,		0,		0,
-  &div_usrreqs,
-},
-#endif
 #ifdef IPXIP
 { SOCK_RAW,	&inetdomain,	IPPROTO_IDP,	PR_ATOMIC|PR_ADDR|PR_LASTHDR,
   ipxip_input,	0,		ipxip_ctlinput,	0,
@@ -239,6 +240,17 @@ struct protosw inetsw[] = {
   &rip_usrreqs
 },
 #endif	/* DEV_PFSYNC */
+
+/* Spacer n-times for loadable protocols. */
+IPPROTOSPACER,
+IPPROTOSPACER,
+IPPROTOSPACER,
+IPPROTOSPACER,
+IPPROTOSPACER,
+IPPROTOSPACER,
+IPPROTOSPACER,
+IPPROTOSPACER,
+
 	/* raw wildcard */
 { SOCK_RAW,	&inetdomain,	0,		PR_ATOMIC|PR_ADDR,
   rip_input,	0,		0,		rip_ctloutput,
@@ -280,9 +292,6 @@ SYSCTL_NODE(_net_inet, IPPROTO_AH,	ipsec
 #endif /* IPSEC */
 #endif /* !FAST_IPSEC */
 SYSCTL_NODE(_net_inet, IPPROTO_RAW,	raw,	CTLFLAG_RW, 0,	"RAW");
-#ifdef IPDIVERT
-SYSCTL_NODE(_net_inet, IPPROTO_DIVERT,	divert,	CTLFLAG_RW, 0,	"DIVERT");
-#endif
 #ifdef PIM
 SYSCTL_NODE(_net_inet, IPPROTO_PIM,    pim,    CTLFLAG_RW, 0,  "PIM");
 #endif
Index: netinet/ip_divert.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_divert.c,v
retrieving revision 1.100
diff -u -p -r1.100 ip_divert.c
--- netinet/ip_divert.c	3 Oct 2004 00:26:35 -0000	1.100
+++ netinet/ip_divert.c	18 Oct 2004 21:24:37 -0000
@@ -29,15 +29,13 @@
  * $FreeBSD: src/sys/netinet/ip_divert.c,v 1.100 2004/10/03 00:26:35 green Exp $
  */
 
+#if !defined(KLD_MODULE)
 #include "opt_inet.h"
-#include "opt_ipfw.h"
-#include "opt_ipdivert.h"
-#include "opt_ipsec.h"
 #include "opt_mac.h"
-
 #ifndef INET
 #error "IPDIVERT requires INET."
 #endif
+#endif
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -45,6 +43,8 @@
 #include <sys/malloc.h>
 #include <sys/mac.h>
 #include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
 #include <sys/proc.h>
 #include <sys/protosw.h>
 #include <sys/signalvar.h>
@@ -102,13 +102,16 @@
  * will cause it to be effectively considered as a standard packet).
  */
 
-/* Internal variables */
+/* Internal variables. */
 static struct inpcbhead divcb;
 static struct inpcbinfo divcbinfo;
 
 static u_long	div_sendspace = DIVSNDQ;	/* XXX sysctl ? */
 static u_long	div_recvspace = DIVRCVQ;	/* XXX sysctl ? */
 
+/* Forward declarations. */
+//static	void divert_packet(struct mbuf *, int);
+
 /*
  * Initialize divert connection block queue.
  */
@@ -147,7 +150,7 @@ div_input(struct mbuf *m, int off)
  * Setup generic address and protocol structures for div_input routine,
  * then pass them along with mbuf chain.
  */
-void
+static void
 divert_packet(struct mbuf *m, int incoming)
 {
 	struct ip *ip;
@@ -650,10 +653,14 @@ div_peeraddr(struct socket *so, struct s
 	return (in_setpeeraddr(so, nam, &divcbinfo));
 }
 
-
+/* XXX broken.  Why???
+#ifdef SYSCTL_NODE
+SYSCTL_NODE(_net_inet, OID_AUTO, divert, CTLFLAG_RW, 0, "IP Divert");
 SYSCTL_DECL(_net_inet_divert);
 SYSCTL_PROC(_net_inet_divert, OID_AUTO, pcblist, CTLFLAG_RD, 0, 0,
 	    div_pcblist, "S,xinpcb", "List of active divert sockets");
+#endif
+  XXX */
 
 struct pr_usrreqs div_usrreqs = {
 	div_abort, pru_accept_notsupp, div_attach, div_bind,
@@ -662,3 +669,61 @@ struct pr_usrreqs div_usrreqs = {
 	pru_rcvoob_notsupp, div_send, pru_sense_null, div_shutdown,
 	div_sockaddr, sosend, soreceive, sopoll, in_pcbsosetlabel
 };
+
+struct protosw div_protosw = {
+  SOCK_RAW,	NULL,		IPPROTO_DIVERT,	PR_ATOMIC|PR_ADDR,
+  div_input,	NULL,		div_ctlinput,	ip_ctloutput,
+  NULL,
+  div_init,	NULL,		NULL,		NULL,
+  &div_usrreqs
+};
+
+static int
+div_modevent(module_t mod, int type, void *unused)
+{
+	int err = 0;
+	int n;
+
+	switch (type) {
+	case MOD_LOAD:
+		/*
+		 * Protocol will be initialized by pf_proto_register().
+		 * We don't have to register ip_protox because we are not
+		 * a true IP protocol that goes over the wire.
+		 */
+		err = pf_proto_register(PF_INET, &div_protosw);
+		ip_divert_ptr = divert_packet;
+		break;
+	case MOD_UNLOAD:
+		/*
+		 * Module ipdivert can only be unloaded if no sockets are
+		 * connected.  Maybe this can be changed later to forcefully
+		 * disconnect any open sockets.
+		 */
+		INP_INFO_RLOCK(&divcbinfo);
+		n = divcbinfo.ipi_count;
+		INP_INFO_RUNLOCK(&divcbinfo);
+		if (n != 0) {
+			err = EBUSY;
+			break;
+		}
+		ip_divert_ptr = NULL;
+		err = pf_proto_unregister(PF_INET, IPPROTO_DIVERT, SOCK_RAW);
+		INP_INFO_LOCK_DESTROY(&divcbinfo);
+		break;
+	default:
+		return EINVAL;
+		break;
+	}
+	return err;
+}
+
+static moduledata_t ipdivertmod = {
+        "ipdivert",
+        div_modevent,
+        0
+};
+
+DECLARE_MODULE(ipdivert, ipdivertmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
+MODULE_DEPEND(dummynet, ipfw, 2, 2, 2);
+MODULE_VERSION(ipdivert, 1);
Index: netinet/ip_divert.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_divert.h,v
retrieving revision 1.3
diff -u -p -r1.3 ip_divert.h
--- netinet/ip_divert.h	25 Feb 2004 19:55:28 -0000	1.3
+++ netinet/ip_divert.h	18 Oct 2004 21:24:37 -0000
@@ -74,10 +74,10 @@ divert_find_info(struct mbuf *m)
 	return mtag ? divert_info(mtag) : 0;
 }
 
+typedef	void ip_divert_packet_t(struct mbuf *m, int incoming);
+extern	ip_divert_packet_t *ip_divert_ptr;
+
 extern	void div_init(void);
 extern	void div_input(struct mbuf *, int);
 extern	void div_ctlinput(int, struct sockaddr *, void *);
-extern	void divert_packet(struct mbuf *m, int incoming);
-extern	struct mbuf *divert_clone(struct mbuf *);
-extern struct pr_usrreqs div_usrreqs;
 #endif /* _NETINET_IP_DIVERT_H_ */
 			/*
Index: netinet/ip_fw2.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fw2.c,v
retrieving revision 1.81
diff -u -p -r1.81 ip_fw2.c
--- netinet/ip_fw2.c	3 Oct 2004 00:47:15 -0000	1.81
+++ netinet/ip_fw2.c	18 Oct 2004 21:24:37 -0000
@@ -35,7 +35,6 @@
 #if !defined(KLD_MODULE)
 #include "opt_ipfw.h"
 #include "opt_ipdn.h"
-#include "opt_ipdivert.h"
 #include "opt_inet.h"
 #include "opt_ipsec.h"
 #ifndef INET
@@ -3077,9 +3076,8 @@ check_ipfw_struct(struct ip_fw *rule, in
 
 		case O_DIVERT:
 		case O_TEE:
-#ifndef	IPDIVERT
-			return EINVAL;
-#endif
+			if (ip_divert_ptr == NULL)
+				return EINVAL;
 		case O_FORWARD_MAC: /* XXX not implemented yet */
 		case O_CHECK_STATE:
 		case O_COUNT:
Index: netinet/ip_fw_pfil.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fw_pfil.c,v
retrieving revision 1.10
diff -u -p -r1.10 ip_fw_pfil.c
--- netinet/ip_fw_pfil.c	29 Sep 2004 04:54:33 -0000	1.10
+++ netinet/ip_fw_pfil.c	18 Oct 2004 21:24:37 -0000
@@ -29,7 +29,6 @@
 #if !defined(KLD_MODULE)
 #include "opt_ipfw.h"
 #include "opt_ipdn.h"
-#include "opt_ipdivert.h"
 #include "opt_inet.h"
 #ifndef INET
 #error IPFIREWALL requires INET.
@@ -67,10 +66,13 @@ static	int ipfw_pfil_hooked = 0;
 /* Dummynet hooks. */
 ip_dn_ruledel_t	*ip_dn_ruledel_ptr = NULL;
 
-#define	DIV_DIR_IN	1
-#define	DIV_DIR_OUT	0
+/* Divert hooks. */
+ip_divert_packet_t *ip_divert_ptr = NULL;
 
+/* Forward declarations. */
 static int	ipfw_divert(struct mbuf **, int, int);
+#define	DIV_DIR_IN	1
+#define	DIV_DIR_OUT	0
 
 int
 ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
@@ -255,13 +257,16 @@ ipfw_divert(struct mbuf **m, int incomin
 	 * If tee is set, copy packet and return original.
 	 * If not tee, consume packet and send it to divert socket.
 	 */
-#ifdef IPDIVERT
 	struct mbuf *clone, *reass;
 	struct ip *ip;
 	int hlen;
 
 	reass = NULL;
 
+	/* Is divert module loaded? */
+	if (ip_divert_ptr == NULL)
+		goto nodivert;
+
 	/* Cloning needed for tee? */
 	if (tee)
 		clone = m_dup(*m, M_DONTWAIT);
@@ -309,8 +314,8 @@ ipfw_divert(struct mbuf **m, int incomin
 	}
 
 	/* Do the dirty job... */
-	if (clone)
-		divert_packet(clone, incoming);
+	if (clone && ip_divert_ptr != NULL)
+		ip_divert_ptr(clone, incoming);
 
 teeout:
 	/*
@@ -322,10 +327,10 @@ teeout:
 
 	/* Packet diverted and consumed */
 	return 1;
-#else
+
+nodivert:
 	m_freem(*m);
 	return 1;
-#endif	/* ipdivert */
 }
 
 static int
Index: netinet/ip_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.291
diff -u -p -r1.291 ip_input.c
--- netinet/ip_input.c	29 Sep 2004 04:54:33 -0000	1.291
+++ netinet/ip_input.c	18 Oct 2004 21:24:38 -0000
@@ -261,7 +261,7 @@ ip_init()
 		if (pr->pr_domain->dom_family == PF_INET &&
 		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) {
 			/* Be careful to only index valid IP protocols. */
-			if (pr->pr_protocol && pr->pr_protocol < IPPROTO_MAX)
+			if (pr->pr_protocol <= IPPROTO_MAX)
 				ip_protox[pr->pr_protocol] = pr - inetsw;
 		}
 
@@ -1143,6 +1151,67 @@ ip_drain()
 	IPQ_UNLOCK();
 	in_rtqdrain();
 }
+
+/*
+ * The protocol to be inserted into ip_protox[] must be already registered
+ * in inetsw[], either statically or through pf_proto_register().
+ */
+int
+ipproto_register(u_char ipproto)
+{
+	struct protosw *pr;
+
+	/* Sanity checks. */
+	if (ipproto == 0)
+		return (EPROTONOSUPPORT);
+
+	/*
+	 * The protocol slot must not be occupied by another protocol
+	 * already.  An index pointing to IPPROTO_RAW is unused.
+	 */
+	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
+	if (pr == NULL)
+		return (EPFNOSUPPORT);
+	if (ip_protox[ipproto] != pr - inetsw)	/* IPPROTO_RAW */
+		return (EEXIST);
+
+	/* Find the protocol position in inetsw[] and set the index. */
+	for (pr = inetdomain.dom_protosw;
+	     pr < inetdomain.dom_protoswNPROTOSW; pr++) {
+		if (pr->pr_domain->dom_family == PF_INET &&
+		    pr->pr_protocol && pr->pr_protocol == ipproto) {
+			/* Be careful to only index valid IP protocols. */
+			if (pr->pr_protocol <= IPPROTO_MAX) {
+				ip_protox[pr->pr_protocol] = pr - inetsw;
+				return (0);
+			} else
+				return (EINVAL);
+		}
+	}
+	return (EPROTONOSUPPORT);
+}
+
+int
+ipproto_unregister(u_char ipproto)
+{
+	struct protosw *pr;
+
+	/* Sanity checks. */
+	if (ipproto == 0)
+		return (EPROTONOSUPPORT);
+
+	/* Check if the protocol was indeed registered. */
+	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
+	if (pr == NULL)
+		return (EPFNOSUPPORT);
+	if (ip_protox[ipproto] == pr - inetsw)  /* IPPROTO_RAW */
+		return (ENOENT);
+
+	/* Reset the protocol slot to IPPROTO_RAW. */
+	ip_protox[ipproto] = pr - inetsw;
+	return (0);
+}
+
 
 /*
  * Do option processing on a datagram,
Index: netinet/ip_var.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_var.h,v
retrieving revision 1.91
diff -u -p -r1.91 ip_var.h
--- netinet/ip_var.h	15 Sep 2004 20:13:26 -0000	1.91
+++ netinet/ip_var.h	18 Oct 2004 21:24:38 -0000
@@ -168,6 +168,8 @@ extern int	 (*ip_mforward)(struct ip *, 
 int	 ip_output(struct mbuf *,
 	    struct mbuf *, struct route *, int, struct ip_moptions *,
 	    struct inpcb *);
+int	 ipproto_register(u_char);
+int	 ipproto_unregister(u_char);
 struct mbuf *
 	 ip_reass(struct mbuf *);
 struct in_ifaddr *
Index: netinet6/ip6_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.78
diff -u -p -r1.78 ip6_input.c
--- netinet6/ip6_input.c	29 Sep 2004 04:54:33 -0000	1.78
+++ netinet6/ip6_input.c	18 Oct 2004 21:24:38 -0000
@@ -169,13 +169,22 @@ ip6_init()
 	pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW);
 	if (pr == 0)
 		panic("ip6_init");
+
+	/* Initialize the entire ip_protox[] array to IPPROTO_RAW. */
 	for (i = 0; i < IPPROTO_MAX; i++)
 		ip6_protox[i] = pr - inet6sw;
+	/*
+	 * Cycle through IP protocols and put them into the appropriate place
+	 * in ip6_protox[].
+	 */
 	for (pr = (struct ip6protosw *)inet6domain.dom_protosw;
 	    pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW; pr++)
 		if (pr->pr_domain->dom_family == PF_INET6 &&
-		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
-			ip6_protox[pr->pr_protocol] = pr - inet6sw;
+		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) {
+			/* Be careful to only index valid IP protocols. */
+			if (pr->pr_protocol <= IPPROTO_MAX)
+				ip6_protox[pr->pr_protocol] = pr - inet6sw;
+		}
 
 	/* Initialize packet filter hooks. */
 	inet6_pfil_hook.ph_type = PFIL_TYPE_AF;
Index: sys/protosw.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/protosw.h,v
retrieving revision 1.43
diff -u -p -r1.43 protosw.h
--- sys/protosw.h	7 Apr 2004 04:19:49 -0000	1.43
+++ sys/protosw.h	18 Oct 2004 21:24:38 -0000
@@ -105,6 +105,12 @@ struct protosw {
 #define	PR_FASTHZ	5		/* 5 fast timeouts per second */
 
 /*
+ * This number should be defined again within each protocol family to avoid
+ * confusion.
+ */
+#define	PROTO_SPACER	32767		/* spacer for loadable protocols */
+
+/*
  * Values for pr_flags.
  * PR_ADDR requires PR_ATOMIC;
  * PR_ADDR and PR_CONNREQUIRED are mutually exclusive.
@@ -231,16 +237,41 @@ struct pr_usrreqs {
 	void	(*pru_sosetlabel)(struct socket *so);
 };
 
+/*
+ * The dummy protocol specific user requests function pointer array is
+ * initialized to the functions below.  All functions return EOPNOTSUPP.
+ */
+extern	struct pr_usrreqs nousrreqs;
+
+int	pru_abort_notsupp(struct socket *so);
 int	pru_accept_notsupp(struct socket *so, struct sockaddr **nam);
+int	pru_attach_notsupp(struct socket *so, int proto, struct thread *td);
+int	pru_bind_notsupp(struct socket *so, struct sockaddr *nam,
+	    struct thread *td);
 int	pru_connect_notsupp(struct socket *so, struct sockaddr *nam,
 	    struct thread *td);
 int	pru_connect2_notsupp(struct socket *so1, struct socket *so2);
 int	pru_control_notsupp(struct socket *so, u_long cmd, caddr_t data,
 	    struct ifnet *ifp, struct thread *td);
+int	pru_detach_notsupp(struct socket *so);
+int	pru_disconnect_notsupp(struct socket *so);
 int	pru_listen_notsupp(struct socket *so, struct thread *td);
+int	pru_peeraddr_notsupp(struct socket *so, struct sockaddr **nam);
 int	pru_rcvd_notsupp(struct socket *so, int flags);
 int	pru_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags);
+int	pru_send_notsupp(struct socket *so, int flags, struct mbuf *m,
+	    struct sockaddr *addr, struct mbuf *control, struct thread *td);
 int	pru_sense_null(struct socket *so, struct stat *sb);
+int	pru_shutdown_notsupp(struct socket *so);
+int	pru_sockaddr_notsupp(struct socket *so, struct sockaddr **nam);
+int	pru_sosend_notsupp(struct socket *so, struct sockaddr *addr,
+	    struct uio *uio, struct mbuf *top, struct mbuf *control, int flags,
+	    struct thread *td);
+int	pru_soreceive_notsupp(struct socket *so, struct sockaddr **paddr,
+	    struct uio *uio, struct mbuf **mp0, struct mbuf **controlp,
+	    int *flagsp);
+int	pru_sopoll_notsupp(struct socket *so, int events, struct ucred *cred,
+	    struct thread *td);
 void	pru_sosetlabel_null(struct socket *so);
 
 #endif /* _KERNEL */
@@ -319,6 +350,8 @@ void	pfctlinput(int, struct sockaddr *);
 void	pfctlinput2(int, struct sockaddr *, void *);
 struct protosw *pffindproto(int family, int protocol, int type);
 struct protosw *pffindtype(int family, int type);
+int	pf_proto_register(int family, struct protosw *npr);
+int	pf_proto_unregister(int family, int protocol, int type);
 #endif
 
 #endif
