1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 #ifndef __YNL_C_H
3 #define __YNL_C_H 1
4
5 #include <stddef.h>
6 #include <libmnl/libmnl.h>
7 #include <linux/genetlink.h>
8 #include <linux/types.h>
9
10 struct mnl_socket;
11 struct nlmsghdr;
12
13 /*
14 * User facing code
15 */
16
17 struct ynl_ntf_base_type;
18 struct ynl_ntf_info;
19 struct ynl_sock;
20
21 enum ynl_error_code {
22 YNL_ERROR_NONE = 0,
23 __YNL_ERRNO_END = 4096,
24 YNL_ERROR_INTERNAL,
25 YNL_ERROR_EXPECT_ACK,
26 YNL_ERROR_EXPECT_MSG,
27 YNL_ERROR_UNEXPECT_MSG,
28 YNL_ERROR_ATTR_MISSING,
29 YNL_ERROR_ATTR_INVALID,
30 YNL_ERROR_UNKNOWN_NTF,
31 YNL_ERROR_INV_RESP,
32 };
33
34 /**
35 * struct ynl_error - error encountered by YNL
36 * @code: errno (low values) or YNL error code (enum ynl_error_code)
37 * @attr_offs: offset of bad attribute (for very advanced users)
38 * @msg: error message
39 *
40 * Error information for when YNL operations fail.
41 * Users should interact with the err member of struct ynl_sock directly.
42 * The main exception to that rule is ynl_sock_create().
43 */
44 struct ynl_error {
45 enum ynl_error_code code;
46 unsigned int attr_offs;
47 char msg[512];
48 };
49
50 /**
51 * struct ynl_family - YNL family info
52 * Family description generated by codegen. Pass to ynl_sock_create().
53 */
54 struct ynl_family {
55 /* private: */
56 const char *name;
57 const struct ynl_ntf_info *ntf_info;
58 unsigned int ntf_info_size;
59 };
60
61 /**
62 * struct ynl_sock - YNL wrapped netlink socket
63 * @err: YNL error descriptor, cleared on every request.
64 */
65 struct ynl_sock {
66 struct ynl_error err;
67
68 /* private: */
69 const struct ynl_family *family;
70 struct mnl_socket *sock;
71 __u32 seq;
72 __u32 portid;
73 __u16 family_id;
74
75 unsigned int n_mcast_groups;
76 struct {
77 unsigned int id;
78 char name[GENL_NAMSIZ];
79 } *mcast_groups;
80
81 struct ynl_ntf_base_type *ntf_first;
82 struct ynl_ntf_base_type **ntf_last_next;
83
84 struct nlmsghdr *nlh;
85 struct ynl_policy_nest *req_policy;
86 unsigned char *tx_buf;
87 unsigned char *rx_buf;
88 unsigned char raw_buf[];
89 };
90
91 struct ynl_sock *
92 ynl_sock_create(const struct ynl_family *yf, struct ynl_error *e);
93 void ynl_sock_destroy(struct ynl_sock *ys);
94
95 #define ynl_dump_foreach(dump, iter) \
96 for (typeof(dump->obj) *iter = &dump->obj; \
97 !ynl_dump_obj_is_last(iter); \
98 iter = ynl_dump_obj_next(iter))
99
100 int ynl_subscribe(struct ynl_sock *ys, const char *grp_name);
101 int ynl_socket_get_fd(struct ynl_sock *ys);
102 int ynl_ntf_check(struct ynl_sock *ys);
103
104 /**
105 * ynl_has_ntf() - check if socket has *parsed* notifications
106 * @ys: active YNL socket
107 *
108 * Note that this does not take into account notifications sitting
109 * in netlink socket, just the notifications which have already been
110 * read and parsed (e.g. during a ynl_ntf_check() call).
111 */
ynl_has_ntf(struct ynl_sock * ys)112 static inline bool ynl_has_ntf(struct ynl_sock *ys)
113 {
114 return ys->ntf_last_next != &ys->ntf_first;
115 }
116 struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys);
117
118 void ynl_ntf_free(struct ynl_ntf_base_type *ntf);
119
120 /*
121 * YNL internals / low level stuff
122 */
123
124 /* Generic mnl helper code */
125
126 enum ynl_policy_type {
127 YNL_PT_REJECT = 1,
128 YNL_PT_IGNORE,
129 YNL_PT_NEST,
130 YNL_PT_FLAG,
131 YNL_PT_BINARY,
132 YNL_PT_U8,
133 YNL_PT_U16,
134 YNL_PT_U32,
135 YNL_PT_U64,
136 YNL_PT_NUL_STR,
137 };
138
139 struct ynl_policy_attr {
140 enum ynl_policy_type type;
141 unsigned int len;
142 const char *name;
143 struct ynl_policy_nest *nest;
144 };
145
146 struct ynl_policy_nest {
147 unsigned int max_attr;
148 struct ynl_policy_attr *table;
149 };
150
151 struct ynl_parse_arg {
152 struct ynl_sock *ys;
153 struct ynl_policy_nest *rsp_policy;
154 void *data;
155 };
156
157 struct ynl_dump_list_type {
158 struct ynl_dump_list_type *next;
159 unsigned char data[] __attribute__ ((aligned (8)));
160 };
161 extern struct ynl_dump_list_type *YNL_LIST_END;
162
ynl_dump_obj_is_last(void * obj)163 static inline bool ynl_dump_obj_is_last(void *obj)
164 {
165 unsigned long uptr = (unsigned long)obj;
166
167 uptr -= offsetof(struct ynl_dump_list_type, data);
168 return uptr == (unsigned long)YNL_LIST_END;
169 }
170
ynl_dump_obj_next(void * obj)171 static inline void *ynl_dump_obj_next(void *obj)
172 {
173 unsigned long uptr = (unsigned long)obj;
174 struct ynl_dump_list_type *list;
175
176 uptr -= offsetof(struct ynl_dump_list_type, data);
177 list = (void *)uptr;
178 uptr = (unsigned long)list->next;
179 uptr += offsetof(struct ynl_dump_list_type, data);
180
181 return (void *)uptr;
182 }
183
184 struct ynl_ntf_base_type {
185 __u16 family;
186 __u8 cmd;
187 struct ynl_ntf_base_type *next;
188 void (*free)(struct ynl_ntf_base_type *ntf);
189 unsigned char data[] __attribute__ ((aligned (8)));
190 };
191
192 extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE];
193
194 struct nlmsghdr *
195 ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
196 struct nlmsghdr *
197 ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
198
199 int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr);
200
201 int ynl_recv_ack(struct ynl_sock *ys, int ret);
202 int ynl_cb_null(const struct nlmsghdr *nlh, void *data);
203
204 /* YNL specific helpers used by the auto-generated code */
205
206 struct ynl_req_state {
207 struct ynl_parse_arg yarg;
208 mnl_cb_t cb;
209 __u32 rsp_cmd;
210 };
211
212 struct ynl_dump_state {
213 struct ynl_sock *ys;
214 struct ynl_policy_nest *rsp_policy;
215 void *first;
216 struct ynl_dump_list_type *last;
217 size_t alloc_sz;
218 mnl_cb_t cb;
219 __u32 rsp_cmd;
220 };
221
222 struct ynl_ntf_info {
223 struct ynl_policy_nest *policy;
224 mnl_cb_t cb;
225 size_t alloc_sz;
226 void (*free)(struct ynl_ntf_base_type *ntf);
227 };
228
229 int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
230 struct ynl_req_state *yrs);
231 int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
232 struct ynl_dump_state *yds);
233
234 void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd);
235 int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg);
236
237 #endif
238