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 */ 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_UINT, 137 YNL_PT_NUL_STR, 138 YNL_PT_BITFIELD32, 139 }; 140 141 struct ynl_policy_attr { 142 enum ynl_policy_type type; 143 unsigned int len; 144 const char *name; 145 struct ynl_policy_nest *nest; 146 }; 147 148 struct ynl_policy_nest { 149 unsigned int max_attr; 150 struct ynl_policy_attr *table; 151 }; 152 153 struct ynl_parse_arg { 154 struct ynl_sock *ys; 155 struct ynl_policy_nest *rsp_policy; 156 void *data; 157 }; 158 159 struct ynl_dump_list_type { 160 struct ynl_dump_list_type *next; 161 unsigned char data[] __attribute__((aligned(8))); 162 }; 163 extern struct ynl_dump_list_type *YNL_LIST_END; 164 165 static inline bool ynl_dump_obj_is_last(void *obj) 166 { 167 unsigned long uptr = (unsigned long)obj; 168 169 uptr -= offsetof(struct ynl_dump_list_type, data); 170 return uptr == (unsigned long)YNL_LIST_END; 171 } 172 173 static inline void *ynl_dump_obj_next(void *obj) 174 { 175 unsigned long uptr = (unsigned long)obj; 176 struct ynl_dump_list_type *list; 177 178 uptr -= offsetof(struct ynl_dump_list_type, data); 179 list = (void *)uptr; 180 uptr = (unsigned long)list->next; 181 uptr += offsetof(struct ynl_dump_list_type, data); 182 183 return (void *)uptr; 184 } 185 186 struct ynl_ntf_base_type { 187 __u16 family; 188 __u8 cmd; 189 struct ynl_ntf_base_type *next; 190 void (*free)(struct ynl_ntf_base_type *ntf); 191 unsigned char data[] __attribute__((aligned(8))); 192 }; 193 194 extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE]; 195 196 struct nlmsghdr * 197 ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); 198 struct nlmsghdr * 199 ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); 200 201 int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); 202 203 int ynl_recv_ack(struct ynl_sock *ys, int ret); 204 int ynl_cb_null(const struct nlmsghdr *nlh, void *data); 205 206 /* YNL specific helpers used by the auto-generated code */ 207 208 struct ynl_req_state { 209 struct ynl_parse_arg yarg; 210 mnl_cb_t cb; 211 __u32 rsp_cmd; 212 }; 213 214 struct ynl_dump_state { 215 struct ynl_sock *ys; 216 struct ynl_policy_nest *rsp_policy; 217 void *first; 218 struct ynl_dump_list_type *last; 219 size_t alloc_sz; 220 mnl_cb_t cb; 221 __u32 rsp_cmd; 222 }; 223 224 struct ynl_ntf_info { 225 struct ynl_policy_nest *policy; 226 mnl_cb_t cb; 227 size_t alloc_sz; 228 void (*free)(struct ynl_ntf_base_type *ntf); 229 }; 230 231 int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, 232 struct ynl_req_state *yrs); 233 int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, 234 struct ynl_dump_state *yds); 235 236 void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); 237 int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); 238 239 #ifndef MNL_HAS_AUTO_SCALARS 240 static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr) 241 { 242 if (mnl_attr_get_len(attr) == 4) 243 return mnl_attr_get_u32(attr); 244 return mnl_attr_get_u64(attr); 245 } 246 247 static inline void 248 mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data) 249 { 250 if ((uint32_t)data == (uint64_t)data) 251 return mnl_attr_put_u32(nlh, type, data); 252 return mnl_attr_put_u64(nlh, type, data); 253 } 254 #endif 255 #endif 256