| /* SPDX-License-Identifier: GPL-2.0-only */ | |
| /* | |
| * Generic netlink handshake service | |
| * | |
| * Author: Chuck Lever <chuck.lever@oracle.com> | |
| * | |
| * 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 file; | |
| 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 file *hr_file; | |
| 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, | |
| 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, int status, | |
| struct genl_info *info); | |
| bool handshake_req_cancel(struct sock *sk); | |
| #endif /* _INTERNAL_HANDSHAKE_H */ |