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