diff options
| author | Gleb Smirnoff <glebius@FreeBSD.org> | 2025-02-01 01:01:57 +0000 |
|---|---|---|
| committer | Gleb Smirnoff <glebius@FreeBSD.org> | 2025-02-01 09:00:25 +0000 |
| commit | fa1b961259bc5ba90b2ed693d8eb54c7641b6ec7 (patch) | |
| tree | 46dcbb3201c2409ff1c033a75737dc5097f0b1a3 | |
| parent | 5418b1ebdfa0c6118894ce0e91115c3c13f3850d (diff) | |
| -rw-r--r-- | include/rpc/Makefile | 6 | ||||
| -rw-r--r-- | sys/conf/files | 1 | ||||
| -rw-r--r-- | sys/modules/krpc/Makefile | 1 | ||||
| -rw-r--r-- | sys/rpc/clnt.h | 11 | ||||
| -rw-r--r-- | sys/rpc/clnt_nl.c | 510 | ||||
| -rw-r--r-- | sys/rpc/clnt_nl.h | 42 | ||||
| -rw-r--r-- | sys/rpc/krpc.h | 2 | ||||
| -rw-r--r-- | sys/rpc/rpc_generic.c | 3 |
8 files changed, 575 insertions, 1 deletions
diff --git a/include/rpc/Makefile b/include/rpc/Makefile index b6e3ab53adb4..db8d78826eb2 100644 --- a/include/rpc/Makefile +++ b/include/rpc/Makefile @@ -1,3 +1,6 @@ +.include <src.opts.mk> +.PATH: ${SRCTOP}/sys/rpc + .SUFFIXES: .x RPCCOM= RPCGEN_CPP=${CPP:Q} rpcgen -C @@ -11,6 +14,9 @@ HFILES= auth.h auth_unix.h clnt.h clnt_soc.h clnt_stat.h \ rpc.h rpc_msg.h rpcb_clnt.h rpcent.h rpc_com.h rpcsec_gss.h \ svc.h svc_auth.h svc_soc.h svc_dg.h xdr.h +# User visible declarations for kernel RPC modules +HFILES+= clnt_nl.h + # Secure RPC HFILES+= auth_des.h des.h des_crypt.h diff --git a/sys/conf/files b/sys/conf/files index 496f1617a67a..230d5229210e 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -5101,6 +5101,7 @@ rpc/auth_unix.c optional krpc | nfslockd | nfscl | nfsd rpc/authunix_prot.c optional krpc | nfslockd | nfscl | nfsd rpc/clnt_bck.c optional krpc | nfslockd | nfscl | nfsd rpc/clnt_dg.c optional krpc | nfslockd | nfscl | nfsd +rpc/clnt_nl.c optional krpc | nfslockd | nfscl | nfsd rpc/clnt_rc.c optional krpc | nfslockd | nfscl | nfsd rpc/clnt_vc.c optional krpc | nfslockd | nfscl | nfsd rpc/getnetconfig.c optional krpc | nfslockd | nfscl | nfsd diff --git a/sys/modules/krpc/Makefile b/sys/modules/krpc/Makefile index a49207b78123..a47c5cbc55c0 100644 --- a/sys/modules/krpc/Makefile +++ b/sys/modules/krpc/Makefile @@ -5,6 +5,7 @@ SRCS= auth_none.c \ authunix_prot.c \ clnt_bck.c \ clnt_dg.c \ + clnt_nl.c \ clnt_rc.c \ clnt_vc.c \ getnetconfig.c \ diff --git a/sys/rpc/clnt.h b/sys/rpc/clnt.h index d9fc372709cf..a237b00928e0 100644 --- a/sys/rpc/clnt.h +++ b/sys/rpc/clnt.h @@ -372,6 +372,17 @@ extern CLIENT *clnt_dg_create(struct socket *so, size_t sendsz, size_t recvsz); /* + * netlink(4) client that would multicast calls on genetlink(4) family + * named "rpcnl" (with dynamic id). The server counterpart of this + * client is a userland application that uses libc/rpc/svc_nl.c to + * receive the calls and send replies. + * + * const char *name -- multicast group name + */ +extern CLIENT *client_nl_create(const char *name, const rpcprog_t prog, + const rpcvers_t version); + +/* * struct socket *so; -- socket * struct sockaddr *svcaddr; -- servers address * rpcprog_t prog; -- program number diff --git a/sys/rpc/clnt_nl.c b/sys/rpc/clnt_nl.c new file mode 100644 index 000000000000..8f841e4240d7 --- /dev/null +++ b/sys/rpc/clnt_nl.c @@ -0,0 +1,510 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org> + * + * 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 <sys/param.h> +#include <sys/lock.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/rwlock.h> +#include <sys/mbuf.h> +#include <sys/priv.h> +#include <sys/proc.h> +#include <sys/queue.h> +#include <sys/tree.h> + +#include <rpc/rpc.h> +#include <rpc/rpc_com.h> +#include <rpc/krpc.h> +#include <rpc/clnt_nl.h> + +#include <netlink/netlink.h> +#include <netlink/netlink_ctl.h> +#include <netlink/netlink_generic.h> + +/* + * Kernel RPC client over netlink(4), where kernel is RPC client and an + * application is a server. See svc_nl.c in the libc/rpc as the counterpart. + * + * The module registers itself within generic netlink families list under name + * "rpc". Every new client creates a new multicast group belonging to this + * family. When a client starts RPC, the module will multicast the call to + * potential netlink listeners and sleep/retry until receiving a result. The + * framing of the request: + * + * [netlink message header, type = "rpc" ID, seq == xid] + * [generic netlink header, cmd = RPCNL_REQUEST] + * [netlink attribute RPCNL_REQUEST_GROUP] + * [group ID] + * [netlink attribute RPCNL_REQUEST_BODY] + * [XDR encoded payload] + * + * Note: the generic netlink header and attributes aren't really necessary + * for successful communication, since the netlink multicast membership already + * guarantees us all needed filtering. The working prototype was putting the + * XDR encoded payload right after netlink message header. But we will provide + * this framing to allow for any future extensions. + * + * The expected RPC result from the userland shall be framed like this: + * + * [netlink message header, type = "rpc" ID, seq == xid] + * [generic netlink header, cmd = RPCNL_REPLY] + * [netlink attribute RPCNL_REPLY_GROUP] + * [group ID] + * [netlink attribute RPCNL_REPLY_BODY] + * [XDR encoded payload] + * + * Disclaimer: has been designed and tested only for the NFS related kernel + * RPC clients: kgssapi, RPC binding for NLM, TLS client and TLS server. + * + * Caveats: + * 1) Now the privilege checking is hardcoded to PRIV_NFS_DAEMON at the netlink + * command and multicast layers. If any new client in addition to NFS + * service emerges, we may want to rewrite privelege checking at the client + * level somehow. + * 2) Since we are using netlink attribute for the payload, payload size is + * limited to UINT16_MAX. Today it is smaller than RPC_MAXDATASIZE of 9000. + * What if a future RPC wants more? + */ + +static enum clnt_stat clnt_nl_call(CLIENT *, struct rpc_callextra *, + rpcproc_t, struct mbuf *, struct mbuf **, struct timeval); +static void clnt_nl_close(CLIENT *); +static void clnt_nl_destroy(CLIENT *); +static bool_t clnt_nl_control(CLIENT *, u_int, void *); + +static const struct clnt_ops clnt_nl_ops = { + .cl_call = clnt_nl_call, + .cl_close = clnt_nl_close, + .cl_destroy = clnt_nl_destroy, + .cl_control = clnt_nl_control, +}; + +static int clnt_nl_reply(struct nlmsghdr *, struct nl_pstate *); + +static const struct genl_cmd clnt_cmds[] = { + { + .cmd_num = RPCNL_REPLY, + .cmd_name = "request", + .cmd_cb = clnt_nl_reply, + .cmd_priv = PRIV_NFS_DAEMON, + }, +}; + +struct nl_reply_parsed { + uint32_t group; + struct nlattr *data; +}; +static const struct nlattr_parser rpcnl_attr_parser[] = { +#define OUT(field) offsetof(struct nl_reply_parsed, field) + { .type = RPCNL_REPLY_GROUP, .off = OUT(group), .cb = nlattr_get_uint32 }, + { .type = RPCNL_REPLY_BODY, .off = OUT(data), .cb = nlattr_get_nla }, +#undef OUT +}; +NL_DECLARE_PARSER(rpcnl_parser, struct genlmsghdr, nlf_p_empty, + rpcnl_attr_parser); + +struct nl_data { + struct mtx nl_lock; + RB_ENTRY(nl_data) nl_tree; + TAILQ_HEAD(, ct_request) nl_pending; + uint32_t nl_xid; + u_int nl_mpos; + u_int nl_authlen; + u_int nl_retries; + struct { + struct genlmsghdr ghdr; + struct nlattr gattr; + uint32_t group; + } nl_hdr; /* pre-initialized header */ + char nl_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ + /* msleep(9) arguments */ + const char * nl_wchan; + int nl_prio; + int nl_timo; +}; + +static RB_HEAD(nl_data_t, nl_data) rpcnl_clients; +static int32_t +nl_data_compare(const struct nl_data *a, const struct nl_data *b) +{ + return ((int32_t)(a->nl_hdr.group - b->nl_hdr.group)); +} +RB_GENERATE_STATIC(nl_data_t, nl_data, nl_tree, nl_data_compare); +static struct rwlock rpcnl_global_lock; + +static const char rpcnl_family_name[] = "rpc"; +static uint16_t rpcnl_family_id; + +void +rpcnl_init(void) +{ + bool rv __diagused; + + rpcnl_family_id = genl_register_family(rpcnl_family_name, 0, 1, 1); + MPASS(rpcnl_family_id != 0); + rv = genl_register_cmds(rpcnl_family_name, clnt_cmds, + nitems(clnt_cmds)); + MPASS(rv); + rw_init(&rpcnl_global_lock, rpcnl_family_name); +} + +CLIENT * +client_nl_create(const char *name, const rpcprog_t program, + const rpcvers_t version) +{ + CLIENT *cl; + struct nl_data *nl; + struct timeval now; + struct rpc_msg call_msg; + XDR xdrs; + uint32_t group; + bool rv __diagused; + + if ((group = genl_register_group(rpcnl_family_name, name)) == 0) + return (NULL); + + nl = malloc(sizeof(*nl), M_RPC, M_WAITOK); + *nl = (struct nl_data){ + .nl_pending = TAILQ_HEAD_INITIALIZER(nl->nl_pending), + .nl_hdr = { + .ghdr.cmd = RPCNL_REQUEST, + .gattr.nla_type = RPCNL_REQUEST_GROUP, + .gattr.nla_len = sizeof(struct nlattr) + + sizeof(uint32_t), + .group = group, + }, + .nl_wchan = rpcnl_family_name, + .nl_prio = PSOCK | PCATCH, + .nl_timo = 60 * hz, + .nl_retries = 1, + }; + mtx_init(&nl->nl_lock, "rpc_clnt_nl", NULL, MTX_DEF); + + /* + * Initialize and pre-serialize the static part of the call message. + */ + getmicrotime(&now); + nl->nl_xid = __RPC_GETXID(&now); + call_msg = (struct rpc_msg ){ + .rm_xid = nl->nl_xid, + .rm_direction = CALL, + .rm_call = { + .cb_rpcvers = RPC_MSG_VERSION, + .cb_prog = (uint32_t)program, + .cb_vers = (uint32_t)version, + }, + }; + + cl = malloc(sizeof(*cl), M_RPC, M_WAITOK); + *cl = (CLIENT){ + .cl_refs = 1, + .cl_ops = &clnt_nl_ops, + .cl_private = nl, + .cl_auth = authnone_create(), + }; + + /* + * Experimentally learn how many bytes does procedure name plus + * authnone header needs. Use nl_mcallc as temporary scratch space. + */ + xdrmem_create(&xdrs, nl->nl_mcallc, MCALL_MSG_SIZE, XDR_ENCODE); + rv = xdr_putint32(&xdrs, &(rpcproc_t){0}); + MPASS(rv); + rv = AUTH_MARSHALL(cl->cl_auth, 0, &xdrs, NULL); + MPASS(rv); + nl->nl_authlen = xdr_getpos(&xdrs); + xdr_destroy(&xdrs); + + xdrmem_create(&xdrs, nl->nl_mcallc, MCALL_MSG_SIZE, XDR_ENCODE); + rv = xdr_callhdr(&xdrs, &call_msg); + MPASS(rv); + nl->nl_mpos = xdr_getpos(&xdrs); + xdr_destroy(&xdrs); + + rw_wlock(&rpcnl_global_lock); + RB_INSERT(nl_data_t, &rpcnl_clients, nl); + rw_wunlock(&rpcnl_global_lock); + + return (cl); +} + +static enum clnt_stat +clnt_nl_call(CLIENT *cl, struct rpc_callextra *ext, rpcproc_t proc, + struct mbuf *args, struct mbuf **resultsp, struct timeval utimeout) +{ + struct nl_writer nw; + struct nl_data *nl = cl->cl_private; + struct ct_request *cr; + struct rpc_err *errp, err; + enum clnt_stat stat; + AUTH *auth; + XDR xdrs; + void *mem; + uint32_t len, xlen; + u_int retries = 0; + bool rv __diagused; + + cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK); + *cr = (struct ct_request){ + .cr_xid = atomic_fetchadd_32(&nl->nl_xid, 1), + .cr_error = ETIMEDOUT, + }; + + if (ext) { + auth = ext->rc_auth; + errp = &ext->rc_err; + len = RPC_MAXDATASIZE; /* XXXGL: can be improved */ + } else { + auth = cl->cl_auth; + errp = &err; + len = nl->nl_mpos + nl->nl_authlen + m_length(args, NULL); + } + + mem = malloc(len, M_RPC, M_WAITOK); +retry: + xdrmem_create(&xdrs, mem, len, XDR_ENCODE); + + rv = xdr_putbytes(&xdrs, nl->nl_mcallc, nl->nl_mpos); + MPASS(rv); + rv = xdr_putint32(&xdrs, &proc); + MPASS(rv); + if (!AUTH_MARSHALL(auth, cr->cr_xid, &xdrs, args)) { + stat = errp->re_status = RPC_CANTENCODEARGS; + goto out; + } else + stat = errp->re_status = RPC_SUCCESS; + + /* XXX: XID is the first thing in the request. */ + *(uint32_t *)mem = htonl(cr->cr_xid); + + xlen = xdr_getpos(&xdrs); + rv = nl_writer_group(&nw, xlen, NETLINK_GENERIC, nl->nl_hdr.group, + PRIV_NFS_DAEMON, true); + MPASS(rv); + + rv = nlmsg_add(&nw, 0, cr->cr_xid, rpcnl_family_id, 0, + sizeof(nl->nl_hdr) + sizeof(struct nlattr) + xlen); + MPASS(rv); + + memcpy(nlmsg_reserve_data_raw(&nw, sizeof(nl->nl_hdr)), &nl->nl_hdr, + sizeof(nl->nl_hdr)); + + rv = nlattr_add(&nw, RPCNL_REQUEST_BODY, xlen, mem); + MPASS(rv); + + rv = nlmsg_end(&nw); + MPASS(rv); + + mtx_lock(&nl->nl_lock); + TAILQ_INSERT_TAIL(&nl->nl_pending, cr, cr_link); + mtx_unlock(&nl->nl_lock); + + nlmsg_flush(&nw); + + mtx_lock(&nl->nl_lock); + if (__predict_true(cr->cr_error == ETIMEDOUT)) + (void)msleep(cr, &nl->nl_lock, nl->nl_prio, nl->nl_wchan, + (nl->nl_timo ? nl->nl_timo : tvtohz(&utimeout)) / + nl->nl_retries); + TAILQ_REMOVE(&nl->nl_pending, cr, cr_link); + mtx_unlock(&nl->nl_lock); + + if (__predict_true(cr->cr_error == 0)) { + struct rpc_msg reply_msg = { + .acpted_rply.ar_verf.oa_base = cr->cr_verf, + .acpted_rply.ar_results.proc = (xdrproc_t)xdr_void, + }; + + MPASS(cr->cr_mrep); + if (ext && ext->rc_feedback) + ext->rc_feedback(FEEDBACK_OK, proc, + ext->rc_feedback_arg); + xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE); + rv = xdr_replymsg(&xdrs, &reply_msg); + if (__predict_false(!rv)) { + stat = errp->re_status = RPC_CANTDECODERES; + goto out; + } + if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (reply_msg.acpted_rply.ar_stat == SUCCESS)) { + struct mbuf *results; + + stat = errp->re_status = RPC_SUCCESS; + results = xdrmbuf_getall(&xdrs); + if (__predict_true(AUTH_VALIDATE(auth, cr->cr_xid, + &reply_msg.acpted_rply.ar_verf, &results))) { + MPASS(results); + *resultsp = results; + /* end successful completion */ + } else { + stat = errp->re_status = RPC_AUTHERROR; + errp->re_why = AUTH_INVALIDRESP; + } + } else { + stat = _seterr_reply(&reply_msg, errp); + } + xdr_destroy(&xdrs); /* frees cr->cr_mrep */ + } else { + MPASS(cr->cr_mrep == NULL); + errp->re_errno = cr->cr_error; + stat = errp->re_status = RPC_CANTRECV; + if (cr->cr_error == ETIMEDOUT && ++retries < nl->nl_retries) { + cr->cr_xid = atomic_fetchadd_32(&nl->nl_xid, 1); + goto retry; + } + } +out: + free(cr, M_RPC); + free(mem, M_RPC); + + return (stat); +} + +static int +clnt_nl_reply(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + struct nl_reply_parsed attrs = {}; + struct nl_data *nl; + struct ct_request *cr; + struct mchain mc; + int error; + + if ((error = nl_parse_nlmsg(hdr, &rpcnl_parser, npt, &attrs)) != 0) + return (error); + if (attrs.data == NULL) + return (EINVAL); + + error = mc_get(&mc, NLA_DATA_LEN(attrs.data), M_WAITOK, MT_DATA, 0); + MPASS(error == 0); + m_copyback(mc_first(&mc), 0, NLA_DATA_LEN(attrs.data), + NLA_DATA(attrs.data)); + + rw_rlock(&rpcnl_global_lock); + if ((nl = RB_FIND(nl_data_t, &rpcnl_clients, + &(struct nl_data){ .nl_hdr.group = attrs.group })) == NULL) { + rw_runlock(&rpcnl_global_lock); + mc_freem(&mc); + return (EPROGUNAVAIL); + }; + mtx_lock(&nl->nl_lock); + rw_runlock(&rpcnl_global_lock); + + TAILQ_FOREACH(cr, &nl->nl_pending, cr_link) + if (cr->cr_xid == hdr->nlmsg_seq) + break; + if (cr == NULL) { + mtx_unlock(&nl->nl_lock); + mc_freem(&mc); + return (EPROCUNAVAIL); + } + cr->cr_mrep = mc_first(&mc); + cr->cr_error = 0; + wakeup(cr); + mtx_unlock(&nl->nl_lock); + + return (0); +} + +static void +clnt_nl_close(CLIENT *cl) +{ + struct nl_data *nl = cl->cl_private; + struct ct_request *cr; + + mtx_lock(&nl->nl_lock); + TAILQ_FOREACH(cr, &nl->nl_pending, cr_link) { + cr->cr_error = ESHUTDOWN; + wakeup(cr); + } + mtx_unlock(&nl->nl_lock); +} + +static void +clnt_nl_destroy(CLIENT *cl) +{ + struct nl_data *nl = cl->cl_private; + + MPASS(TAILQ_EMPTY(&nl->nl_pending)); + + rw_wlock(&rpcnl_global_lock); + RB_REMOVE(nl_data_t, &rpcnl_clients, nl); + rw_wlock(&rpcnl_global_lock); + + mtx_destroy(&nl->nl_lock); + free(nl, M_RPC); + free(cl, M_RPC); +} + +static bool_t +clnt_nl_control(CLIENT *cl, u_int request, void *info) +{ + struct nl_data *nl = (struct nl_data *)cl->cl_private; + + mtx_lock(&nl->nl_lock); + switch (request) { + case CLSET_TIMEOUT: + nl->nl_timo = tvtohz((struct timeval *)info); + break; + + case CLGET_TIMEOUT: + *(struct timeval *)info = + (struct timeval){.tv_sec = nl->nl_timo / hz}; + break; + + case CLSET_RETRIES: + nl->nl_retries = *(u_int *)info; + break; + + case CLSET_WAITCHAN: + nl->nl_wchan = (const char *)info; + break; + + case CLGET_WAITCHAN: + *(const char **)info = nl->nl_wchan; + break; + + case CLSET_INTERRUPTIBLE: + if (*(int *)info) + nl->nl_prio |= PCATCH; + else + nl->nl_prio &= ~PCATCH; + break; + + case CLGET_INTERRUPTIBLE: + *(int *)info = (nl->nl_prio & PCATCH) ? TRUE : FALSE; + break; + + default: + mtx_unlock(&nl->nl_lock); + printf("%s: unsupported request %u\n", __func__, request); + return (FALSE); + } + + mtx_unlock(&nl->nl_lock); + return (TRUE); +} diff --git a/sys/rpc/clnt_nl.h b/sys/rpc/clnt_nl.h new file mode 100644 index 000000000000..8b1c29ed7dd9 --- /dev/null +++ b/sys/rpc/clnt_nl.h @@ -0,0 +1,42 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org> + * + * 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. + */ + +#ifndef _RPC_CLNT_NL_H +#define _RPC_CLNT_NL_H + +enum rpcnl_cmds_t { + RPCNL_REQUEST = 1, /* mcast: kernel -> userland */ + RPCNL_REPLY, /* unicast: userland -> kernel */ +}; + +enum rpcnl_attr_t { + RPCNL_REQUEST_GROUP = 1, + RPCNL_REQUEST_BODY, + RPCNL_REPLY_GROUP, + RPCNL_REPLY_BODY, +}; +#endif /* _RPC_CLNT_NL_H */ diff --git a/sys/rpc/krpc.h b/sys/rpc/krpc.h index a5a34c8a4a8e..02c167d50d55 100644 --- a/sys/rpc/krpc.h +++ b/sys/rpc/krpc.h @@ -129,6 +129,8 @@ struct cf_conn { /* kept in xprt->xp_p1 for actual connection */ bool_t eor; /* reading last fragment of current record */ }; +void rpcnl_init(void); + #endif /* _KERNEL */ #endif /* _RPC_KRPC_H_ */ diff --git a/sys/rpc/rpc_generic.c b/sys/rpc/rpc_generic.c index 0d6c0f1b7c7d..b3cf2612bdbb 100644 --- a/sys/rpc/rpc_generic.c +++ b/sys/rpc/rpc_generic.c @@ -949,6 +949,7 @@ krpc_modevent(module_t mod, int type, void *data) switch (type) { case MOD_LOAD: + rpcnl_init(); error = rpctls_init(); break; case MOD_UNLOAD: @@ -967,7 +968,7 @@ static moduledata_t krpc_mod = { krpc_modevent, NULL, }; -DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY); +DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_FIRST); /* So that loader and kldload(2) can find us, wherever we are.. */ MODULE_VERSION(krpc, 1); |
