git: e7d02be19d40 - main - protosw: refactor protosw and domain static declaration and load

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Wed, 17 Aug 2022 18:52:27 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=e7d02be19d40063783d6b8f1ff2bc4c7170fd434

commit e7d02be19d40063783d6b8f1ff2bc4c7170fd434
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2022-08-17 18:50:32 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2022-08-17 18:50:32 +0000

    protosw: refactor protosw and domain static declaration and load
    
    o Assert that every protosw has pr_attach.  Now this structure is
      only for socket protocols declarations and nothing else.
    o Merge struct pr_usrreqs into struct protosw.  This was suggested
      in 1996 by wollman@ (see 7b187005d18ef), and later reiterated
      in 2006 by rwatson@ (see 6fbb9cf860dcd).
    o Make struct domain hold a variable sized array of protosw pointers.
      For most protocols these pointers are initialized statically.
      Those domains that may have loadable protocols have spacers. IPv4
      and IPv6 have 8 spacers each (andre@ dff3237ee54ea).
    o For inetsw and inet6sw leave a comment noting that many protosw
      entries very likely are dead code.
    o Refactor pf_proto_[un]register() into protosw_[un]register().
    o Isolate pr_*_notsupp() methods into uipc_domain.c
    
    Reviewed by:            melifaro
    Differential revision:  https://reviews.freebsd.org/D36232
---
 sys/compat/linuxkpi/common/include/linux/net.h     |   4 +-
 sys/dev/cxgbe/tom/t4_tom.c                         |  29 +-
 sys/dev/hyperv/hvsock/hv_sock.c                    |  47 +--
 sys/kern/kern_sendfile.c                           |  17 +-
 sys/kern/sys_socket.c                              |  11 +-
 sys/kern/uipc_domain.c                             | 376 ++++++++++++---------
 sys/kern/uipc_ktls.c                               |  12 +-
 sys/kern/uipc_socket.c                             | 260 +++-----------
 sys/kern/uipc_syscalls.c                           |   4 +-
 sys/kern/uipc_usrreq.c                             | 223 ++++++------
 sys/net/if.c                                       |   3 +-
 sys/net/if_ovpn.c                                  |   2 +-
 sys/net/rtsock.c                                   |  25 +-
 sys/netgraph/bluetooth/socket/ng_btsocket.c        | 210 +++++-------
 sys/netgraph/bluetooth/socket/ng_btsocket_rfcomm.c |   4 +-
 sys/netgraph/ng_ksocket.c                          |   4 +-
 sys/netgraph/ng_socket.c                           |  59 ++--
 sys/netinet/in_proto.c                             | 202 +++--------
 sys/netinet/ip_divert.c                            |  28 +-
 sys/netinet/ip_output.c                            |   1 -
 sys/netinet/ip_var.h                               |   1 -
 sys/netinet/raw_ip.c                               |  81 ++++-
 sys/netinet/sctp_module.c                          |  60 +---
 sys/netinet/sctp_usrreq.c                          |  51 +--
 sys/netinet/sctp_var.h                             |   2 +-
 sys/netinet/tcp_subr.c                             |   4 +-
 sys/netinet/tcp_usrreq.c                           |  86 ++---
 sys/netinet/tcp_var.h                              |   3 +-
 sys/netinet/udp_usrreq.c                           |  44 ++-
 sys/netinet/udp_var.h                              |   1 -
 sys/netinet6/in6_proto.c                           | 202 +++--------
 sys/netinet6/raw_ip6.c                             |  75 +++-
 sys/netinet6/sctp6_usrreq.c                        |  50 +--
 sys/netinet6/sctp6_var.h                           |   2 +-
 sys/netinet6/send.c                                |  15 +-
 sys/netinet6/udp6_usrreq.c                         |  44 ++-
 sys/netipsec/keysock.c                             |  34 +-
 sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c     |  74 ++--
 sys/rpc/rpc_generic.c                              |   6 +-
 sys/rpc/svc_dg.c                                   |   2 +-
 sys/rpc/svc_vc.c                                   |   6 +-
 sys/security/mac/mac_socket.c                      |   4 +-
 sys/sys/domain.h                                   |   3 +-
 sys/sys/protosw.h                                  | 136 +++-----
 44 files changed, 1042 insertions(+), 1465 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/net.h b/sys/compat/linuxkpi/common/include/linux/net.h
index 5438fccb8512..d5752093da74 100644
--- a/sys/compat/linuxkpi/common/include/linux/net.h
+++ b/sys/compat/linuxkpi/common/include/linux/net.h
@@ -58,9 +58,9 @@ sock_getname(struct socket *so, struct sockaddr *addr, int *sockaddr_len,
 		if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
 			return (-ENOTCONN);
 
-		error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, &nam);
+		error = so->so_proto->pr_peeraddr(so, &nam);
 	} else
-		error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &nam);
+		error = so->so_proto->pr_sockaddr(so, &nam);
 	if (error)
 		return (-error);
 	*addr = *nam;
