/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ #ifndef __YNL_C_PRIV_H #define __YNL_C_PRIV_H 1 #include #include #include /* * 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); /* Attribute helpers */ static inline void *ynl_nlmsg_end_addr(const struct nlmsghdr *nlh) { return (char *)nlh + nlh->nlmsg_len; } static inline unsigned int ynl_attr_type(const struct nlattr *attr) { return attr->nla_type & NLA_TYPE_MASK; } static inline unsigned int ynl_attr_data_len(const struct nlattr *attr) { return attr->nla_len - NLA_HDRLEN; } static inline void *ynl_attr_data(const struct nlattr *attr) { return (unsigned char *)attr + NLA_HDRLEN; } static inline struct nlattr * ynl_attr_nest_start(struct nlmsghdr *nlh, unsigned int attr_type) { struct nlattr *attr; attr = ynl_nlmsg_end_addr(nlh); attr->nla_type = attr_type | NLA_F_NESTED; nlh->nlmsg_len += NLA_HDRLEN; return attr; } static inline void ynl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *attr) { attr->nla_len = (char *)ynl_nlmsg_end_addr(nlh) - (char *)attr; } static inline void ynl_attr_put(struct nlmsghdr *nlh, unsigned int attr_type, const void *value, size_t size) { struct nlattr *attr; attr = ynl_nlmsg_end_addr(nlh); attr->nla_type = attr_type; attr->nla_len = NLA_HDRLEN + size; memcpy(ynl_attr_data(attr), value, size); nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len); } static inline void ynl_attr_put_str(struct nlmsghdr *nlh, unsigned int attr_type, const char *str) { struct nlattr *attr; const char *end; attr = ynl_nlmsg_end_addr(nlh); attr->nla_type = attr_type; end = stpcpy(ynl_attr_data(attr), str); attr->nla_len = NLA_HDRLEN + NLA_ALIGN(end - (char *)ynl_attr_data(attr)); nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len); } static inline const char *ynl_attr_get_str(const struct nlattr *attr) { return (const char *)ynl_attr_data(attr); } static inline __s8 ynl_attr_get_s8(const struct nlattr *attr) { return *(__s8 *)ynl_attr_data(attr); } static inline __s16 ynl_attr_get_s16(const struct nlattr *attr) { return *(__s16 *)ynl_attr_data(attr); } static inline __s32 ynl_attr_get_s32(const struct nlattr *attr) { return *(__s32 *)ynl_attr_data(attr); } static inline __s64 ynl_attr_get_s64(const struct nlattr *attr) { __s64 tmp; memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp)); return tmp; } static inline __u8 ynl_attr_get_u8(const struct nlattr *attr) { return *(__u8 *)ynl_attr_data(attr); } static inline __u16 ynl_attr_get_u16(const struct nlattr *attr) { return *(__u16 *)ynl_attr_data(attr); } static inline __u32 ynl_attr_get_u32(const struct nlattr *attr) { return *(__u32 *)ynl_attr_data(attr); } static inline __u64 ynl_attr_get_u64(const struct nlattr *attr) { __u64 tmp; memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp)); return tmp; } static inline void ynl_attr_put_s8(struct nlmsghdr *nlh, unsigned int attr_type, __s8 value) { ynl_attr_put(nlh, attr_type, &value, sizeof(value)); } static inline void ynl_attr_put_s16(struct nlmsghdr *nlh, unsigned int attr_type, __s16 value) { ynl_attr_put(nlh, attr_type, &value, sizeof(value)); } static inline void ynl_attr_put_s32(struct nlmsghdr *nlh, unsigned int attr_type, __s32 value) { ynl_attr_put(nlh, attr_type, &value, sizeof(value)); } static inline void ynl_attr_put_s64(struct nlmsghdr *nlh, unsigned int attr_type, __s64 value) { ynl_attr_put(nlh, attr_type, &value, sizeof(value)); } static inline void ynl_attr_put_u8(struct nlmsghdr *nlh, unsigned int attr_type, __u8 value) { ynl_attr_put(nlh, attr_type, &value, sizeof(value)); } static inline void ynl_attr_put_u16(struct nlmsghdr *nlh, unsigned int attr_type, __u16 value) { ynl_attr_put(nlh, attr_type, &value, sizeof(value)); } static inline void ynl_attr_put_u32(struct nlmsghdr *nlh, unsigned int attr_type, __u32 value) { ynl_attr_put(nlh, attr_type, &value, sizeof(value)); } static inline void ynl_attr_put_u64(struct nlmsghdr *nlh, unsigned int attr_type, __u64 value) { ynl_attr_put(nlh, attr_type, &value, sizeof(value)); } static inline __u64 ynl_attr_get_uint(const struct nlattr *attr) { switch (ynl_attr_data_len(attr)) { case 4: return ynl_attr_get_u32(attr); case 8: return ynl_attr_get_u64(attr); default: return 0; } } static inline __s64 ynl_attr_get_sint(const struct nlattr *attr) { switch (ynl_attr_data_len(attr)) { case 4: return ynl_attr_get_s32(attr); case 8: return ynl_attr_get_s64(attr); default: return 0; } } static inline void ynl_attr_put_uint(struct nlmsghdr *nlh, __u16 type, __u64 data) { if ((__u32)data == (__u64)data) ynl_attr_put_u32(nlh, type, data); else ynl_attr_put_u64(nlh, type, data); } static inline void ynl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data) { if ((__s32)data == (__s64)data) ynl_attr_put_s32(nlh, type, data); else ynl_attr_put_s64(nlh, type, data); } #endif