162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
262306a36Sopenharmony_ci#ifndef __YNL_C_H
362306a36Sopenharmony_ci#define __YNL_C_H 1
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <stddef.h>
662306a36Sopenharmony_ci#include <libmnl/libmnl.h>
762306a36Sopenharmony_ci#include <linux/genetlink.h>
862306a36Sopenharmony_ci#include <linux/types.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cistruct mnl_socket;
1162306a36Sopenharmony_cistruct nlmsghdr;
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci * User facing code
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistruct ynl_ntf_base_type;
1862306a36Sopenharmony_cistruct ynl_ntf_info;
1962306a36Sopenharmony_cistruct ynl_sock;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cienum ynl_error_code {
2262306a36Sopenharmony_ci	YNL_ERROR_NONE = 0,
2362306a36Sopenharmony_ci	__YNL_ERRNO_END = 4096,
2462306a36Sopenharmony_ci	YNL_ERROR_INTERNAL,
2562306a36Sopenharmony_ci	YNL_ERROR_EXPECT_ACK,
2662306a36Sopenharmony_ci	YNL_ERROR_EXPECT_MSG,
2762306a36Sopenharmony_ci	YNL_ERROR_UNEXPECT_MSG,
2862306a36Sopenharmony_ci	YNL_ERROR_ATTR_MISSING,
2962306a36Sopenharmony_ci	YNL_ERROR_ATTR_INVALID,
3062306a36Sopenharmony_ci	YNL_ERROR_UNKNOWN_NTF,
3162306a36Sopenharmony_ci	YNL_ERROR_INV_RESP,
3262306a36Sopenharmony_ci};
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/**
3562306a36Sopenharmony_ci * struct ynl_error - error encountered by YNL
3662306a36Sopenharmony_ci * @code:	errno (low values) or YNL error code (enum ynl_error_code)
3762306a36Sopenharmony_ci * @attr_offs:	offset of bad attribute (for very advanced users)
3862306a36Sopenharmony_ci * @msg:	error message
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * Error information for when YNL operations fail.
4162306a36Sopenharmony_ci * Users should interact with the err member of struct ynl_sock directly.
4262306a36Sopenharmony_ci * The main exception to that rule is ynl_sock_create().
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_cistruct ynl_error {
4562306a36Sopenharmony_ci	enum ynl_error_code code;
4662306a36Sopenharmony_ci	unsigned int attr_offs;
4762306a36Sopenharmony_ci	char msg[512];
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/**
5162306a36Sopenharmony_ci * struct ynl_family - YNL family info
5262306a36Sopenharmony_ci * Family description generated by codegen. Pass to ynl_sock_create().
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_cistruct ynl_family {
5562306a36Sopenharmony_ci/* private: */
5662306a36Sopenharmony_ci	const char *name;
5762306a36Sopenharmony_ci	const struct ynl_ntf_info *ntf_info;
5862306a36Sopenharmony_ci	unsigned int ntf_info_size;
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/**
6262306a36Sopenharmony_ci * struct ynl_sock - YNL wrapped netlink socket
6362306a36Sopenharmony_ci * @err: YNL error descriptor, cleared on every request.
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_cistruct ynl_sock {
6662306a36Sopenharmony_ci	struct ynl_error err;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* private: */
6962306a36Sopenharmony_ci	const struct ynl_family *family;
7062306a36Sopenharmony_ci	struct mnl_socket *sock;
7162306a36Sopenharmony_ci	__u32 seq;
7262306a36Sopenharmony_ci	__u32 portid;
7362306a36Sopenharmony_ci	__u16 family_id;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	unsigned int n_mcast_groups;
7662306a36Sopenharmony_ci	struct {
7762306a36Sopenharmony_ci		unsigned int id;
7862306a36Sopenharmony_ci		char name[GENL_NAMSIZ];
7962306a36Sopenharmony_ci	} *mcast_groups;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	struct ynl_ntf_base_type *ntf_first;
8262306a36Sopenharmony_ci	struct ynl_ntf_base_type **ntf_last_next;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	struct nlmsghdr *nlh;
8562306a36Sopenharmony_ci	struct ynl_policy_nest *req_policy;
8662306a36Sopenharmony_ci	unsigned char *tx_buf;
8762306a36Sopenharmony_ci	unsigned char *rx_buf;
8862306a36Sopenharmony_ci	unsigned char raw_buf[];
8962306a36Sopenharmony_ci};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistruct ynl_sock *
9262306a36Sopenharmony_ciynl_sock_create(const struct ynl_family *yf, struct ynl_error *e);
9362306a36Sopenharmony_civoid ynl_sock_destroy(struct ynl_sock *ys);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define ynl_dump_foreach(dump, iter)					\
9662306a36Sopenharmony_ci	for (typeof(dump->obj) *iter = &dump->obj;			\
9762306a36Sopenharmony_ci	     !ynl_dump_obj_is_last(iter);				\
9862306a36Sopenharmony_ci	     iter = ynl_dump_obj_next(iter))
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ciint ynl_subscribe(struct ynl_sock *ys, const char *grp_name);
10162306a36Sopenharmony_ciint ynl_socket_get_fd(struct ynl_sock *ys);
10262306a36Sopenharmony_ciint ynl_ntf_check(struct ynl_sock *ys);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/**
10562306a36Sopenharmony_ci * ynl_has_ntf() - check if socket has *parsed* notifications
10662306a36Sopenharmony_ci * @ys: active YNL socket
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * Note that this does not take into account notifications sitting
10962306a36Sopenharmony_ci * in netlink socket, just the notifications which have already been
11062306a36Sopenharmony_ci * read and parsed (e.g. during a ynl_ntf_check() call).
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_cistatic inline bool ynl_has_ntf(struct ynl_sock *ys)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	return ys->ntf_last_next != &ys->ntf_first;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_cistruct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_civoid ynl_ntf_free(struct ynl_ntf_base_type *ntf);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/*
12162306a36Sopenharmony_ci * YNL internals / low level stuff
12262306a36Sopenharmony_ci */
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/* Generic mnl helper code */
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cienum ynl_policy_type {
12762306a36Sopenharmony_ci	YNL_PT_REJECT = 1,
12862306a36Sopenharmony_ci	YNL_PT_IGNORE,
12962306a36Sopenharmony_ci	YNL_PT_NEST,
13062306a36Sopenharmony_ci	YNL_PT_FLAG,
13162306a36Sopenharmony_ci	YNL_PT_BINARY,
13262306a36Sopenharmony_ci	YNL_PT_U8,
13362306a36Sopenharmony_ci	YNL_PT_U16,
13462306a36Sopenharmony_ci	YNL_PT_U32,
13562306a36Sopenharmony_ci	YNL_PT_U64,
13662306a36Sopenharmony_ci	YNL_PT_NUL_STR,
13762306a36Sopenharmony_ci};
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistruct ynl_policy_attr {
14062306a36Sopenharmony_ci	enum ynl_policy_type type;
14162306a36Sopenharmony_ci	unsigned int len;
14262306a36Sopenharmony_ci	const char *name;
14362306a36Sopenharmony_ci	struct ynl_policy_nest *nest;
14462306a36Sopenharmony_ci};
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistruct ynl_policy_nest {
14762306a36Sopenharmony_ci	unsigned int max_attr;
14862306a36Sopenharmony_ci	struct ynl_policy_attr *table;
14962306a36Sopenharmony_ci};
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistruct ynl_parse_arg {
15262306a36Sopenharmony_ci	struct ynl_sock *ys;
15362306a36Sopenharmony_ci	struct ynl_policy_nest *rsp_policy;
15462306a36Sopenharmony_ci	void *data;
15562306a36Sopenharmony_ci};
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistruct ynl_dump_list_type {
15862306a36Sopenharmony_ci	struct ynl_dump_list_type *next;
15962306a36Sopenharmony_ci	unsigned char data[] __attribute__ ((aligned (8)));
16062306a36Sopenharmony_ci};
16162306a36Sopenharmony_ciextern struct ynl_dump_list_type *YNL_LIST_END;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic inline bool ynl_dump_obj_is_last(void *obj)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	unsigned long uptr = (unsigned long)obj;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	uptr -= offsetof(struct ynl_dump_list_type, data);
16862306a36Sopenharmony_ci	return uptr == (unsigned long)YNL_LIST_END;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic inline void *ynl_dump_obj_next(void *obj)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	unsigned long uptr = (unsigned long)obj;
17462306a36Sopenharmony_ci	struct ynl_dump_list_type *list;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	uptr -= offsetof(struct ynl_dump_list_type, data);
17762306a36Sopenharmony_ci	list = (void *)uptr;
17862306a36Sopenharmony_ci	uptr = (unsigned long)list->next;
17962306a36Sopenharmony_ci	uptr += offsetof(struct ynl_dump_list_type, data);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return (void *)uptr;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistruct ynl_ntf_base_type {
18562306a36Sopenharmony_ci	__u16 family;
18662306a36Sopenharmony_ci	__u8 cmd;
18762306a36Sopenharmony_ci	struct ynl_ntf_base_type *next;
18862306a36Sopenharmony_ci	void (*free)(struct ynl_ntf_base_type *ntf);
18962306a36Sopenharmony_ci	unsigned char data[] __attribute__ ((aligned (8)));
19062306a36Sopenharmony_ci};
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ciextern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE];
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistruct nlmsghdr *
19562306a36Sopenharmony_ciynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
19662306a36Sopenharmony_cistruct nlmsghdr *
19762306a36Sopenharmony_ciynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ciint ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ciint ynl_recv_ack(struct ynl_sock *ys, int ret);
20262306a36Sopenharmony_ciint ynl_cb_null(const struct nlmsghdr *nlh, void *data);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci/* YNL specific helpers used by the auto-generated code */
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistruct ynl_req_state {
20762306a36Sopenharmony_ci	struct ynl_parse_arg yarg;
20862306a36Sopenharmony_ci	mnl_cb_t cb;
20962306a36Sopenharmony_ci	__u32 rsp_cmd;
21062306a36Sopenharmony_ci};
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistruct ynl_dump_state {
21362306a36Sopenharmony_ci	struct ynl_sock *ys;
21462306a36Sopenharmony_ci	struct ynl_policy_nest *rsp_policy;
21562306a36Sopenharmony_ci	void *first;
21662306a36Sopenharmony_ci	struct ynl_dump_list_type *last;
21762306a36Sopenharmony_ci	size_t alloc_sz;
21862306a36Sopenharmony_ci	mnl_cb_t cb;
21962306a36Sopenharmony_ci	__u32 rsp_cmd;
22062306a36Sopenharmony_ci};
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistruct ynl_ntf_info {
22362306a36Sopenharmony_ci	struct ynl_policy_nest *policy;
22462306a36Sopenharmony_ci	mnl_cb_t cb;
22562306a36Sopenharmony_ci	size_t alloc_sz;
22662306a36Sopenharmony_ci	void (*free)(struct ynl_ntf_base_type *ntf);
22762306a36Sopenharmony_ci};
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ciint ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
23062306a36Sopenharmony_ci	     struct ynl_req_state *yrs);
23162306a36Sopenharmony_ciint ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
23262306a36Sopenharmony_ci		  struct ynl_dump_state *yds);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_civoid ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd);
23562306a36Sopenharmony_ciint ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci#endif
238