From 4b8c01febf19053371038d70566127271baad428 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 27 Jul 2020 14:41:23 +0000 Subject: [PATCH] MFC r363079, r363080, r363129, r363133: Provide support for building SCTP as a loadable module. --- share/man/man4/sctp.4 | 18 +++- sys/modules/Makefile | 4 + sys/modules/sctp/Makefile | 30 ++++++ sys/netinet/sctp_module.c | 197 ++++++++++++++++++++++++++++++++++++ sys/netinet/sctp_os_bsd.h | 7 +- sys/netinet/sctp_syscalls.c | 73 +++++++------ sys/netinet/sctp_usrreq.c | 1 + 7 files changed, 296 insertions(+), 34 deletions(-) create mode 100644 sys/modules/sctp/Makefile create mode 100644 sys/netinet/sctp_module.c diff --git a/share/man/man4/sctp.4 b/share/man/man4/sctp.4 index bd1b33e5b25..b28d5c02906 100644 --- a/share/man/man4/sctp.4 +++ b/share/man/man4/sctp.4 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 18, 2020 +.Dd July 9, 2020 .Dt SCTP 4 .Os .Sh NAME @@ -144,8 +144,18 @@ The transport protocol also provides a unordered service as well. The unordered service allows a message to be sent and delivered with no regard to the ordering of any other message. +.Pp +The +.Tn SCTP +kernel implementation may either be compiled into the kernel, or loaded +dynamically as a module. +To support dynamic loading of the stack, the kernel must be compiled +with +.Cd "options SCTP_SUPPORT" . .Ss Extensions -The FreeBSD implementation of +The +.Fx +implementation of .Tn SCTP also supports the following extensions: .Bl -tag -width "sctp partial reliability" @@ -609,3 +619,7 @@ Maximum outgoing SCTP buffer size. .Xr sctp_recvmsg 3 , .Xr sctp_sendmsg 3 , .Xr blackhole 4 +.Sh BUGS +The +.Nm +kernel module cannot be unloaded. diff --git a/sys/modules/Makefile b/sys/modules/Makefile index a06a743edfa..495746b7ecc 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -343,6 +343,7 @@ SUBDIR= \ ${_sbni} \ scc \ ${_scsi_low} \ + ${_sctp} \ sdhci \ ${_sdhci_acpi} \ sdhci_pci \ @@ -461,6 +462,9 @@ _ipfw_pmod= ipfw_pmod .if ${MK_IPSEC_SUPPORT} != "no" _ipsec= ipsec .endif +.if ${KERN_OPTS:MSCTP_SUPPORT} || ${KERN_OPTS:MSCTP} +_sctp= sctp +.endif .endif .if (${MK_INET_SUPPORT} != "no" && ${MK_INET6_SUPPORT} != "no") || \ diff --git a/sys/modules/sctp/Makefile b/sys/modules/sctp/Makefile new file mode 100644 index 00000000000..1896c22dd83 --- /dev/null +++ b/sys/modules/sctp/Makefile @@ -0,0 +1,30 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/netinet +.PATH: ${SRCTOP}/sys/netinet6 + +KMOD= sctp +SRCS= sctp_asconf.c \ + sctp_auth.c \ + sctp_bsd_addr.c \ + sctp_cc_functions.c \ + sctp_crc32.c \ + sctp_indata.c \ + sctp_input.c \ + sctp_kdtrace.c \ + sctp_module.c \ + sctp_output.c \ + sctp_pcb.c \ + sctp_peeloff.c \ + sctp_ss_functions.c \ + sctp_syscalls.c \ + sctp_sysctl.c \ + sctp_timer.c \ + sctp_usrreq.c \ + sctp6_usrreq.c \ + sctputil.c + +SRCS+= device_if.h bus_if.h vnode_if.h +SRCS+= opt_capsicum.h opt_ktrace.h opt_inet.h opt_inet6.h opt_sctp.h + +.include diff --git a/sys/netinet/sctp_module.c b/sys/netinet/sctp_module.c new file mode 100644 index 00000000000..50b09eb6f93 --- /dev/null +++ b/sys/netinet/sctp_module.c @@ -0,0 +1,197 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019-2020 The FreeBSD Foundation + * + * This software was developed by Mark Johnston under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_inet.h" +#include "opt_inet6.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef INET +extern struct domain inetdomain; + +struct protosw sctp_stream_protosw = { + .pr_type = SOCK_STREAM, + .pr_domain = &inetdomain, + .pr_protocol = IPPROTO_SCTP, + .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_LASTHDR, + .pr_input = sctp_input, + .pr_ctlinput = sctp_ctlinput, + .pr_ctloutput = sctp_ctloutput, + .pr_drain = sctp_drain, + .pr_usrreqs = &sctp_usrreqs, +}; + +struct protosw sctp_seqpacket_protosw = { + .pr_type = SOCK_SEQPACKET, + .pr_domain = &inetdomain, + .pr_protocol = IPPROTO_SCTP, + .pr_flags = PR_WANTRCVD|PR_LASTHDR, + .pr_input = sctp_input, + .pr_ctlinput = sctp_ctlinput, + .pr_ctloutput = sctp_ctloutput, + .pr_drain = sctp_drain, + .pr_usrreqs = &sctp_usrreqs, +}; +#endif + +#ifdef INET6 +extern struct domain inet6domain; + +struct protosw sctp6_stream_protosw = { + .pr_type = SOCK_STREAM, + .pr_domain = &inet6domain, + .pr_protocol = IPPROTO_SCTP, + .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_LASTHDR, + .pr_input = sctp6_input, + .pr_ctlinput = sctp6_ctlinput, + .pr_ctloutput = sctp_ctloutput, + .pr_init = sctp_init, + .pr_drain = sctp_drain, + .pr_usrreqs = &sctp6_usrreqs, +}; + +struct protosw sctp6_seqpacket_protosw = { + .pr_type = SOCK_SEQPACKET, + .pr_domain = &inet6domain, + .pr_protocol = IPPROTO_SCTP, + .pr_flags = PR_WANTRCVD|PR_LASTHDR, + .pr_input = sctp6_input, + .pr_ctlinput = sctp6_ctlinput, + .pr_ctloutput = sctp_ctloutput, +#ifndef INET /* Do not call initialization and drain routines twice. */ + .pr_init = sctp_init, + .pr_drain = sctp_drain, +#endif + .pr_usrreqs = &sctp6_usrreqs, +}; +#endif + +static int +sctp_module_load(void) +{ + int error; + +#ifdef INET + error = pf_proto_register(PF_INET, &sctp_stream_protosw); + if (error != 0) + return (error); + error = pf_proto_register(PF_INET, &sctp_seqpacket_protosw); + if (error != 0) + return (error); + error = ipproto_register(IPPROTO_SCTP); + if (error != 0) + return (error); +#endif +#ifdef INET6 + error = pf_proto_register(PF_INET6, &sctp6_stream_protosw); + if (error != 0) + return (error); + error = pf_proto_register(PF_INET6, &sctp6_seqpacket_protosw); + if (error != 0) + return (error); + error = ip6proto_register(IPPROTO_SCTP); + if (error != 0) + return (error); +#endif + error = sctp_syscalls_init(); + if (error != 0) + return (error); + return (0); +} + +static int __unused +sctp_module_unload(void) +{ + + (void)sctp_syscalls_uninit(); + +#ifdef INET + (void)ipproto_unregister(IPPROTO_SCTP); + (void)pf_proto_unregister(PF_INET, IPPROTO_SCTP, SOCK_STREAM); + (void)pf_proto_unregister(PF_INET, IPPROTO_SCTP, SOCK_SEQPACKET); +#endif +#ifdef INET6 + (void)ip6proto_unregister(IPPROTO_SCTP); + (void)pf_proto_unregister(PF_INET6, IPPROTO_SCTP, SOCK_STREAM); + (void)pf_proto_unregister(PF_INET6, IPPROTO_SCTP, SOCK_SEQPACKET); +#endif + return (0); +} + +static int +sctp_modload(struct module *module, int cmd, void *arg) +{ + int error; + + switch (cmd) { + case MOD_LOAD: + error = sctp_module_load(); + break; + case MOD_UNLOAD: + /* + * Unloading SCTP is currently unsupported. Currently, SCTP + * iterator threads are not stopped during unload. + */ + error = EOPNOTSUPP; + break; + default: + error = 0; + break; + } + return (error); +} + +static moduledata_t sctp_mod = { + "sctp", + &sctp_modload, + NULL, +}; + +DECLARE_MODULE(sctp, sctp_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); +MODULE_VERSION(sctp, 1); diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h index 4a7097127ec..4db7f543e58 100644 --- a/sys/netinet/sctp_os_bsd.h +++ b/sys/netinet/sctp_os_bsd.h @@ -45,9 +45,12 @@ __FBSDID("$FreeBSD$"); #include "opt_sctp.h" #include +#include +#include #include #include #include +#include #include #include #include @@ -83,7 +86,6 @@ __FBSDID("$FreeBSD$"); #include #ifdef INET6 -#include #include #include #include @@ -478,4 +480,7 @@ sctp_get_mbuf_for_msg(unsigned int space_needed, #define SCTP_IS_LISTENING(inp) ((inp->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING) != 0) +int sctp_syscalls_init(void); +int sctp_syscalls_uninit(void); + #endif diff --git a/sys/netinet/sctp_syscalls.c b/sys/netinet/sctp_syscalls.c index fe95a197e8a..a7bf7cfba07 100644 --- a/sys/netinet/sctp_syscalls.c +++ b/sys/netinet/sctp_syscalls.c @@ -32,8 +32,6 @@ __FBSDID("$FreeBSD$"); #include "opt_capsicum.h" -#include "opt_inet.h" -#include "opt_inet6.h" #include "opt_sctp.h" #include "opt_ktrace.h" @@ -69,6 +67,8 @@ __FBSDID("$FreeBSD$"); #include #endif #ifdef COMPAT_FREEBSD32 +#include +#include #include #endif @@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include static struct syscall_helper_data sctp_syscalls[] = { @@ -88,28 +89,54 @@ static struct syscall_helper_data sctp_syscalls[] = { SYSCALL_INIT_LAST }; -static void -sctp_syscalls_init(void *unused __unused) +#ifdef COMPAT_FREEBSD32 +static struct syscall_helper_data sctp32_syscalls[] = { + SYSCALL32_INIT_HELPER_COMPAT(sctp_peeloff), + SYSCALL32_INIT_HELPER_COMPAT(sctp_generic_sendmsg), + SYSCALL32_INIT_HELPER_COMPAT(sctp_generic_sendmsg_iov), + SYSCALL32_INIT_HELPER_COMPAT(sctp_generic_recvmsg), + SYSCALL_INIT_LAST +}; +#endif + +int +sctp_syscalls_init(void) { - int error __unused; + int error; - error = syscall_helper_register(sctp_syscalls, SY_THR_STATIC); - KASSERT((error == 0), - ("%s: syscall_helper_register failed for sctp syscalls", __func__)); + error = syscall_helper_register(sctp_syscalls, SY_THR_STATIC_KLD); + if (error != 0) + return (error); #ifdef COMPAT_FREEBSD32 - error = syscall32_helper_register(sctp_syscalls, SY_THR_STATIC); - KASSERT((error == 0), - ("%s: syscall32_helper_register failed for sctp syscalls", - __func__)); + error = syscall32_helper_register(sctp32_syscalls, SY_THR_STATIC_KLD); + if (error != 0) + return (error); #endif + return (0); } + +#ifdef SCTP SYSINIT(sctp_syscalls, SI_SUB_SYSCALLS, SI_ORDER_ANY, sctp_syscalls_init, NULL); +#endif + +int +sctp_syscalls_uninit(void) +{ + int error; + +#ifdef COMPAT_FREEBSD32 + error = syscall32_helper_unregister(sctp32_syscalls); + if (error != 0) + return (error); +#endif + error = syscall_helper_unregister(sctp_syscalls); + if (error != 0) + return (error); + return (0); +} /* * SCTP syscalls. - * Functionality only compiled in if SCTP is defined in the kernel Makefile, - * otherwise all return EOPNOTSUPP. - * XXX: We should make this loadable one day. */ int sys_sctp_peeloff(td, uap) @@ -119,7 +146,6 @@ sys_sctp_peeloff(td, uap) caddr_t name; } */ *uap; { -#if (defined(INET) || defined(INET6)) && defined(SCTP) struct file *headfp, *nfp = NULL; struct socket *head, *so; cap_rights_t rights; @@ -181,9 +207,6 @@ sys_sctp_peeloff(td, uap) fdrop(headfp, td); done2: return (error); -#else /* SCTP */ - return (EOPNOTSUPP); -#endif /* SCTP */ } int @@ -199,7 +222,6 @@ sys_sctp_generic_sendmsg (td, uap) int flags } */ *uap; { -#if (defined(INET) || defined(INET6)) && defined(SCTP) struct sctp_sndrcvinfo sinfo, *u_sinfo = NULL; struct socket *so; struct file *fp = NULL; @@ -294,9 +316,6 @@ sys_sctp_generic_sendmsg (td, uap) sctp_bad2: free(to, M_SONAME); return (error); -#else /* SCTP */ - return (EOPNOTSUPP); -#endif /* SCTP */ } int @@ -312,7 +331,6 @@ sys_sctp_generic_sendmsg_iov(td, uap) int flags } */ *uap; { -#if (defined(INET) || defined(INET6)) && defined(SCTP) struct sctp_sndrcvinfo sinfo, *u_sinfo = NULL; struct socket *so; struct file *fp = NULL; @@ -424,9 +442,6 @@ sys_sctp_generic_sendmsg_iov(td, uap) sctp_bad2: free(to, M_SONAME); return (error); -#else /* SCTP */ - return (EOPNOTSUPP); -#endif /* SCTP */ } int @@ -442,7 +457,6 @@ sys_sctp_generic_recvmsg(td, uap) int *msg_flags } */ *uap; { -#if (defined(INET) || defined(INET6)) && defined(SCTP) uint8_t sockbufstore[256]; struct uio auio; struct iovec *iov, *tiov; @@ -572,7 +586,4 @@ sys_sctp_generic_recvmsg(td, uap) fdrop(fp, td); return (error); -#else /* SCTP */ - return (EOPNOTSUPP); -#endif /* SCTP */ } diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 4cf3812e542..5b51a1636c4 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -98,6 +98,7 @@ sctp_init(void) static void sctp_finish(void *unused __unused) { + EVENTHANDLER_DEREGISTER(rt_addrmsg, SCTP_BASE_VAR(eh_tag)); sctp_pcb_finish(); } -- 2.45.0