238 lines
5.4 KiB
C
238 lines
5.4 KiB
C
|
// 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_NUL_STR,
|
||
|
};
|
||
|
|
||
|
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);
|
||
|
|
||
|
#endif
|