| // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
| #ifndef __YNL_C_H |
| #define __YNL_C_H 1 |
| |
| #include <stddef.h> |
| #include <libmnl/libmnl.h> |
| #include <linux/genetlink.h> |
| #include <linux/types.h> |
| |
| struct mnl_socket; |
| struct nlmsghdr; |
| |
| /* |
| * User facing code |
| */ |
| |
| struct ynl_ntf_base_type; |
| struct ynl_ntf_info; |
| struct ynl_sock; |
| |
| enum ynl_error_code { |
| YNL_ERROR_NONE = 0, |
| __YNL_ERRNO_END = 4096, |
| YNL_ERROR_INTERNAL, |
| YNL_ERROR_EXPECT_ACK, |
| YNL_ERROR_EXPECT_MSG, |
| YNL_ERROR_UNEXPECT_MSG, |
| YNL_ERROR_ATTR_MISSING, |
| YNL_ERROR_ATTR_INVALID, |
| YNL_ERROR_UNKNOWN_NTF, |
| YNL_ERROR_INV_RESP, |
| }; |
| |
| /** |
| * struct ynl_error - error encountered by YNL |
| * @code: errno (low values) or YNL error code (enum ynl_error_code) |
| * @attr_offs: offset of bad attribute (for very advanced users) |
| * @msg: error message |
| * |
| * Error information for when YNL operations fail. |
| * Users should interact with the err member of struct ynl_sock directly. |
| * The main exception to that rule is ynl_sock_create(). |
| */ |
| struct ynl_error { |
| enum ynl_error_code code; |
| unsigned int attr_offs; |
| char msg[512]; |
| }; |
| |
| /** |
| * struct ynl_family - YNL family info |
| * Family description generated by codegen. Pass to ynl_sock_create(). |
| */ |
| struct ynl_family { |
| /* private: */ |
| const char *name; |
| const struct ynl_ntf_info *ntf_info; |
| unsigned int ntf_info_size; |
| }; |
| |
| /** |
| * struct ynl_sock - YNL wrapped netlink socket |
| * @err: YNL error descriptor, cleared on every request. |
| */ |
| struct ynl_sock { |
| struct ynl_error err; |
| |
| /* private: */ |
| const struct ynl_family *family; |
| struct mnl_socket *sock; |
| __u32 seq; |
| __u32 portid; |
| __u16 family_id; |
| |
| unsigned int n_mcast_groups; |
| struct { |
| unsigned int id; |
| char name[GENL_NAMSIZ]; |
| } *mcast_groups; |
| |
| struct ynl_ntf_base_type *ntf_first; |
| struct ynl_ntf_base_type **ntf_last_next; |
| |
| struct nlmsghdr *nlh; |
| struct ynl_policy_nest *req_policy; |
| unsigned char *tx_buf; |
| unsigned char *rx_buf; |
| unsigned char raw_buf[]; |
| }; |
| |
| struct ynl_sock * |
| ynl_sock_create(const struct ynl_family *yf, struct ynl_error *e); |
| void ynl_sock_destroy(struct ynl_sock *ys); |
| |
| #define ynl_dump_foreach(dump, iter) \ |
| for (typeof(dump->obj) *iter = &dump->obj; \ |
| !ynl_dump_obj_is_last(iter); \ |
| iter = ynl_dump_obj_next(iter)) |
| |
| int ynl_subscribe(struct ynl_sock *ys, const char *grp_name); |
| int ynl_socket_get_fd(struct ynl_sock *ys); |
| int ynl_ntf_check(struct ynl_sock *ys); |
| |
| /** |
| * ynl_has_ntf() - check if socket has *parsed* notifications |
| * @ys: active YNL socket |
| * |
| * Note that this does not take into account notifications sitting |
| * in netlink socket, just the notifications which have already been |
| * read and parsed (e.g. during a ynl_ntf_check() call). |
| */ |
| static inline bool ynl_has_ntf(struct ynl_sock *ys) |
| { |
| return ys->ntf_last_next != &ys->ntf_first; |
| } |
| struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys); |
| |
| void ynl_ntf_free(struct ynl_ntf_base_type *ntf); |
| |
| /* |
| * YNL internals / low level stuff |
| */ |
| |
| /* Generic mnl helper code */ |
| |
| enum ynl_policy_type { |
| YNL_PT_REJECT = 1, |
| YNL_PT_IGNORE, |
| YNL_PT_NEST, |
| YNL_PT_FLAG, |
| YNL_PT_BINARY, |
| YNL_PT_U8, |
| YNL_PT_U16, |
| YNL_PT_U32, |
| YNL_PT_U64, |
| YNL_PT_UINT, |
| YNL_PT_NUL_STR, |
| YNL_PT_BITFIELD32, |
| }; |
| |
| struct ynl_policy_attr { |
| enum ynl_policy_type type; |
| unsigned int len; |
| const char *name; |
| struct ynl_policy_nest *nest; |
| }; |
| |
| struct ynl_policy_nest { |
| unsigned int max_attr; |
| struct ynl_policy_attr *table; |
| }; |
| |
| struct ynl_parse_arg { |
| struct ynl_sock *ys; |
| struct ynl_policy_nest *rsp_policy; |
| void *data; |
| }; |
| |
| struct ynl_dump_list_type { |
| struct ynl_dump_list_type *next; |
| unsigned char data[] __attribute__((aligned(8))); |
| }; |
| extern struct ynl_dump_list_type *YNL_LIST_END; |
| |
| static inline bool ynl_dump_obj_is_last(void *obj) |
| { |
| unsigned long uptr = (unsigned long)obj; |
| |
| uptr -= offsetof(struct ynl_dump_list_type, data); |
| return uptr == (unsigned long)YNL_LIST_END; |
| } |
| |
| static inline void *ynl_dump_obj_next(void *obj) |
| { |
| unsigned long uptr = (unsigned long)obj; |
| struct ynl_dump_list_type *list; |
| |
| uptr -= offsetof(struct ynl_dump_list_type, data); |
| list = (void *)uptr; |
| uptr = (unsigned long)list->next; |
| uptr += offsetof(struct ynl_dump_list_type, data); |
| |
| return (void *)uptr; |
| } |
| |
| struct ynl_ntf_base_type { |
| __u16 family; |
| __u8 cmd; |
| struct ynl_ntf_base_type *next; |
| void (*free)(struct ynl_ntf_base_type *ntf); |
| unsigned char data[] __attribute__((aligned(8))); |
| }; |
| |
| extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE]; |
| |
| struct nlmsghdr * |
| ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); |
| struct nlmsghdr * |
| ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); |
| |
| int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); |
| |
| int ynl_recv_ack(struct ynl_sock *ys, int ret); |
| int ynl_cb_null(const struct nlmsghdr *nlh, void *data); |
| |
| /* YNL specific helpers used by the auto-generated code */ |
| |
| struct ynl_req_state { |
| struct ynl_parse_arg yarg; |
| mnl_cb_t cb; |
| __u32 rsp_cmd; |
| }; |
| |
| struct ynl_dump_state { |
| struct ynl_sock *ys; |
| struct ynl_policy_nest *rsp_policy; |
| void *first; |
| struct ynl_dump_list_type *last; |
| size_t alloc_sz; |
| mnl_cb_t cb; |
| __u32 rsp_cmd; |
| }; |
| |
| struct ynl_ntf_info { |
| struct ynl_policy_nest *policy; |
| mnl_cb_t cb; |
| size_t alloc_sz; |
| void (*free)(struct ynl_ntf_base_type *ntf); |
| }; |
| |
| int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, |
| struct ynl_req_state *yrs); |
| int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, |
| struct ynl_dump_state *yds); |
| |
| void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); |
| int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); |
| |
| #ifndef MNL_HAS_AUTO_SCALARS |
| static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr) |
| { |
| if (mnl_attr_get_len(attr) == 4) |
| return mnl_attr_get_u32(attr); |
| return mnl_attr_get_u64(attr); |
| } |
| |
| static inline void |
| mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data) |
| { |
| if ((uint32_t)data == (uint64_t)data) |
| return mnl_attr_put_u32(nlh, type, data); |
| return mnl_attr_put_u64(nlh, type, data); |
| } |
| #endif |
| #endif |