diff --git a/sys/dev/cxgbe/tom/t4_tom.c b/sys/dev/cxgbe/tom/t4_tom.c
index 9bd6145c9acc..825a4e96ce81 100644
--- a/sys/dev/cxgbe/tom/t4_tom.c
+++ b/sys/dev/cxgbe/tom/t4_tom.c
@@ -80,13 +80,8 @@ __FBSDID("$FreeBSD$");
 #include "tom/t4_tom.h"
 #include "tom/t4_tls.h"
 
-static struct protosw *tcp_protosw;
 static struct protosw toe_protosw;
-static struct pr_usrreqs toe_usrreqs;
-
-static struct protosw *tcp6_protosw;
 static struct protosw toe6_protosw;
-static struct pr_usrreqs toe6_usrreqs;
 
 /* Module ops */
 static int t4_tom_mod_load(void);
@@ -269,9 +264,9 @@ void
 restore_so_proto(struct socket *so, bool v6)
 {
 	if (v6)
-		so->so_proto = tcp6_protosw;
+		so->so_proto = &tcp6_protosw;
 	else
-		so->so_proto = tcp_protosw;
+		so->so_proto = &tcp_protosw;
 }
 
 /* This is _not_ the normal way to "unoffload" a socket. */
@@ -2024,21 +2019,11 @@ t4_tom_mod_load(void)
 	t4_ddp_mod_load();
 	t4_tls_mod_load();
 
-	tcp_protosw = pffindproto(PF_INET, IPPROTO_TCP, SOCK_STREAM);
-	if (tcp_protosw == NULL)
-		return (ENOPROTOOPT);
-	bcopy(tcp_protosw, &toe_protosw, sizeof(toe_protosw));
-	bcopy(tcp_protosw->pr_usrreqs, &toe_usrreqs, sizeof(toe_usrreqs));
-	toe_usrreqs.pru_aio_queue = t4_aio_queue_tom;
-	toe_protosw.pr_usrreqs = &toe_usrreqs;
-
-	tcp6_protosw = pffindproto(PF_INET6, IPPROTO_TCP, SOCK_STREAM);
-	if (tcp6_protosw == NULL)
-		return (ENOPROTOOPT);
-	bcopy(tcp6_protosw, &toe6_protosw, sizeof(toe6_protosw));
-	bcopy(tcp6_protosw->pr_usrreqs, &toe6_usrreqs, sizeof(toe6_usrreqs));
-	toe6_usrreqs.pru_aio_queue = t4_aio_queue_tom;
-	toe6_protosw.pr_usrreqs = &toe6_usrreqs;
+	bcopy(&tcp_protosw, &toe_protosw, sizeof(toe_protosw));
+	toe_protosw.pr_aio_queue = t4_aio_queue_tom;
+
+	bcopy(&tcp6_protosw, &toe6_protosw, sizeof(toe6_protosw));
+	toe6_protosw.pr_aio_queue = t4_aio_queue_tom;
 
 	return (t4_register_uld(&tom_uld_info));
 }
diff --git a/sys/dev/hyperv/hvsock/hv_sock.c b/sys/dev/hyperv/hvsock/hv_sock.c
index 8c327a22e6fd..f728383a1b6f 100644
--- a/sys/dev/hyperv/hvsock/hv_sock.c
+++ b/sys/dev/hyperv/hvsock/hv_sock.c
@@ -86,48 +86,35 @@ static int hvs_dom_probe(void);
 					 roundup2(payload_len, 8) + \
 					 sizeof(uint64_t))
 
-
-static struct domain		hv_socket_domain;
-
 /*
  * HyperV Transport sockets
  */
