1/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ 2#ifndef __YNL_C_PRIV_H 3#define __YNL_C_PRIV_H 1 4 5#include <stdbool.h> 6#include <stddef.h> 7#include <linux/types.h> 8 9struct ynl_parse_arg; 10 11/* 12 * YNL internals / low level stuff 13 */ 14 15enum ynl_policy_type { 16 YNL_PT_REJECT = 1, 17 YNL_PT_IGNORE, 18 YNL_PT_NEST, 19 YNL_PT_FLAG, 20 YNL_PT_BINARY, 21 YNL_PT_U8, 22 YNL_PT_U16, 23 YNL_PT_U32, 24 YNL_PT_U64, 25 YNL_PT_UINT, 26 YNL_PT_NUL_STR, 27 YNL_PT_BITFIELD32, 28}; 29 30enum ynl_parse_result { 31 YNL_PARSE_CB_ERROR = -1, 32 YNL_PARSE_CB_STOP = 0, 33 YNL_PARSE_CB_OK = 1, 34}; 35 36#define YNL_SOCKET_BUFFER_SIZE (1 << 17) 37 38#define YNL_ARRAY_SIZE(array) (sizeof(array) ? \ 39 sizeof(array) / sizeof(array[0]) : 0) 40 41typedef int (*ynl_parse_cb_t)(const struct nlmsghdr *nlh, 42 struct ynl_parse_arg *yarg); 43 44struct ynl_policy_attr { 45 enum ynl_policy_type type; 46 unsigned int len; 47 const char *name; 48 struct ynl_policy_nest *nest; 49}; 50 51struct ynl_policy_nest { 52 unsigned int max_attr; 53 struct ynl_policy_attr *table; 54}; 55 56struct ynl_parse_arg { 57 struct ynl_sock *ys; 58 struct ynl_policy_nest *rsp_policy; 59 void *data; 60}; 61 62struct ynl_dump_list_type { 63 struct ynl_dump_list_type *next; 64 unsigned char data[] __attribute__((aligned(8))); 65}; 66extern struct ynl_dump_list_type *YNL_LIST_END; 67 68static inline bool ynl_dump_obj_is_last(void *obj) 69{ 70 unsigned long uptr = (unsigned long)obj; 71 72 uptr -= offsetof(struct ynl_dump_list_type, data); 73 return uptr == (unsigned long)YNL_LIST_END; 74} 75 76static inline void *ynl_dump_obj_next(void *obj) 77{ 78 unsigned long uptr = (unsigned long)obj; 79 struct ynl_dump_list_type *list; 80 81 uptr -= offsetof(struct ynl_dump_list_type, data); 82 list = (void *)uptr; 83 uptr = (unsigned long)list->next; 84 uptr += offsetof(struct ynl_dump_list_type, data); 85 86 return (void *)uptr; 87} 88 89struct ynl_ntf_base_type { 90 __u16 family; 91 __u8 cmd; 92 struct ynl_ntf_base_type *next; 93 void (*free)(struct ynl_ntf_base_type *ntf); 94 unsigned char data[] __attribute__((aligned(8))); 95}; 96 97struct nlmsghdr * 98ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); 99struct nlmsghdr * 100ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); 101 102int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); 103 104/* YNL specific helpers used by the auto-generated code */ 105 106struct ynl_req_state { 107 struct ynl_parse_arg yarg; 108 ynl_parse_cb_t cb; 109 __u32 rsp_cmd; 110}; 111 112struct ynl_dump_state { 113 struct ynl_parse_arg yarg; 114 void *first; 115 struct ynl_dump_list_type *last; 116 size_t alloc_sz; 117 ynl_parse_cb_t cb; 118 __u32 rsp_cmd; 119}; 120 121struct ynl_ntf_info { 122 struct ynl_policy_nest *policy; 123 ynl_parse_cb_t cb; 124 size_t alloc_sz; 125 void (*free)(struct ynl_ntf_base_type *ntf); 126}; 127 128int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, 129 struct ynl_req_state *yrs); 130int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, 131 struct ynl_dump_state *yds); 132 133void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); 134int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); 135 136/* Netlink message handling helpers */ 137 138#define YNL_MSG_OVERFLOW 1 139 140static inline struct nlmsghdr *ynl_nlmsg_put_header(void *buf) 141{ 142 struct nlmsghdr *nlh = buf; 143 144 memset(nlh, 0, sizeof(*nlh)); 145 nlh->nlmsg_len = NLMSG_HDRLEN; 146 147 return nlh; 148} 149 150static inline unsigned int ynl_nlmsg_data_len(const struct nlmsghdr *nlh) 151{ 152 return nlh->nlmsg_len - NLMSG_HDRLEN; 153} 154 155static inline void *ynl_nlmsg_data(const struct nlmsghdr *nlh) 156{ 157 return (unsigned char *)nlh + NLMSG_HDRLEN; 158} 159 160static inline void * 161ynl_nlmsg_data_offset(const struct nlmsghdr *nlh, unsigned int offset) 162{ 163 return (unsigned char *)nlh + NLMSG_HDRLEN + offset; 164} 165 166static inline void *ynl_nlmsg_end_addr(const struct nlmsghdr *nlh) 167{ 168 return (char *)nlh + nlh->nlmsg_len; 169} 170 171static inline void * 172ynl_nlmsg_put_extra_header(struct nlmsghdr *nlh, unsigned int size) 173{ 174 void *tail = ynl_nlmsg_end_addr(nlh); 175 176 nlh->nlmsg_len += NLMSG_ALIGN(size); 177 return tail; 178} 179 180/* Netlink attribute helpers */ 181 182static inline unsigned int ynl_attr_type(const struct nlattr *attr) 183{ 184 return attr->nla_type & NLA_TYPE_MASK; 185} 186 187static inline unsigned int ynl_attr_data_len(const struct nlattr *attr) 188{ 189 return attr->nla_len - NLA_HDRLEN; 190} 191 192static inline void *ynl_attr_data(const struct nlattr *attr) 193{ 194 return (unsigned char *)attr + NLA_HDRLEN; 195} 196 197static inline void *ynl_attr_data_end(const struct nlattr *attr) 198{ 199 return ynl_attr_data(attr) + ynl_attr_data_len(attr); 200} 201 202#define ynl_attr_for_each(attr, nlh, fixed_hdr_sz) \ 203 for ((attr) = ynl_attr_first(nlh, (nlh)->nlmsg_len, \ 204 NLMSG_HDRLEN + fixed_hdr_sz); attr; \ 205 (attr) = ynl_attr_next(ynl_nlmsg_end_addr(nlh), attr)) 206 207#define ynl_attr_for_each_nested(attr, outer) \ 208 for ((attr) = ynl_attr_first(outer, outer->nla_len, \ 209 sizeof(struct nlattr)); attr; \ 210 (attr) = ynl_attr_next(ynl_attr_data_end(outer), attr)) 211 212#define ynl_attr_for_each_payload(start, len, attr) \ 213 for ((attr) = ynl_attr_first(start, len, 0); attr; \ 214 (attr) = ynl_attr_next(start + len, attr)) 215 216static inline struct nlattr * 217ynl_attr_if_good(const void *end, struct nlattr *attr) 218{ 219 if (attr + 1 > (const struct nlattr *)end) 220 return NULL; 221 if (ynl_attr_data_end(attr) > end) 222 return NULL; 223 return attr; 224} 225 226static inline struct nlattr * 227ynl_attr_next(const void *end, const struct nlattr *prev) 228{ 229 struct nlattr *attr; 230 231 attr = (void *)((char *)prev + NLA_ALIGN(prev->nla_len)); 232 return ynl_attr_if_good(end, attr); 233} 234 235static inline struct nlattr * 236ynl_attr_first(const void *start, size_t len, size_t skip) 237{ 238 struct nlattr *attr; 239 240 attr = (void *)((char *)start + NLMSG_ALIGN(skip)); 241 return ynl_attr_if_good(start + len, attr); 242} 243 244static inline bool 245__ynl_attr_put_overflow(struct nlmsghdr *nlh, size_t size) 246{ 247 bool o; 248 249 /* ynl_msg_start() stashed buffer length in nlmsg_pid. */ 250 o = nlh->nlmsg_len + NLA_HDRLEN + NLMSG_ALIGN(size) > nlh->nlmsg_pid; 251 if (o) 252 /* YNL_MSG_OVERFLOW is < NLMSG_HDRLEN, all subsequent checks 253 * are guaranteed to fail. 254 */ 255 nlh->nlmsg_pid = YNL_MSG_OVERFLOW; 256 return o; 257} 258 259static inline struct nlattr * 260ynl_attr_nest_start(struct nlmsghdr *nlh, unsigned int attr_type) 261{ 262 struct nlattr *attr; 263 264 if (__ynl_attr_put_overflow(nlh, 0)) 265 return ynl_nlmsg_end_addr(nlh) - NLA_HDRLEN; 266 267 attr = ynl_nlmsg_end_addr(nlh); 268 attr->nla_type = attr_type | NLA_F_NESTED; 269 nlh->nlmsg_len += NLA_HDRLEN; 270 271 return attr; 272} 273 274static inline void 275ynl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *attr) 276{ 277 attr->nla_len = (char *)ynl_nlmsg_end_addr(nlh) - (char *)attr; 278} 279 280static inline void 281ynl_attr_put(struct nlmsghdr *nlh, unsigned int attr_type, 282 const void *value, size_t size) 283{ 284 struct nlattr *attr; 285 286 if (__ynl_attr_put_overflow(nlh, size)) 287 return; 288 289 attr = ynl_nlmsg_end_addr(nlh); 290 attr->nla_type = attr_type; 291 attr->nla_len = NLA_HDRLEN + size; 292 293 memcpy(ynl_attr_data(attr), value, size); 294 295 nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len); 296} 297 298static inline void 299ynl_attr_put_str(struct nlmsghdr *nlh, unsigned int attr_type, const char *str) 300{ 301 struct nlattr *attr; 302 size_t len; 303 304 len = strlen(str); 305 if (__ynl_attr_put_overflow(nlh, len)) 306 return; 307 308 attr = ynl_nlmsg_end_addr(nlh); 309 attr->nla_type = attr_type; 310 311 strcpy(ynl_attr_data(attr), str); 312 attr->nla_len = NLA_HDRLEN + NLA_ALIGN(len); 313 314 nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len); 315} 316 317static inline const char *ynl_attr_get_str(const struct nlattr *attr) 318{ 319 return (const char *)ynl_attr_data(attr); 320} 321 322static inline __s8 ynl_attr_get_s8(const struct nlattr *attr) 323{ 324 return *(__s8 *)ynl_attr_data(attr); 325} 326 327static inline __s16 ynl_attr_get_s16(const struct nlattr *attr) 328{ 329 return *(__s16 *)ynl_attr_data(attr); 330} 331 332static inline __s32 ynl_attr_get_s32(const struct nlattr *attr) 333{ 334 return *(__s32 *)ynl_attr_data(attr); 335} 336 337static inline __s64 ynl_attr_get_s64(const struct nlattr *attr) 338{ 339 __s64 tmp; 340 341 memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp)); 342 return tmp; 343} 344 345static inline __u8 ynl_attr_get_u8(const struct nlattr *attr) 346{ 347 return *(__u8 *)ynl_attr_data(attr); 348} 349 350static inline __u16 ynl_attr_get_u16(const struct nlattr *attr) 351{ 352 return *(__u16 *)ynl_attr_data(attr); 353} 354 355static inline __u32 ynl_attr_get_u32(const struct nlattr *attr) 356{ 357 return *(__u32 *)ynl_attr_data(attr); 358} 359 360static inline __u64 ynl_attr_get_u64(const struct nlattr *attr) 361{ 362 __u64 tmp; 363 364 memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp)); 365 return tmp; 366} 367 368static inline void 369ynl_attr_put_s8(struct nlmsghdr *nlh, unsigned int attr_type, __s8 value) 370{ 371 ynl_attr_put(nlh, attr_type, &value, sizeof(value)); 372} 373 374static inline void 375ynl_attr_put_s16(struct nlmsghdr *nlh, unsigned int attr_type, __s16 value) 376{ 377 ynl_attr_put(nlh, attr_type, &value, sizeof(value)); 378} 379 380static inline void 381ynl_attr_put_s32(struct nlmsghdr *nlh, unsigned int attr_type, __s32 value) 382{ 383 ynl_attr_put(nlh, attr_type, &value, sizeof(value)); 384} 385 386static inline void 387ynl_attr_put_s64(struct nlmsghdr *nlh, unsigned int attr_type, __s64 value) 388{ 389 ynl_attr_put(nlh, attr_type, &value, sizeof(value)); 390} 391 392static inline void 393ynl_attr_put_u8(struct nlmsghdr *nlh, unsigned int attr_type, __u8 value) 394{ 395 ynl_attr_put(nlh, attr_type, &value, sizeof(value)); 396} 397 398static inline void 399ynl_attr_put_u16(struct nlmsghdr *nlh, unsigned int attr_type, __u16 value) 400{ 401 ynl_attr_put(nlh, attr_type, &value, sizeof(value)); 402} 403 404static inline void 405ynl_attr_put_u32(struct nlmsghdr *nlh, unsigned int attr_type, __u32 value) 406{ 407 ynl_attr_put(nlh, attr_type, &value, sizeof(value)); 408} 409 410static inline void 411ynl_attr_put_u64(struct nlmsghdr *nlh, unsigned int attr_type, __u64 value) 412{ 413 ynl_attr_put(nlh, attr_type, &value, sizeof(value)); 414} 415 416static inline __u64 ynl_attr_get_uint(const struct nlattr *attr) 417{ 418 switch (ynl_attr_data_len(attr)) { 419 case 4: 420 return ynl_attr_get_u32(attr); 421 case 8: 422 return ynl_attr_get_u64(attr); 423 default: 424 return 0; 425 } 426} 427 428static inline __s64 ynl_attr_get_sint(const struct nlattr *attr) 429{ 430 switch (ynl_attr_data_len(attr)) { 431 case 4: 432 return ynl_attr_get_s32(attr); 433 case 8: 434 return ynl_attr_get_s64(attr); 435 default: 436 return 0; 437 } 438} 439 440static inline void 441ynl_attr_put_uint(struct nlmsghdr *nlh, __u16 type, __u64 data) 442{ 443 if ((__u32)data == (__u64)data) 444 ynl_attr_put_u32(nlh, type, data); 445 else 446 ynl_attr_put_u64(nlh, type, data); 447} 448 449static inline void 450ynl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data) 451{ 452 if ((__s32)data == (__s64)data) 453 ynl_attr_put_s32(nlh, type, data); 454 else 455 ynl_attr_put_s64(nlh, type, data); 456} 457#endif 458