/* SPDX-License-Identifier: GPL-2.0-only */ /* * Generic netlink handshake service * * Author: Chuck Lever * * Copyright (c) 2023, Oracle and/or its affiliates. */ #ifndef _INTERNAL_HANDSHAKE_H #define _INTERNAL_HANDSHAKE_H /* Per-net namespace context */ struct handshake_net { spinlock_t hn_lock; /* protects next 3 fields */ int hn_pending; int hn_pending_max; struct list_head hn_requests; unsigned long hn_flags; }; enum hn_flags_bits { HANDSHAKE_F_NET_DRAINING, }; struct handshake_proto; /* One handshake request */ struct handshake_req { struct list_head hr_list; struct rhash_head hr_rhash; unsigned long hr_flags; const struct handshake_proto *hr_proto; struct sock *hr_sk; void (*hr_odestruct)(struct sock *sk); /* Always the last field */ char hr_priv[]; }; enum hr_flags_bits { HANDSHAKE_F_REQ_COMPLETED, HANDSHAKE_F_REQ_SESSION, }; struct genl_info; /* Invariants for all handshake requests for one transport layer * security protocol */ struct handshake_proto { int hp_handler_class; size_t hp_privsize; unsigned long hp_flags; int (*hp_accept)(struct handshake_req *req, struct genl_info *info, int fd); void (*hp_done)(struct handshake_req *req, unsigned int status, struct genl_info *info); void (*hp_destroy)(struct handshake_req *req); }; enum hp_flags_bits { HANDSHAKE_F_PROTO_NOTIFY, }; /* alert.c */ int tls_alert_send(struct socket *sock, u8 level, u8 description); /* netlink.c */ int handshake_genl_notify(struct net *net, const struct handshake_proto *proto, gfp_t flags); struct nlmsghdr *handshake_genl_put(struct sk_buff *msg, struct genl_info *info); struct handshake_net *handshake_pernet(struct net *net); /* request.c */ struct handshake_req *handshake_req_alloc(const struct handshake_proto *proto, gfp_t flags); int handshake_req_hash_init(void); void handshake_req_hash_destroy(void); void *handshake_req_private(struct handshake_req *req); struct handshake_req *handshake_req_hash_lookup(struct sock *sk); struct handshake_req *handshake_req_next(struct handshake_net *hn, int class); int handshake_req_submit(struct socket *sock, struct handshake_req *req, gfp_t flags); void handshake_complete(struct handshake_req *req, unsigned int status, struct genl_info *info); bool handshake_req_cancel(struct sock *sk); #endif /* _INTERNAL_HANDSHAKE_H */