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