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