// SPDX-License-Identifier: GPL-2.0 /* * linux/fs/lockd/mon.c * * The kernel statd client. * * Copyright (C) 1996, Olaf Kirch <[email protected]> */ #include <linux/types.h> #include <linux/kernel.h> #include <linux/ktime.h> #include <linux/slab.h> #include <linux/sunrpc/clnt.h> #include <linux/sunrpc/addr.h> #include <linux/sunrpc/xprtsock.h> #include <linux/sunrpc/svc.h> #include <linux/lockd/lockd.h> #include <asm/unaligned.h> #include "netns.h" #define NLMDBG_FACILITY … #define NSM_PROGRAM … #define NSM_VERSION … enum { … }; struct nsm_args { … }; struct nsm_res { … }; static const struct rpc_program nsm_program; static DEFINE_SPINLOCK(nsm_lock); /* * Local NSM state */ u32 __read_mostly nsm_local_state; bool __read_mostly nsm_use_hostnames; static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) { … } static struct rpc_clnt *nsm_create(struct net *net, const char *nodename) { … } static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, const struct nlm_host *host) { … } /** * nsm_monitor - Notify a peer in case we reboot * @host: pointer to nlm_host of peer to notify * * If this peer is not already monitored, this function sends an * upcall to the local rpc.statd to record the name/address of * the peer to notify in case we reboot. * * Returns zero if the peer is monitored by the local rpc.statd; * otherwise a negative errno value is returned. */ int nsm_monitor(const struct nlm_host *host) { … } /** * nsm_unmonitor - Unregister peer notification * @host: pointer to nlm_host of peer to stop monitoring * * If this peer is monitored, this function sends an upcall to * tell the local rpc.statd not to send this peer a notification * when we reboot. */ void nsm_unmonitor(const struct nlm_host *host) { … } static struct nsm_handle *nsm_lookup_hostname(const struct list_head *nsm_handles, const char *hostname, const size_t len) { … } static struct nsm_handle *nsm_lookup_addr(const struct list_head *nsm_handles, const struct sockaddr *sap) { … } static struct nsm_handle *nsm_lookup_priv(const struct list_head *nsm_handles, const struct nsm_private *priv) { … } /* * Construct a unique cookie to match this nsm_handle to this monitored * host. It is passed to the local rpc.statd via NSMPROC_MON, and * returned via NLMPROC_SM_NOTIFY, in the "priv" field of these * requests. * * The NSM protocol requires that these cookies be unique while the * system is running. We prefer a stronger requirement of making them * unique across reboots. If user space bugs cause a stale cookie to * be sent to the kernel, it could cause the wrong host to lose its * lock state if cookies were not unique across reboots. * * The cookies are exposed only to local user space via loopback. They * do not appear on the physical network. If we want greater security * for some reason, nsm_init_private() could perform a one-way hash to * obscure the contents of the cookie. */ static void nsm_init_private(struct nsm_handle *nsm) { … } static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap, const size_t salen, const char *hostname, const size_t hostname_len) { … } /** * nsm_get_handle - Find or create a cached nsm_handle * @net: network namespace * @sap: pointer to socket address of handle to find * @salen: length of socket address * @hostname: pointer to C string containing hostname to find * @hostname_len: length of C string * * Behavior is modulated by the global nsm_use_hostnames variable. * * Returns a cached nsm_handle after bumping its ref count, or * returns a fresh nsm_handle if a handle that matches @sap and/or * @hostname cannot be found in the handle cache. Returns NULL if * an error occurs. */ struct nsm_handle *nsm_get_handle(const struct net *net, const struct sockaddr *sap, const size_t salen, const char *hostname, const size_t hostname_len) { … } /** * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle * @net: network namespace * @info: pointer to NLMPROC_SM_NOTIFY arguments * * Returns a matching nsm_handle if found in the nsm cache. The returned * nsm_handle's reference count is bumped. Otherwise returns NULL if some * error occurred. */ struct nsm_handle *nsm_reboot_lookup(const struct net *net, const struct nlm_reboot *info) { … } /** * nsm_release - Release an NSM handle * @nsm: pointer to handle to be released * */ void nsm_release(struct nsm_handle *nsm) { … } /* * XDR functions for NSM. * * See https://www.opengroup.org/ for details on the Network * Status Monitor wire protocol. */ static void encode_nsm_string(struct xdr_stream *xdr, const char *string) { … } /* * "mon_name" specifies the host to be monitored. */ static void encode_mon_name(struct xdr_stream *xdr, const struct nsm_args *argp) { … } /* * The "my_id" argument specifies the hostname and RPC procedure * to be called when the status manager receives notification * (via the NLMPROC_SM_NOTIFY call) that the state of host "mon_name" * has changed. */ static void encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp) { … } /* * The "mon_id" argument specifies the non-private arguments * of an NSMPROC_MON or NSMPROC_UNMON call. */ static void encode_mon_id(struct xdr_stream *xdr, const struct nsm_args *argp) { … } /* * The "priv" argument may contain private information required * by the NSMPROC_MON call. This information will be supplied in the * NLMPROC_SM_NOTIFY call. */ static void encode_priv(struct xdr_stream *xdr, const struct nsm_args *argp) { … } static void nsm_xdr_enc_mon(struct rpc_rqst *req, struct xdr_stream *xdr, const void *argp) { … } static void nsm_xdr_enc_unmon(struct rpc_rqst *req, struct xdr_stream *xdr, const void *argp) { … } static int nsm_xdr_dec_stat_res(struct rpc_rqst *rqstp, struct xdr_stream *xdr, void *data) { … } static int nsm_xdr_dec_stat(struct rpc_rqst *rqstp, struct xdr_stream *xdr, void *data) { … } #define SM_my_name_sz … #define SM_my_id_sz … #define SM_mon_name_sz … #define SM_mon_id_sz … #define SM_priv_sz … #define SM_mon_sz … #define SM_monres_sz … #define SM_unmonres_sz … static const struct rpc_procinfo nsm_procedures[] = …; static unsigned int nsm_version1_counts[ARRAY_SIZE(nsm_procedures)]; static const struct rpc_version nsm_version1 = …; static const struct rpc_version *nsm_version[] = …; static struct rpc_stat nsm_stats; static const struct rpc_program nsm_program = …;