// SPDX-License-Identifier: GPL-2.0-only /* * Handshake request lifetime events * * Author: Chuck Lever <[email protected]> * * Copyright (c) 2023, Oracle and/or its affiliates. */ #include <linux/types.h> #include <linux/socket.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/skbuff.h> #include <linux/inet.h> #include <linux/fdtable.h> #include <linux/rhashtable.h> #include <net/sock.h> #include <net/genetlink.h> #include <net/netns/generic.h> #include <kunit/visibility.h> #include <uapi/linux/handshake.h> #include "handshake.h" #include <trace/events/handshake.h> /* * We need both a handshake_req -> sock mapping, and a sock -> * handshake_req mapping. Both are one-to-one. * * To avoid adding another pointer field to struct sock, net/handshake * maintains a hash table, indexed by the memory address of @sock, to * find the struct handshake_req outstanding for that socket. The * reverse direction uses a simple pointer field in the handshake_req * struct. */ static struct rhashtable handshake_rhashtbl ____cacheline_aligned_in_smp; static const struct rhashtable_params handshake_rhash_params = …; int handshake_req_hash_init(void) { … } void handshake_req_hash_destroy(void) { … } struct handshake_req *handshake_req_hash_lookup(struct sock *sk) { … } EXPORT_SYMBOL_IF_KUNIT(…); static bool handshake_req_hash_add(struct handshake_req *req) { … } static void handshake_req_destroy(struct handshake_req *req) { … } static void handshake_sk_destruct(struct sock *sk) { … } /** * handshake_req_alloc - Allocate a handshake request * @proto: security protocol * @flags: memory allocation flags * * Returns an initialized handshake_req or NULL. */ struct handshake_req *handshake_req_alloc(const struct handshake_proto *proto, gfp_t flags) { … } EXPORT_SYMBOL(…); /** * handshake_req_private - Get per-handshake private data * @req: handshake arguments * */ void *handshake_req_private(struct handshake_req *req) { … } EXPORT_SYMBOL(…); static bool __add_pending_locked(struct handshake_net *hn, struct handshake_req *req) { … } static void __remove_pending_locked(struct handshake_net *hn, struct handshake_req *req) { … } /* * Returns %true if the request was found on @net's pending list, * otherwise %false. * * If @req was on a pending list, it has not yet been accepted. */ static bool remove_pending(struct handshake_net *hn, struct handshake_req *req) { … } struct handshake_req *handshake_req_next(struct handshake_net *hn, int class) { … } EXPORT_SYMBOL_IF_KUNIT(…); /** * handshake_req_submit - Submit a handshake request * @sock: open socket on which to perform the handshake * @req: handshake arguments * @flags: memory allocation flags * * Return values: * %0: Request queued * %-EINVAL: Invalid argument * %-EBUSY: A handshake is already under way for this socket * %-ESRCH: No handshake agent is available * %-EAGAIN: Too many pending handshake requests * %-ENOMEM: Failed to allocate memory * %-EMSGSIZE: Failed to construct notification message * %-EOPNOTSUPP: Handshake module not initialized * * A zero return value from handshake_req_submit() means that * exactly one subsequent completion callback is guaranteed. * * A negative return value from handshake_req_submit() means that * no completion callback will be done and that @req has been * destroyed. */ int handshake_req_submit(struct socket *sock, struct handshake_req *req, gfp_t flags) { … } EXPORT_SYMBOL(…); void handshake_complete(struct handshake_req *req, unsigned int status, struct genl_info *info) { … } EXPORT_SYMBOL_IF_KUNIT(…); /** * handshake_req_cancel - Cancel an in-progress handshake * @sk: socket on which there is an ongoing handshake * * Request cancellation races with request completion. To determine * who won, callers examine the return value from this function. * * Return values: * %true - Uncompleted handshake request was canceled * %false - Handshake request already completed or not found */ bool handshake_req_cancel(struct sock *sk) { … } EXPORT_SYMBOL(…);