-static struct pr_usrreqs	hvs_trans_usrreqs = {
-	.pru_attach =		hvs_trans_attach,
-	.pru_bind =		hvs_trans_bind,
-	.pru_listen =		hvs_trans_listen,
-	.pru_accept =		hvs_trans_accept,
-	.pru_connect =		hvs_trans_connect,
-	.pru_peeraddr =		hvs_trans_peeraddr,
-	.pru_sockaddr =		hvs_trans_sockaddr,
-	.pru_soreceive =	hvs_trans_soreceive,
-	.pru_sosend =		hvs_trans_sosend,
-	.pru_disconnect =	hvs_trans_disconnect,
-	.pru_close =		hvs_trans_close,
-	.pru_detach =		hvs_trans_detach,
-	.pru_shutdown =		hvs_trans_shutdown,
-	.pru_abort =		hvs_trans_abort,
-};
-
-/*
- * Definitions of protocols supported in HyperV socket domain
- */
-static struct protosw		hv_socket_protosw[] = {
-{
+static struct protosw hv_socket_protosw = {
 	.pr_type =		SOCK_STREAM,
-	.pr_domain =		&hv_socket_domain,
 	.pr_protocol =		HYPERV_SOCK_PROTO_TRANS,
 	.pr_flags =		PR_CONNREQUIRED,
-	.pr_usrreqs =		&hvs_trans_usrreqs,
-},
+	.pr_attach =		hvs_trans_attach,
+	.pr_bind =		hvs_trans_bind,
+	.pr_listen =		hvs_trans_listen,
+	.pr_accept =		hvs_trans_accept,
+	.pr_connect =		hvs_trans_connect,
+	.pr_peeraddr =		hvs_trans_peeraddr,
+	.pr_sockaddr =		hvs_trans_sockaddr,
+	.pr_soreceive =		hvs_trans_soreceive,
+	.pr_sosend =		hvs_trans_sosend,
+	.pr_disconnect =	hvs_trans_disconnect,
+	.pr_close =		hvs_trans_close,
+	.pr_detach =		hvs_trans_detach,
+	.pr_shutdown =		hvs_trans_shutdown,
+	.pr_abort =		hvs_trans_abort,
 };
 
 static struct domain		hv_socket_domain = {
 	.dom_family =		AF_HYPERV,
 	.dom_name =		"hyperv",
 	.dom_probe =		hvs_dom_probe,
-	.dom_protosw =		hv_socket_protosw,
-	.dom_protoswNPROTOSW =	&hv_socket_protosw[nitems(hv_socket_protosw)]
+	.dom_nprotosw =		1,
+	.dom_protosw =		{ &hv_socket_protosw },
 };
 
 DOMAIN_SET(hv_socket_);
diff --git a/sys/kern/kern_sendfile.c b/sys/kern/kern_sendfile.c
index 2de015254ab9..f444e38e153d 100644
--- a/sys/kern/kern_sendfile.c
+++ b/sys/kern/kern_sendfile.c
@@ -377,7 +377,7 @@ sendfile_iodone(void *arg, vm_page_t *pa, int count, int error)
 		 * for read, so that application receives EIO on next
 		 * syscall and eventually closes the socket.
 		 */
-		so->so_proto->pr_usrreqs->pru_abort(so);
+		so->so_proto->pr_abort(so);
 		so->so_error = EIO;
 
 		mb_free_notready(sfio->m, sfio->npages);
@@ -396,8 +396,7 @@ sendfile_iodone(void *arg, vm_page_t *pa, int count, int error)
 		goto out_with_ref;
 #endif
 	} else
-		(void)(so->so_proto->pr_usrreqs->pru_ready)(so, sfio->m,
-		    sfio->npages);
+		(void)so->so_proto->pr_ready(so, sfio->m, sfio->npages);
 
 	sorele(so);
 #ifdef KERN_TLS
@@ -1172,8 +1171,8 @@ prepend_header:
 				sendfile_iodone(sfio, NULL, 0, 0);
 #ifdef KERN_TLS
 			if (tls != NULL && tls->mode == TCP_TLS_MODE_SW) {
-				error = (*so->so_proto->pr_usrreqs->pru_send)
-				    (so, PRUS_NOTREADY, m, NULL, NULL, td);
+				error = so->so_proto->pr_send(so,
+				    PRUS_NOTREADY, m, NULL, NULL, td);
 				if (error != 0) {
 					m_freem(m);
 				} else {
@@ -1182,14 +1181,14 @@ prepend_header:
 				}
 			} else
 #endif
-				error = (*so->so_proto->pr_usrreqs->pru_send)
-				    (so, 0, m, NULL, NULL, td);
+				error = so->so_proto->pr_send(so, 0, m, NULL,
+				    NULL, td);
 		} else {
 			sfio->so = so;
 			sfio->m = m0;
 			soref(so);
-			error = (*so->so_proto->pr_usrreqs->pru_send)
-			    (so, PRUS_NOTREADY, m, NULL, NULL, td);
+			error = so->so_proto->pr_send(so, PRUS_NOTREADY, m,
+			    NULL, NULL, td);
 			sendfile_iodone(sfio, NULL, 0, error);
 		}
 		CURVNET_RESTORE();
diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c
index 7f39e58f4ce4..5b8aadc12e08 100644
--- a/sys/kern/sys_socket.c
+++ b/sys/kern/sys_socket.c
@@ -276,8 +276,7 @@ soo_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *active_cred,
 			CURVNET_RESTORE();
 		} else {
 			CURVNET_SET(so->so_vnet);
-			error = ((*so->so_proto->pr_usrreqs->pru_control)
-			    (so, cmd, data, 0, td));
+			error = so->so_proto->pr_control(so, cmd, data, 0, td);
 			CURVNET_RESTORE();
 		}
 		break;
@@ -336,7 +335,7 @@ soo_stat(struct file *fp, struct stat *ub, struct ucred *active_cred)
 	}
 	ub->st_uid = so->so_cred->cr_uid;
 	ub->st_gid = so->so_cred->cr_gid;
-	error = so->so_proto->pr_usrreqs->pru_sense(so, ub);
+	error = so->so_proto->pr_sense(so, ub);
 	SOCK_UNLOCK(so);
 	return (error);
 }
