Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F109267433
D48550.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D48550.diff
View Options
diff --git a/include/rpc/svc.h b/include/rpc/svc.h
--- a/include/rpc/svc.h
+++ b/include/rpc/svc.h
@@ -455,6 +455,12 @@
*/
extern SVCXPRT *svcunixfd_create(int, u_int, u_int);
+/*
+ * netlink(4) server creation. To be used to service requests that
+ * originate from an in-kernel client.
+ */
+extern SVCXPRT *svc_nl_create(const char *);
+
/*
* Memory based rpc (for speed check and testing)
*/
diff --git a/lib/libc/rpc/Makefile.inc b/lib/libc/rpc/Makefile.inc
--- a/lib/libc/rpc/Makefile.inc
+++ b/lib/libc/rpc/Makefile.inc
@@ -8,7 +8,7 @@
rpc_callmsg.c rpc_generic.c rpc_soc.c rpcb_clnt.c rpcb_prot.c \
rpcb_st_xdr.c rpcsec_gss_stub.c svc.c svc_auth.c svc_dg.c \
svc_auth_unix.c svc_generic.c svc_raw.c svc_run.c svc_simple.c \
- svc_vc.c
+ svc_vc.c svc_nl.c
# Secure-RPC
SRCS+= auth_time.c auth_des.c authdes_prot.c des_crypt.c des_soft.c \
diff --git a/lib/libc/rpc/Symbol.map b/lib/libc/rpc/Symbol.map
--- a/lib/libc/rpc/Symbol.map
+++ b/lib/libc/rpc/Symbol.map
@@ -199,6 +199,10 @@
__rpc_get_local_uid;
};
+FBSD_1.8 {
+ svc_nl_create;
+};
+
FBSDprivate_1.0 {
__des_crypt_LOCAL;
__key_encryptsession_pk_LOCAL;
diff --git a/lib/libc/rpc/rpc_generic.c b/lib/libc/rpc/rpc_generic.c
--- a/lib/libc/rpc/rpc_generic.c
+++ b/lib/libc/rpc/rpc_generic.c
@@ -95,7 +95,8 @@
{ "udp6", AF_INET6, IPPROTO_UDP },
{ "tcp6", AF_INET6, IPPROTO_TCP },
#endif
- { "local", AF_LOCAL, 0 }
+ { "local", AF_LOCAL, 0 },
+ { "netlink", AF_NETLINK, 0 },
};
#if 0
diff --git a/lib/libc/rpc/svc_nl.c b/lib/libc/rpc/svc_nl.c
new file mode 100644
--- /dev/null
+++ b/lib/libc/rpc/svc_nl.c
@@ -0,0 +1,300 @@
+/*-
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <rpc/rpc.h>
+#include <rpc/clnt_nl.h>
+
+#include <netlink/netlink.h>
+#include <netlink/netlink_generic.h>
+#include <netlink/netlink_snl.h>
+#include <netlink/netlink_snl_generic.h>
+
+#include "rpc_com.h"
+
+/*
+ * RPC server to serve a kernel RPC client(s) over netlink(4). See clnt_nl.c
+ * in sys/rpc as the counterpart.
+ *
+ * Upon creation the client will seek for specified multicast group within the
+ * generic netlink family named "rpc". Then it would listen for incoming
+ * messages, process them and send replies over the same netlink socket.
+ * See clnt_nl.c for more transport protocol implementation details.
+ */
+
+static void svc_nl_destroy(SVCXPRT *);
+static bool_t svc_nl_recv(SVCXPRT *, struct rpc_msg *);
+static bool_t svc_nl_reply(SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat svc_nl_stat(SVCXPRT *);
+static bool_t svc_nl_getargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t svc_nl_freeargs(SVCXPRT *, xdrproc_t, void *);
+
+static struct xp_ops nl_ops = {
+ .xp_recv = svc_nl_recv,
+ .xp_reply = svc_nl_reply,
+ .xp_stat = svc_nl_stat,
+ .xp_getargs = svc_nl_getargs,
+ .xp_freeargs = svc_nl_freeargs,
+ .xp_destroy = svc_nl_destroy,
+};
+
+struct nl_softc {
+ struct snl_state snl;
+ XDR xdrs;
+ struct nlmsghdr *hdr;
+ size_t mlen;
+ enum xprt_stat stat;
+ uint32_t xid;
+ uint32_t group;
+ uint16_t family;
+ u_int errline;
+ int error;
+};
+
+SVCXPRT *
+svc_nl_create(const char *service)
+{
+ static struct sockaddr_nl snl_null = {
+ .nl_len = sizeof(struct sockaddr_nl),
+ .nl_family = PF_NETLINK,
+ };
+ struct nl_softc *sc;
+ SVCXPRT *xprt;
+ void *buf = NULL;
+ uint16_t family;
+ ssize_t len = 1024;
+
+ if ((sc = calloc(1, sizeof(struct nl_softc))) == NULL)
+ return (NULL);
+ if (!snl_init(&sc->snl, NETLINK_GENERIC) || (sc->group =
+ snl_get_genl_mcast_group(&sc->snl, "rpc", service, &family)) == 0)
+ goto fail;
+ if (setsockopt(sc->snl.fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
+ &sc->group, sizeof(sc->group)) == -1)
+ goto fail;
+ if ((buf = malloc(len)) == NULL)
+ goto fail;
+ if ((xprt = svc_xprt_alloc()) == NULL)
+ goto fail;
+
+ sc->hdr = buf,
+ sc->mlen = len,
+ sc->stat = XPRT_IDLE,
+ sc->family = family;
+
+ xprt->xp_fd = sc->snl.fd,
+ xprt->xp_p1 = sc,
+ xprt->xp_ops = &nl_ops,
+ xprt->xp_rtaddr = (struct netbuf){
+ .maxlen = sizeof(struct sockaddr_nl),
+ .len = sizeof(struct sockaddr_nl),
+ .buf = &snl_null,
+ };
+ xprt_register(xprt);
+
+ return (xprt);
+fail:
+ free(buf);
+ snl_free(&sc->snl);
+ free(sc);
+ return (NULL);
+}
+
+static void
+svc_nl_destroy(SVCXPRT *xprt)
+{
+ struct nl_softc *sc = xprt->xp_p1;
+
+ snl_free(&sc->snl);
+ free(sc->hdr);
+ free(xprt->xp_p1);
+ svc_xprt_free(xprt);
+}
+
+#define DIE(sc) do { \
+ (sc)->stat = XPRT_DIED; \
+ (sc)->errline = __LINE__; \
+ (sc)->error = errno; \
+ return (FALSE); \
+} while (0)
+
+struct nl_request_parsed {
+ uint32_t group;
+ struct nlattr *data;
+};
+static const struct snl_attr_parser rpcnl_attr_parser[] = {
+#define OUT(field) offsetof(struct nl_request_parsed, field)
+ { .type = RPCNL_REQUEST_GROUP, .off = OUT(group),
+ .cb = snl_attr_get_uint32 },
+ { .type = RPCNL_REQUEST_BODY, .off = OUT(data), .cb = snl_attr_get_nla },
+#undef OUT
+};
+SNL_DECLARE_GENL_PARSER(request_parser, rpcnl_attr_parser);
+
+static bool_t
+svc_nl_recv(SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct nl_request_parsed req;
+ struct nl_softc *sc = xprt->xp_p1;
+ struct nlmsghdr *hdr = sc->hdr;
+
+ switch (sc->stat) {
+ case XPRT_IDLE:
+ if (recv(xprt->xp_fd, hdr, sizeof(struct nlmsghdr),
+ MSG_PEEK) != sizeof(struct nlmsghdr))
+ DIE(sc);
+ break;
+ case XPRT_MOREREQS:
+ sc->stat = XPRT_IDLE;
+ break;
+ case XPRT_DIED:
+ return (FALSE);
+ }
+
+ if (sc->mlen < hdr->nlmsg_len) {
+ if ((hdr = sc->hdr = realloc(hdr, hdr->nlmsg_len)) == NULL)
+ DIE(sc);
+ else
+ sc->mlen = hdr->nlmsg_len;
+ }
+ if (read(xprt->xp_fd, hdr, hdr->nlmsg_len) != hdr->nlmsg_len)
+ DIE(sc);
+
+ if (hdr->nlmsg_type != sc->family)
+ return (FALSE);
+
+ if (((struct genlmsghdr *)(hdr + 1))->cmd != RPCNL_REQUEST)
+ return (FALSE);
+
+ if (!snl_parse_nlmsg(NULL, hdr, &request_parser, &req))
+ return (FALSE);
+
+ if (req.group != sc->group)
+ return (FALSE);
+
+ xdrmem_create(&sc->xdrs, NLA_DATA(req.data), NLA_DATA_LEN(req.data),
+ XDR_DECODE);
+ if (xdr_callmsg(&sc->xdrs, msg)) {
+ /* XXX: assert that xid == nlmsg_seq? */
+ sc->xid = msg->rm_xid;
+ return (TRUE);
+ } else
+ return (FALSE);
+}
+
+static bool_t
+svc_nl_reply(SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct nl_softc *sc = xprt->xp_p1;
+ struct snl_state snl;
+ struct snl_writer nw;
+ struct nlattr *body;
+ bool_t rv;
+
+ msg->rm_xid = sc->xid;
+
+ if (__predict_false(!snl_clone(&snl, &sc->snl)))
+ return (FALSE);
+ snl_init_writer(&sc->snl, &nw);
+ snl_create_genl_msg_request(&nw, sc->family, RPCNL_REPLY);
+ snl_add_msg_attr_u32(&nw, RPCNL_REPLY_GROUP, sc->group);
+ body = snl_reserve_msg_attr_raw(&nw, RPCNL_REPLY_BODY, RPC_MAXDATASIZE);
+
+ xdrmem_create(&sc->xdrs, (char *)(body + 1), RPC_MAXDATASIZE,
+ XDR_ENCODE);
+
+ if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
+ msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
+ xdrproc_t xdr_proc;
+ char *xdr_where;
+ u_int pos;
+
+ xdr_proc = msg->acpted_rply.ar_results.proc;
+ xdr_where = msg->acpted_rply.ar_results.where;
+ msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
+ msg->acpted_rply.ar_results.where = NULL;
+
+ pos = xdr_getpos(&sc->xdrs);
+ if (!xdr_replymsg(&sc->xdrs, msg) ||
+ !SVCAUTH_WRAP(&SVC_AUTH(xprt), &sc->xdrs, xdr_proc,
+ xdr_where)) {
+ xdr_setpos(&sc->xdrs, pos);
+ rv = FALSE;
+ } else
+ rv = TRUE;
+ } else
+ rv = xdr_replymsg(&sc->xdrs, msg);
+
+ if (rv) {
+ /* snl_finalize_msg() really doesn't work for us */
+ body->nla_len = sizeof(struct nlattr) + xdr_getpos(&sc->xdrs);
+ nw.hdr->nlmsg_len = ((char *)body - (char *)nw.hdr) +
+ body->nla_len;
+ nw.hdr->nlmsg_type = sc->family;
+ nw.hdr->nlmsg_flags = NLM_F_REQUEST;
+ nw.hdr->nlmsg_seq = sc->xid;
+ if (write(xprt->xp_fd, nw.hdr, nw.hdr->nlmsg_len) !=
+ nw.hdr->nlmsg_len)
+ DIE(sc);
+ }
+
+ snl_free(&snl);
+
+ return (rv);
+}
+
+static enum xprt_stat
+svc_nl_stat(SVCXPRT *xprt)
+{
+ struct nl_softc *sc = xprt->xp_p1;
+
+ if (sc->stat == XPRT_IDLE &&
+ recv(xprt->xp_fd, sc->hdr, sizeof(struct nlmsghdr),
+ MSG_PEEK | MSG_DONTWAIT) == sizeof(struct nlmsghdr))
+ sc->stat = XPRT_MOREREQS;
+
+ return (sc->stat);
+}
+
+static bool_t
+svc_nl_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
+{
+ struct nl_softc *sc = xprt->xp_p1;
+
+ return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), &sc->xdrs, xdr_args, args_ptr));
+}
+
+static bool_t
+svc_nl_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
+{
+ struct nl_softc *sc = xprt->xp_p1;
+
+ sc->xdrs.x_op = XDR_FREE;
+ return ((*xdr_args)(&sc->xdrs, args_ptr));
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Feb 3, 7:58 PM (20 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16441601
Default Alt Text
D48550.diff (9 KB)
Attached To
Mode
D48550: libc/rpc: add userland side RPC server over netlink(4)
Attached
Detach File
Event Timeline
Log In to Comment