1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2003-2008 Thomas Graf <[email protected]>
4 */
5
6 /**
7 * @ingroup core
8 * @defgroup cb Callbacks/Customization
9 *
10 * Related sections in the development guide:
11 * - @core_doc{core_cb, Callback Configuration}
12 *
13 * @{
14 *
15 * Header
16 * ------
17 * ~~~~{.c}
18 * #include <netlink/handlers.h>
19 * ~~~~
20 */
21
22 #include "nl-default.h"
23
24 #include <netlink/netlink.h>
25 #include <netlink/utils.h>
26 #include <netlink/msg.h>
27 #include <netlink/handlers.h>
28
29 #include "nl-core.h"
30 #include "nl-priv-dynamic-core/nl-core.h"
31
print_header_content(FILE * ofd,struct nlmsghdr * n)32 static void print_header_content(FILE *ofd, struct nlmsghdr *n)
33 {
34 char flags[128];
35 char type[32];
36
37 fprintf(ofd, "type=%s length=%u flags=<%s> sequence-nr=%u pid=%u",
38 nl_nlmsgtype2str(n->nlmsg_type, type, sizeof(type)),
39 n->nlmsg_len, nl_nlmsg_flags2str(n->nlmsg_flags, flags,
40 sizeof(flags)), n->nlmsg_seq, n->nlmsg_pid);
41 }
42
nl_valid_handler_verbose(struct nl_msg * msg,void * arg)43 static int nl_valid_handler_verbose(struct nl_msg *msg, void *arg)
44 {
45 FILE *ofd = arg ? arg : stdout;
46
47 fprintf(ofd, "-- Warning: unhandled valid message: ");
48 print_header_content(ofd, nlmsg_hdr(msg));
49 fprintf(ofd, "\n");
50
51 return NL_OK;
52 }
53
nl_invalid_handler_verbose(struct nl_msg * msg,void * arg)54 static int nl_invalid_handler_verbose(struct nl_msg *msg, void *arg)
55 {
56 FILE *ofd = arg ? arg : stderr;
57
58 fprintf(ofd, "-- Error: Invalid message: ");
59 print_header_content(ofd, nlmsg_hdr(msg));
60 fprintf(ofd, "\n");
61
62 return NL_STOP;
63 }
64
nl_overrun_handler_verbose(struct nl_msg * msg,void * arg)65 static int nl_overrun_handler_verbose(struct nl_msg *msg, void *arg)
66 {
67 FILE *ofd = arg ? arg : stderr;
68
69 fprintf(ofd, "-- Error: Netlink Overrun: ");
70 print_header_content(ofd, nlmsg_hdr(msg));
71 fprintf(ofd, "\n");
72
73 return NL_STOP;
74 }
75
nl_error_handler_verbose(struct sockaddr_nl * who,struct nlmsgerr * e,void * arg)76 static int nl_error_handler_verbose(struct sockaddr_nl *who,
77 struct nlmsgerr *e, void *arg)
78 {
79 FILE *ofd = arg ? arg : stderr;
80
81 fprintf(ofd, "-- Error received: %s\n-- Original message: ",
82 nl_strerror_l(-e->error));
83 print_header_content(ofd, &e->msg);
84 fprintf(ofd, "\n");
85
86 return -nl_syserr2nlerr(e->error);
87 }
88
nl_valid_handler_debug(struct nl_msg * msg,void * arg)89 static int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
90 {
91 FILE *ofd = arg ? arg : stderr;
92
93 fprintf(ofd, "-- Debug: Unhandled Valid message: ");
94 print_header_content(ofd, nlmsg_hdr(msg));
95 fprintf(ofd, "\n");
96
97 return NL_OK;
98 }
99
nl_finish_handler_debug(struct nl_msg * msg,void * arg)100 static int nl_finish_handler_debug(struct nl_msg *msg, void *arg)
101 {
102 FILE *ofd = arg ? arg : stderr;
103
104 fprintf(ofd, "-- Debug: End of multipart message block: ");
105 print_header_content(ofd, nlmsg_hdr(msg));
106 fprintf(ofd, "\n");
107
108 return NL_STOP;
109 }
110
nl_msg_in_handler_debug(struct nl_msg * msg,void * arg)111 static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg)
112 {
113 FILE *ofd = arg ? arg : stderr;
114
115 fprintf(ofd, "-- Debug: Received Message:\n");
116 nl_msg_dump(msg, ofd);
117
118 return NL_OK;
119 }
120
nl_msg_out_handler_debug(struct nl_msg * msg,void * arg)121 static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg)
122 {
123 FILE *ofd = arg ? arg : stderr;
124
125 fprintf(ofd, "-- Debug: Sent Message:\n");
126 nl_msg_dump(msg, ofd);
127
128 return NL_OK;
129 }
130
nl_skipped_handler_debug(struct nl_msg * msg,void * arg)131 static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg)
132 {
133 FILE *ofd = arg ? arg : stderr;
134
135 fprintf(ofd, "-- Debug: Skipped message: ");
136 print_header_content(ofd, nlmsg_hdr(msg));
137 fprintf(ofd, "\n");
138
139 return NL_SKIP;
140 }
141
nl_ack_handler_debug(struct nl_msg * msg,void * arg)142 static int nl_ack_handler_debug(struct nl_msg *msg, void *arg)
143 {
144 FILE *ofd = arg ? arg : stderr;
145
146 fprintf(ofd, "-- Debug: ACK: ");
147 print_header_content(ofd, nlmsg_hdr(msg));
148 fprintf(ofd, "\n");
149
150 return NL_STOP;
151 }
152
153 static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = {
154 [NL_CB_VALID] = {
155 [NL_CB_VERBOSE] = nl_valid_handler_verbose,
156 [NL_CB_DEBUG] = nl_valid_handler_debug,
157 },
158 [NL_CB_FINISH] = {
159 [NL_CB_DEBUG] = nl_finish_handler_debug,
160 },
161 [NL_CB_INVALID] = {
162 [NL_CB_VERBOSE] = nl_invalid_handler_verbose,
163 [NL_CB_DEBUG] = nl_invalid_handler_verbose,
164 },
165 [NL_CB_MSG_IN] = {
166 [NL_CB_DEBUG] = nl_msg_in_handler_debug,
167 },
168 [NL_CB_MSG_OUT] = {
169 [NL_CB_DEBUG] = nl_msg_out_handler_debug,
170 },
171 [NL_CB_OVERRUN] = {
172 [NL_CB_VERBOSE] = nl_overrun_handler_verbose,
173 [NL_CB_DEBUG] = nl_overrun_handler_verbose,
174 },
175 [NL_CB_SKIPPED] = {
176 [NL_CB_DEBUG] = nl_skipped_handler_debug,
177 },
178 [NL_CB_ACK] = {
179 [NL_CB_DEBUG] = nl_ack_handler_debug,
180 },
181 };
182
183 static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = {
184 [NL_CB_VERBOSE] = nl_error_handler_verbose,
185 [NL_CB_DEBUG] = nl_error_handler_verbose,
186 };
187
188 /**
189 * @name Callback Handle Management
190 * @{
191 */
192
193 /**
194 * Allocate a new callback handle
195 * @arg kind callback kind to be used for initialization
196 * @return Newly allocated callback handle or NULL
197 */
nl_cb_alloc(enum nl_cb_kind kind)198 struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
199 {
200 int i;
201 struct nl_cb *cb;
202
203 if ((unsigned int) kind > NL_CB_KIND_MAX)
204 return NULL;
205
206 cb = calloc(1, sizeof(*cb));
207 if (!cb)
208 return NULL;
209
210 cb->cb_refcnt = 1;
211 cb->cb_active = NL_CB_TYPE_MAX + 1;
212
213 for (i = 0; i <= NL_CB_TYPE_MAX; i++)
214 nl_cb_set(cb, i, kind, NULL, NULL);
215
216 nl_cb_err(cb, kind, NULL, NULL);
217
218 return cb;
219 }
220
221 /**
222 * Clone an existing callback handle
223 * @arg orig original callback handle
224 * @return Newly allocated callback handle being a duplicate of
225 * orig or NULL
226 */
nl_cb_clone(struct nl_cb * orig)227 struct nl_cb *nl_cb_clone(struct nl_cb *orig)
228 {
229 struct nl_cb *cb;
230
231 cb = nl_cb_alloc(NL_CB_DEFAULT);
232 if (!cb)
233 return NULL;
234
235 memcpy(cb, orig, sizeof(*orig));
236 cb->cb_refcnt = 1;
237
238 return cb;
239 }
240
nl_cb_get(struct nl_cb * cb)241 struct nl_cb *nl_cb_get(struct nl_cb *cb)
242 {
243 cb->cb_refcnt++;
244
245 return cb;
246 }
247
nl_cb_put(struct nl_cb * cb)248 void nl_cb_put(struct nl_cb *cb)
249 {
250 if (!cb)
251 return;
252
253 cb->cb_refcnt--;
254
255 if (cb->cb_refcnt < 0)
256 BUG();
257
258 if (cb->cb_refcnt <= 0)
259 free(cb);
260 }
261
262 /**
263 * Obtain type of current active callback
264 * @arg cb callback to query
265 *
266 * @return type or __NL_CB_TYPE_MAX if none active
267 */
nl_cb_active_type(struct nl_cb * cb)268 enum nl_cb_type nl_cb_active_type(struct nl_cb *cb)
269 {
270 return cb->cb_active;
271 }
272
273 /** @} */
274
275 /**
276 * @name Callback Setup
277 * @{
278 */
279
280 /**
281 * Set up a callback
282 * @arg cb callback set
283 * @arg type callback to modify
284 * @arg kind kind of implementation
285 * @arg func callback function (NL_CB_CUSTOM)
286 * @arg arg argument passed to callback
287 *
288 * @return 0 on success or a negative error code
289 */
nl_cb_set(struct nl_cb * cb,enum nl_cb_type type,enum nl_cb_kind kind,nl_recvmsg_msg_cb_t func,void * arg)290 int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
291 nl_recvmsg_msg_cb_t func, void *arg)
292 {
293 if ((unsigned int) type > NL_CB_TYPE_MAX)
294 return -NLE_RANGE;
295
296 if ((unsigned int) kind > NL_CB_KIND_MAX)
297 return -NLE_RANGE;
298
299 if (kind == NL_CB_CUSTOM) {
300 cb->cb_set[type] = func;
301 cb->cb_args[type] = arg;
302 } else {
303 cb->cb_set[type] = cb_def[type][kind];
304 cb->cb_args[type] = arg;
305 }
306
307 return 0;
308 }
309
310 /**
311 * Set up a all callbacks
312 * @arg cb callback set
313 * @arg kind kind of callback
314 * @arg func callback function
315 * @arg arg argument to be passwd to callback function
316 *
317 * @return 0 on success or a negative error code
318 */
nl_cb_set_all(struct nl_cb * cb,enum nl_cb_kind kind,nl_recvmsg_msg_cb_t func,void * arg)319 int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
320 nl_recvmsg_msg_cb_t func, void *arg)
321 {
322 int i, err;
323
324 for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
325 err = nl_cb_set(cb, i, kind, func, arg);
326 if (err < 0)
327 return err;
328 }
329
330 return 0;
331 }
332
333 /**
334 * Set up an error callback
335 * @arg cb callback set
336 * @arg kind kind of callback
337 * @arg func callback function
338 * @arg arg argument to be passed to callback function
339 */
nl_cb_err(struct nl_cb * cb,enum nl_cb_kind kind,nl_recvmsg_err_cb_t func,void * arg)340 int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
341 nl_recvmsg_err_cb_t func, void *arg)
342 {
343 if ((unsigned int) kind > NL_CB_KIND_MAX)
344 return -NLE_RANGE;
345
346 if (kind == NL_CB_CUSTOM) {
347 cb->cb_err = func;
348 cb->cb_err_arg = arg;
349 } else {
350 cb->cb_err = cb_err_def[kind];
351 cb->cb_err_arg = arg;
352 }
353
354 return 0;
355 }
356
357 /** @} */
358
359 /**
360 * @name Overwriting
361 * @{
362 */
363
364 /**
365 * Overwrite internal calls to nl_recvmsgs()
366 * @arg cb callback set
367 * @arg func replacement callback for nl_recvmsgs()
368 */
nl_cb_overwrite_recvmsgs(struct nl_cb * cb,int (* func)(struct nl_sock *,struct nl_cb *))369 void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
370 int (*func)(struct nl_sock *, struct nl_cb *))
371 {
372 cb->cb_recvmsgs_ow = func;
373 }
374
375 /**
376 * Overwrite internal calls to nl_recv()
377 * @arg cb callback set
378 * @arg func replacement callback for nl_recv()
379 */
nl_cb_overwrite_recv(struct nl_cb * cb,int (* func)(struct nl_sock *,struct sockaddr_nl *,unsigned char **,struct ucred **))380 void nl_cb_overwrite_recv(struct nl_cb *cb,
381 int (*func)(struct nl_sock *, struct sockaddr_nl *,
382 unsigned char **, struct ucred **))
383 {
384 cb->cb_recv_ow = func;
385 }
386
387 /**
388 * Overwrite internal calls to nl_send()
389 * @arg cb callback set
390 * @arg func replacement callback for nl_send()
391 */
nl_cb_overwrite_send(struct nl_cb * cb,int (* func)(struct nl_sock *,struct nl_msg *))392 void nl_cb_overwrite_send(struct nl_cb *cb,
393 int (*func)(struct nl_sock *, struct nl_msg *))
394 {
395 cb->cb_send_ow = func;
396 }
397
398 /** @} */
399
400 /** @} */
401