@@ -414,13 +413,13 @@ soo_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp)
 		}
 		break;
 	}
-	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
+	error = so->so_proto->pr_sockaddr(so, &sa);
 	if (error == 0 &&
 	    sa->sa_len <= sizeof(kif->kf_un.kf_sock.kf_sa_local)) {
 		bcopy(sa, &kif->kf_un.kf_sock.kf_sa_local, sa->sa_len);
 		free(sa, M_SONAME);
 	}
-	error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
+	error = so->so_proto->pr_peeraddr(so, &sa);
 	if (error == 0 &&
 	    sa->sa_len <= sizeof(kif->kf_un.kf_sock.kf_sa_peer)) {
 		bcopy(sa, &kif->kf_un.kf_sock.kf_sa_peer, sa->sa_len);
@@ -812,7 +811,7 @@ soo_aio_queue(struct file *fp, struct kaiocb *job)
 	int error;
 
 	so = fp->f_data;
-	error = (*so->so_proto->pr_usrreqs->pru_aio_queue)(so, job);
+	error = so->so_proto->pr_aio_queue(so, job);
 	if (error == 0)
 		return (0);
 
diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c
index c6a79d34beb2..d2b8d9095f13 100644
--- a/sys/kern/uipc_domain.c
+++ b/sys/kern/uipc_domain.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/rmlock.h>
 #include <sys/socketvar.h>
 #include <sys/systm.h>
+#include <sys/stat.h>		/* XXXGL: remove */
 
 #include <machine/atomic.h>
 
@@ -76,85 +77,182 @@ int domain_init_status = 0;
 static struct mtx dom_mtx;		/* domain list lock */
 MTX_SYSINIT(domain, &dom_mtx, "domain list", MTX_DEF);
 
+static int
+pr_accept_notsupp(struct socket *so, struct sockaddr **nam)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_aio_queue_notsupp(struct socket *so, struct kaiocb *job)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_bind_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_bindat_notsupp(int fd, struct socket *so, struct sockaddr *nam,
+    struct thread *td)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_connect_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_connectat_notsupp(int fd, struct socket *so, struct sockaddr *nam,
+    struct thread *td)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_connect2_notsupp(struct socket *so1, struct socket *so2)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_control_notsupp(struct socket *so, u_long cmd, void *data,
+    struct ifnet *ifp, struct thread *td)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_disconnect_notsupp(struct socket *so)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_listen_notsupp(struct socket *so, int backlog, struct thread *td)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_peeraddr_notsupp(struct socket *so, struct sockaddr **nam)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_rcvd_notsupp(struct socket *so, int flags)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_send_notsupp(struct socket *so, int flags, struct mbuf *m,
+    struct sockaddr *addr, struct mbuf *control, struct thread *td)
+{
+	if (control != NULL)
+		m_freem(control);
+	if ((flags & PRUS_NOTREADY) == 0)
+		m_freem(m);
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_ready_notsupp(struct socket *so, struct mbuf *m, int count)
+{
+	return (EOPNOTSUPP);
+}
+
 /*
- * Dummy protocol specific user requests function pointer array.
- * All functions return EOPNOTSUPP.
+ * This isn't really a ``null'' operation, but it's the default one and
+ * doesn't do anything destructive.
  */
-struct pr_usrreqs nousrreqs = {
-	.pru_accept =		pru_accept_notsupp,
-	.pru_attach =		pru_attach_notsupp,
-	.pru_bind =		pru_bind_notsupp,
-	.pru_connect =		pru_connect_notsupp,
-	.pru_connect2 =		pru_connect2_notsupp,
-	.pru_control =		pru_control_notsupp,
-	.pru_disconnect	=	pru_disconnect_notsupp,
-	.pru_listen =		pru_listen_notsupp,
-	.pru_peeraddr =		pru_peeraddr_notsupp,
-	.pru_rcvd =		pru_rcvd_notsupp,
-	.pru_rcvoob =		pru_rcvoob_notsupp,
-	.pru_send =		pru_send_notsupp,
-	.pru_sense =		pru_sense_null,
-	.pru_shutdown =		pru_shutdown_notsupp,
-	.pru_sockaddr =		pru_sockaddr_notsupp,
-	.pru_sosend =		pru_sosend_notsupp,
-	.pru_soreceive =	pru_soreceive_notsupp,
-	.pru_sopoll =		pru_sopoll_notsupp,
-};
+static int
+pr_sense_notsupp(struct socket *so, struct stat *sb)
+{
+	sb->st_blksize = so->so_snd.sb_hiwat;
+	return (0);
+}
 
-static void
-pr_usrreqs_init(struct protosw *pr)
+static int
+pr_shutdown_notsupp(struct socket *so)
 {
-	struct pr_usrreqs *pu;
+	return (EOPNOTSUPP);
+}
 
-	pu = pr->pr_usrreqs;
-	KASSERT(pu != NULL, ("%s: %ssw[%d] has no usrreqs!", __func__,
-	    pr->pr_domain->dom_name,
-	    (int)(pr - pr->pr_domain->dom_protosw)));
+static int
+pr_sockaddr_notsupp(struct socket *so, struct sockaddr **nam)
+{
+	return (EOPNOTSUPP);
+}
 
-	/*
-	 * Protocol switch methods fall into three categories: mandatory,
-	 * mandatory but protosw_init() provides a default, and optional.
-	 *
-	 * For true protocols (i.e., pru_attach != NULL), KASSERT truly
-	 * mandatory methods with no defaults, and initialize defaults for
-	 * other mandatory methods if the protocol hasn't defined an
-	 * implementation (NULL function pointer).
-	 */
-#if 0
-	if (pu->pru_attach != NULL) {
-		KASSERT(pu->pru_abort != NULL,
-		    ("protosw_init: %ssw[%d] pru_abort NULL",
-		    pr->pr_domain->dom_name,
-		    (int)(pr - pr->pr_domain->dom_protosw)));
-		KASSERT(pu->pru_send != NULL,
-		    ("protosw_init: %ssw[%d] pru_send NULL",
-		    pr->pr_domain->dom_name,
-		    (int)(pr - pr->pr_domain->dom_protosw)));
-	}
-#endif
+static int
+pr_sosend_notsupp(struct socket *so, struct sockaddr *addr, struct uio *uio,
+    struct mbuf *top, struct mbuf *control, int flags, struct thread *td)
+{
+	return (EOPNOTSUPP);
+}
 
-#define DEFAULT(foo, bar)	if ((foo) == NULL)  (foo) = (bar)
-	DEFAULT(pu->pru_accept, pru_accept_notsupp);
-	DEFAULT(pu->pru_aio_queue, pru_aio_queue_notsupp);
-	DEFAULT(pu->pru_bind, pru_bind_notsupp);
-	DEFAULT(pu->pru_bindat, pru_bindat_notsupp);
-	DEFAULT(pu->pru_connect, pru_connect_notsupp);
-	DEFAULT(pu->pru_connect2, pru_connect2_notsupp);
-	DEFAULT(pu->pru_connectat, pru_connectat_notsupp);
-	DEFAULT(pu->pru_control, pru_control_notsupp);
-	DEFAULT(pu->pru_disconnect, pru_disconnect_notsupp);
-	DEFAULT(pu->pru_listen, pru_listen_notsupp);
-	DEFAULT(pu->pru_peeraddr, pru_peeraddr_notsupp);
-	DEFAULT(pu->pru_rcvd, pru_rcvd_notsupp);
-	DEFAULT(pu->pru_rcvoob, pru_rcvoob_notsupp);
-	DEFAULT(pu->pru_sense, pru_sense_null);
-	DEFAULT(pu->pru_shutdown, pru_shutdown_notsupp);
-	DEFAULT(pu->pru_sockaddr, pru_sockaddr_notsupp);
-	DEFAULT(pu->pru_sosend, sosend_generic);
-	DEFAULT(pu->pru_soreceive, soreceive_generic);
-	DEFAULT(pu->pru_sopoll, sopoll_generic);
-	DEFAULT(pu->pru_ready, pru_ready_notsupp);
-#undef DEFAULT
+static int
+pr_soreceive_notsupp(struct socket *so, struct sockaddr **paddr,
+    struct uio *uio, struct mbuf **mp0, struct mbuf **controlp, int *flagsp)
+{
+	return (EOPNOTSUPP);
+}
+
+static int
+pr_sopoll_notsupp(struct socket *so, int events, struct ucred *cred,
+    struct thread *td)
+{
+	return (EOPNOTSUPP);
+}
+
+static void
+pr_init(struct protosw *pr)
+{
+
+	KASSERT(pr->pr_attach != NULL,
+	    ("%s: protocol doesn't have pr_attach", __func__));
+
+#define	DEFAULT(foo, bar)	if (pr->foo == NULL) pr->foo = bar
+	DEFAULT(pr_sosend, sosend_generic);
+	DEFAULT(pr_soreceive, soreceive_generic);
+	DEFAULT(pr_sopoll, sopoll_generic);
+
+#define NOTSUPP(foo)	if (pr->foo == NULL)  pr->foo = foo ## _notsupp
+	NOTSUPP(pr_accept);
+	NOTSUPP(pr_aio_queue);
+	NOTSUPP(pr_bind);
+	NOTSUPP(pr_bindat);
+	NOTSUPP(pr_connect);
+	NOTSUPP(pr_connect2);
+	NOTSUPP(pr_connectat);
+	NOTSUPP(pr_control);
+	NOTSUPP(pr_disconnect);
+	NOTSUPP(pr_listen);
+	NOTSUPP(pr_peeraddr);
+	NOTSUPP(pr_rcvd);
+	NOTSUPP(pr_rcvoob);
+	NOTSUPP(pr_send);
+	NOTSUPP(pr_sense);
+	NOTSUPP(pr_shutdown);
+	NOTSUPP(pr_sockaddr);
+	NOTSUPP(pr_sosend);
+	NOTSUPP(pr_soreceive);
+	NOTSUPP(pr_sopoll);
+	NOTSUPP(pr_ready);
 }
 
 /*
@@ -176,9 +274,11 @@ domain_init(void *arg)
 		return;
 	MPASS((flags & DOMF_INITED) == 0);
 
-	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
-		pr_usrreqs_init(pr);
-	}
+	for (int i = 0; i < dp->dom_nprotosw; i++)
+		if ((pr = dp->dom_protosw[i]) != NULL) {
+			pr->pr_domain = dp;
+			pr_init(pr);
+		}
 
 	/*
 	 * update global information about maximums
@@ -288,9 +388,10 @@ pffindtype(int family, int type)
 	if (dp == NULL)
 		return (NULL);
 
-	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
-		if (pr->pr_type && pr->pr_type == type)
+	for (int i = 0; i < dp->dom_nprotosw; i++)
+		if ((pr = dp->dom_protosw[i]) != NULL && pr->pr_type == type)
 			return (pr);
+
 	return (NULL);
 }
 
@@ -301,18 +402,18 @@ pffindproto(int family, int protocol, int type)
 	struct protosw *pr;
 	struct protosw *maybe;
 
-	maybe = NULL;
-	if (family == 0)
-		return (NULL);
-
 	dp = pffinddomain(family);
 	if (dp == NULL)
 		return (NULL);
 
-	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
+	maybe = NULL;
+	for (int i = 0; i < dp->dom_nprotosw; i++) {
+		if ((pr = dp->dom_protosw[i]) == NULL)
+			continue;
 		if ((pr->pr_protocol == protocol) && (pr->pr_type == type))
 			return (pr);
 
+		/* XXX: raw catches all. Why? */
 		if (type == SOCK_RAW && pr->pr_type == SOCK_RAW &&
 		    pr->pr_protocol == 0 && maybe == NULL)
 			maybe = pr;
@@ -325,60 +426,49 @@ pffindproto(int family, int protocol, int type)
  * accept requests before it is registered.
  */
 int
-pf_proto_register(int family, struct protosw *npr)
+protosw_register(struct domain *dp, 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. */
-	dp = pffinddomain(family);
-	if (dp == NULL)
-		return (EPFNOSUPPORT);
+	struct protosw **prp;
 
-	/* Initialize backpointer to struct domain. */
-	npr->pr_domain = dp;
-	fpr = NULL;
+	MPASS(dp);
+	MPASS(npr && npr->pr_type > 0 && npr->pr_protocol > 0);
 
+	prp = NULL;
 	/*
 	 * Protect us against races when two protocol registrations for
 	 * the same protocol happen at the same time.
 	 */
 	mtx_lock(&dom_mtx);
+	for (int i = 0; i < dp->dom_nprotosw; i++) {
+		if (dp->dom_protosw[i] == NULL) {
+			/* Remember the first free spacer. */
+			if (prp == NULL)
+				prp = &dp->dom_protosw[i];
+		} else {
+			/*
+			 * The new protocol must not yet exist.
+			 * XXXAO: Check only protocol?
+			 * XXXGL: Maybe assert that it doesn't exist?
+			 */
+			if ((dp->dom_protosw[i]->pr_type == npr->pr_type) &&
+			    (dp->dom_protosw[i]->pr_protocol ==
+			    npr->pr_protocol)) {
+				mtx_unlock(&dom_mtx);
+				return (EEXIST);
+			}
 
-	/* 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)) {
-			mtx_unlock(&dom_mtx);
-			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) {
+	if (prp == NULL) {
 		mtx_unlock(&dom_mtx);
 		return (ENOMEM);
 	}
 
-	/* Copy the new struct protosw over the spacer. */
-	bcopy(npr, fpr, sizeof(*fpr));
-
-	pr_usrreqs_init(fpr);
-
-	/* Job is done, no more protection required. */
+	npr->pr_domain = dp;
+	pr_init(npr);
+	*prp = npr;
 	mtx_unlock(&dom_mtx);
 
 	return (0);
@@ -389,55 +479,33 @@ pf_proto_register(int family, struct protosw *npr)
  * all sockets and release all locks and memory references.
  */
 int
-pf_proto_unregister(int family, int protocol, int type)
+protosw_unregister(struct protosw *pr)
 {
 	struct domain *dp;
-	struct protosw *pr, *dpr;
+	struct protosw **prp;
 
-	/* Sanity checks. */
-	if (family == 0)
-		return (EPFNOSUPPORT);
-	if (protocol == 0)
-		return (EPROTONOSUPPORT);
-	if (type == 0)
-		return (EPROTOTYPE);
+	dp = pr->pr_domain;
+	prp = NULL;
 
-	/* Try to find the specified domain based on the family type. */
-	dp = pffinddomain(family);
-	if (dp == NULL)
-		return (EPFNOSUPPORT);
-
-	dpr = NULL;
-
-	/* Lock out everyone else while we are manipulating the protosw. */
 	mtx_lock(&dom_mtx);
-
 	/* 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) {
-				mtx_unlock(&dom_mtx);
-				return (EMLINK);   /* Should not happen! */
-			} else
-				dpr = pr;
+	for (int i = 0; i < dp->dom_nprotosw; i++) {
+		if (dp->dom_protosw[i] == pr) {
+			KASSERT(prp == NULL,
+			    ("%s: domain %p protocol %p registered twice\n",
+			    __func__, dp, pr));
+			prp = &dp->dom_protosw[i];
 		}
 	}
 
-	/* Protocol does not exist. */
-	if (dpr == NULL) {
+	/* Protocol does not exist.  XXXGL: assert that it does? */
+	if (prp == NULL) {
 		mtx_unlock(&dom_mtx);
 		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_ctloutput = NULL;
-	dpr->pr_usrreqs = &nousrreqs;
-
-	/* Job is done, not more protection required. */
+	*prp = NULL;
 	mtx_unlock(&dom_mtx);
 
 	return (0);
diff --git a/sys/kern/uipc_ktls.c b/sys/kern/uipc_ktls.c
index 5855e62bd983..ff20b3652407 100644
--- a/sys/kern/uipc_ktls.c
+++ b/sys/kern/uipc_ktls.c
@@ -2366,7 +2366,7 @@ ktls_decrypt(struct socket *so)
 			counter_u64_add(ktls_offload_corrupted_records, 1);
 
 			CURVNET_SET(so->so_vnet);
-			so->so_proto->pr_usrreqs->pru_abort(so);
+			so->so_proto->pr_abort(so);
 			so->so_error = error;
 			CURVNET_RESTORE();
 			goto deref;
@@ -2890,9 +2890,9 @@ ktls_encrypt(struct ktls_wq *wq, struct mbuf *top)
 
 	CURVNET_SET(so->so_vnet);
 	if (error == 0) {
-		(void)(*so->so_proto->pr_usrreqs->pru_ready)(so, top, npages);
+		(void)so->so_proto->pr_ready(so, top, npages);
 	} else {
-		so->so_proto->pr_usrreqs->pru_abort(so);
+		so->so_proto->pr_abort(so);
 		so->so_error = EIO;
 		mb_free_notready(top, total_pages);
 	}
@@ -2934,9 +2934,9 @@ ktls_encrypt_cb(struct ktls_ocf_encrypt_state *state, int error)
 	npages = m->m_epg_nrdy;
 
 	if (error == 0) {
-		(void)(*so->so_proto->pr_usrreqs->pru_ready)(so, m, npages);
+		(void)so->so_proto->pr_ready(so, m, npages);
 	} else {
-		so->so_proto->pr_usrreqs->pru_abort(so);
+		so->so_proto->pr_abort(so);
 		so->so_error = EIO;
 		mb_free_notready(m, npages);
 	}
@@ -3001,7 +3001,7 @@ ktls_encrypt_async(struct ktls_wq *wq, struct mbuf *top)
 
 	CURVNET_SET(so->so_vnet);
 	if (error != 0) {
-		so->so_proto->pr_usrreqs->pru_abort(so);
+		so->so_proto->pr_abort(so);
 		so->so_error = EIO;
 		mb_free_notready(m, total_pages - npages);
 	}
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index bbca2d8663d7..bf22c0245f24 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -523,9 +523,8 @@ socreate(int dom, struct socket **aso, int type, int proto,
 			return (EPROTOTYPE);
 		return (EPROTONOSUPPORT);
 	}
-	if (prp->pr_usrreqs->pru_attach == NULL ||
-	    prp->pr_usrreqs->pru_attach == pru_attach_notsupp)
-		return (EPROTONOSUPPORT);
+
+	MPASS(prp->pr_attach);
 
 	if (IN_CAPABILITY_MODE(td) && (prp->pr_flags & PR_CAPATTACH) == 0)
 		return (ECAPMODE);
@@ -564,7 +563,7 @@ socreate(int dom, struct socket **aso, int type, int proto,
 	 * the appropriate flags must be set in the pru_attach function.
 	 */
 	CURVNET_SET(so->so_vnet);
-	error = (*prp->pr_usrreqs->pru_attach)(so, proto, td);
+	error = prp->pr_attach(so, proto, td);
 	CURVNET_RESTORE();
 	if (error) {
 		sodealloc(so);
@@ -789,9 +788,9 @@ sonewconn(struct socket *head, int connstatus)
 	if ((so = solisten_clone(head)) == NULL)
 		return (NULL);
 
-	if ((*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) {
+	if (so->so_proto->pr_attach(so, 0, NULL) != 0) {
 		sodealloc(so);
-		log(LOG_DEBUG, "%s: pcb %p: pru_attach() failed\n",
+		log(LOG_DEBUG, "%s: pcb %p: pr_attach() failed\n",
 		    __func__, head->so_pcb);
 		return (NULL);
 	}
@@ -894,7 +893,7 @@ sopeeloff(struct socket *head)
 		    __func__, head->so_pcb);
 		return (NULL);
 	}
-	if ((*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) {
+	if ((*so->so_proto->pr_attach)(so, 0, NULL)) {
 		sodealloc(so);
 		log(LOG_DEBUG, "%s: pcb %p: pru_attach() failed\n",
 		    __func__, head->so_pcb);
@@ -919,7 +918,7 @@ sobind(struct socket *so, struct sockaddr *nam, struct thread *td)
 	int error;
 
 	CURVNET_SET(so->so_vnet);
-	error = (*so->so_proto->pr_usrreqs->pru_bind)(so, nam, td);
+	error = so->so_proto->pr_bind(so, nam, td);
 	CURVNET_RESTORE();
 	return (error);
 }
@@ -930,7 +929,7 @@ sobindat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td)
 	int error;
 
 	CURVNET_SET(so->so_vnet);
-	error = (*so->so_proto->pr_usrreqs->pru_bindat)(fd, so, nam, td);
+	error = so->so_proto->pr_bindat(fd, so, nam, td);
 	CURVNET_RESTORE();
 	return (error);
 }
@@ -953,7 +952,7 @@ solisten(struct socket *so, int backlog, struct thread *td)
 	int error;
 
 	CURVNET_SET(so->so_vnet);
-	error = (*so->so_proto->pr_usrreqs->pru_listen)(so, backlog, td);
+	error = so->so_proto->pr_listen(so, backlog, td);
 	CURVNET_RESTORE();
 	return (error);
 }
@@ -1178,8 +1177,8 @@ sofree(struct socket *so)
 		MPASS(pr->pr_domain->dom_dispose != NULL);
 		(*pr->pr_domain->dom_dispose)(so);
 	}
-	if (pr->pr_usrreqs->pru_detach != NULL)
-		(*pr->pr_usrreqs->pru_detach)(so);
+	if (pr->pr_detach != NULL)
+		pr->pr_detach(so);
 
 	/*
 	 * From this point on, we assume that no other references to this
@@ -1253,8 +1252,8 @@ soclose(struct socket *so)
 	}
 
 drop:
-	if (so->so_proto->pr_usrreqs->pru_close != NULL)
-		(*so->so_proto->pr_usrreqs->pru_close)(so);
+	if (so->so_proto->pr_close != NULL)
+		so->so_proto->pr_close(so);
 
 	SOCK_LOCK(so);
 	if ((listening = SOLISTENING(so))) {
@@ -1314,8 +1313,8 @@ soabort(struct socket *so)
 
 	VNET_SO_ASSERT(so);
 
-	if (so->so_proto->pr_usrreqs->pru_abort != NULL)
-		(*so->so_proto->pr_usrreqs->pru_abort)(so);
+	if (so->so_proto->pr_abort != NULL)
+		so->so_proto->pr_abort(so);
 	SOCK_LOCK(so);
 	sorele_locked(so);
 }
@@ -1326,7 +1325,7 @@ soaccept(struct socket *so, struct sockaddr **nam)
 	int error;
 
 	CURVNET_SET(so->so_vnet);
-	error = (*so->so_proto->pr_usrreqs->pru_accept)(so, nam);
+	error = so->so_proto->pr_accept(so, nam);
 	CURVNET_RESTORE();
 	return (error);
 }
@@ -1360,11 +1359,9 @@ soconnectat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td)
 		 */
 		so->so_error = 0;
 		if (fd == AT_FDCWD) {
-			error = (*so->so_proto->pr_usrreqs->pru_connect)(so,
-			    nam, td);
+			error = so->so_proto->pr_connect(so, nam, td);
 		} else {
-			error = (*so->so_proto->pr_usrreqs->pru_connectat)(fd,
-			    so, nam, td);
+			error = so->so_proto->pr_connectat(fd, so, nam, td);
 		}
 	}
 	CURVNET_RESTORE();
@@ -1378,7 +1375,7 @@ soconnect2(struct socket *so1, struct socket *so2)
 	int error;
 
 	CURVNET_SET(so1->so_vnet);
-	error = (*so1->so_proto->pr_usrreqs->pru_connect2)(so1, so2);
+	error = so1->so_proto->pr_connect2(so1, so2);
 	CURVNET_RESTORE();
 	return (error);
 }
@@ -1393,7 +1390,7 @@ sodisconnect(struct socket *so)
 	if (so->so_state & SS_ISDISCONNECTING)
 		return (EALREADY);
 	VNET_SO_ASSERT(so);
-	error = (*so->so_proto->pr_usrreqs->pru_disconnect)(so);
+	error = so->so_proto->pr_disconnect(so);
 	return (error);
 }
 
*** 2768 LINES SKIPPED ***