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