libnl 1.1.4
handlers.c
1/*
2 * lib/handlers.c default netlink message handlers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation version 2.1
7 * of the License.
8 *
9 * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
10 */
11
12/**
13 * @ingroup nl
14 * @defgroup cb Callbacks/Customization
15 * @brief
16 *
17 * Callbacks and overwriting capabilities are provided to take influence
18 * in various control flows inside the library. All callbacks are packed
19 * together in struct nl_cb which is then attached to a netlink socket or
20 * passed on to the respective functions directly.
21 *
22 * Callbacks can control the flow of the underlying layer by returning
23 * the appropriate error codes:
24 * @code
25 * Action ID | Description
26 * -----------------+-------------------------------------------------------
27 * NL_OK | Proceed with whatever comes next.
28 * NL_SKIP | Skip message currently being processed and continue
29 * | with next message.
30 * NL_STOP | Stop parsing and discard all remaining messages in
31 * | this set of messages.
32 * @endcode
33 *
34 * All callbacks are optional and a default action is performed if no
35 * application specific implementation is provided:
36 *
37 * @code
38 * Callback ID | Default Return Value
39 * ------------------+----------------------
40 * NL_CB_VALID | NL_OK
41 * NL_CB_FINISH | NL_STOP
42 * NL_CB_OVERRUN | NL_STOP
43 * NL_CB_SKIPPED | NL_SKIP
44 * NL_CB_ACK | NL_STOP
45 * NL_CB_MSG_IN | NL_OK
46 * NL_CB_MSG_OUT | NL_OK
47 * NL_CB_INVALID | NL_STOP
48 * NL_CB_SEQ_CHECK | NL_OK
49 * NL_CB_SEND_ACK | NL_OK
50 * |
51 * Error Callback | NL_STOP
52 * @endcode
53 *
54 * In order to simplify typical usages of the library, different sets of
55 * default callback implementations exist:
56 * @code
57 * NL_CB_DEFAULT: No additional actions
58 * NL_CB_VERBOSE: Automatically print warning and error messages to a file
59 * descriptor as appropriate. This is useful for CLI based
60 * applications.
61 * NL_CB_DEBUG: Print informal debugging information for each message
62 * received. This will result in every message beint sent or
63 * received to be printed to the screen in a decoded,
64 * human-readable format.
65 * @endcode
66 *
67 * @par 1) Setting up a callback set
68 * @code
69 * // Allocate a callback set and initialize it to the verbose default set
70 * struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE);
71 *
72 * // Modify the set to call my_func() for all valid messages
73 * nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL);
74 *
75 * // Set the error message handler to the verbose default implementation
76 * // and direct it to print all errors to the given file descriptor.
77 * FILE *file = fopen(...);
78 * nl_cb_err(cb, NL_CB_VERBOSE, NULL, file);
79 * @endcode
80 * @{
81 */
82
83#include <netlink-local.h>
84#include <netlink/netlink.h>
85#include <netlink/utils.h>
86#include <netlink/msg.h>
87#include <netlink/handlers.h>
88
89static void print_header_content(FILE *ofd, struct nlmsghdr *n)
90{
91 char flags[128];
92 char type[32];
93
94 fprintf(ofd, "type=%s length=%u flags=<%s> sequence-nr=%u pid=%u",
95 nl_nlmsgtype2str(n->nlmsg_type, type, sizeof(type)),
96 n->nlmsg_len, nl_nlmsg_flags2str(n->nlmsg_flags, flags,
97 sizeof(flags)), n->nlmsg_seq, n->nlmsg_pid);
98}
99
100static int nl_valid_handler_verbose(struct nl_msg *msg, void *arg)
101{
102 FILE *ofd = arg ? arg : stdout;
103
104 fprintf(ofd, "-- Warning: unhandled valid message: ");
105 print_header_content(ofd, nlmsg_hdr(msg));
106 fprintf(ofd, "\n");
107
108 return NL_OK;
109}
110
111static int nl_invalid_handler_verbose(struct nl_msg *msg, void *arg)
112{
113 FILE *ofd = arg ? arg : stderr;
114
115 fprintf(ofd, "-- Error: Invalid message: ");
116 print_header_content(ofd, nlmsg_hdr(msg));
117 fprintf(ofd, "\n");
118
119 return NL_STOP;
120}
121
122static int nl_overrun_handler_verbose(struct nl_msg *msg, void *arg)
123{
124 FILE *ofd = arg ? arg : stderr;
125
126 fprintf(ofd, "-- Error: Netlink Overrun: ");
127 print_header_content(ofd, nlmsg_hdr(msg));
128 fprintf(ofd, "\n");
129
130 return NL_STOP;
131}
132
133static int nl_error_handler_verbose(struct sockaddr_nl *who,
134 struct nlmsgerr *e, void *arg)
135{
136 FILE *ofd = arg ? arg : stderr;
137 char buf[256];
138
139 fprintf(ofd, "-- Error received: %s\n-- Original message: ",
140 strerror_r(-e->error, buf, sizeof(buf)));
141 print_header_content(ofd, &e->msg);
142 fprintf(ofd, "\n");
143
144 return e->error;
145}
146
147static int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
148{
149 FILE *ofd = arg ? arg : stderr;
150
151 fprintf(ofd, "-- Debug: Unhandled Valid message: ");
152 print_header_content(ofd, nlmsg_hdr(msg));
153 fprintf(ofd, "\n");
154
155 return NL_OK;
156}
157
158static int nl_finish_handler_debug(struct nl_msg *msg, void *arg)
159{
160 FILE *ofd = arg ? arg : stderr;
161
162 fprintf(ofd, "-- Debug: End of multipart message block: ");
163 print_header_content(ofd, nlmsg_hdr(msg));
164 fprintf(ofd, "\n");
165
166 return NL_STOP;
167}
168
169static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg)
170{
171 FILE *ofd = arg ? arg : stderr;
172
173 fprintf(ofd, "-- Debug: Received Message:\n");
174 nl_msg_dump(msg, ofd);
175
176 return NL_OK;
177}
178
179static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg)
180{
181 FILE *ofd = arg ? arg : stderr;
182
183 fprintf(ofd, "-- Debug: Sent Message:\n");
184 nl_msg_dump(msg, ofd);
185
186 return NL_OK;
187}
188
189static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg)
190{
191 FILE *ofd = arg ? arg : stderr;
192
193 fprintf(ofd, "-- Debug: Skipped message: ");
194 print_header_content(ofd, nlmsg_hdr(msg));
195 fprintf(ofd, "\n");
196
197 return NL_SKIP;
198}
199
200static int nl_ack_handler_debug(struct nl_msg *msg, void *arg)
201{
202 FILE *ofd = arg ? arg : stderr;
203
204 fprintf(ofd, "-- Debug: ACK: ");
205 print_header_content(ofd, nlmsg_hdr(msg));
206 fprintf(ofd, "\n");
207
208 return NL_STOP;
209}
210
211static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = {
212 [NL_CB_VALID] = {
213 [NL_CB_VERBOSE] = nl_valid_handler_verbose,
214 [NL_CB_DEBUG] = nl_valid_handler_debug,
215 },
216 [NL_CB_FINISH] = {
217 [NL_CB_DEBUG] = nl_finish_handler_debug,
218 },
219 [NL_CB_INVALID] = {
220 [NL_CB_VERBOSE] = nl_invalid_handler_verbose,
221 [NL_CB_DEBUG] = nl_invalid_handler_verbose,
222 },
223 [NL_CB_MSG_IN] = {
224 [NL_CB_DEBUG] = nl_msg_in_handler_debug,
225 },
226 [NL_CB_MSG_OUT] = {
227 [NL_CB_DEBUG] = nl_msg_out_handler_debug,
228 },
229 [NL_CB_OVERRUN] = {
230 [NL_CB_VERBOSE] = nl_overrun_handler_verbose,
231 [NL_CB_DEBUG] = nl_overrun_handler_verbose,
232 },
233 [NL_CB_SKIPPED] = {
234 [NL_CB_DEBUG] = nl_skipped_handler_debug,
235 },
236 [NL_CB_ACK] = {
237 [NL_CB_DEBUG] = nl_ack_handler_debug,
238 },
239};
240
241static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = {
242 [NL_CB_VERBOSE] = nl_error_handler_verbose,
243 [NL_CB_DEBUG] = nl_error_handler_verbose,
244};
245
246/**
247 * @name Callback Handle Management
248 * @{
249 */
250
251/**
252 * Allocate a new callback handle
253 * @arg kind callback kind to be used for initialization
254 * @return Newly allocated callback handle or NULL
255 */
256struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
257{
258 int i;
259 struct nl_cb *cb;
260
261 if (kind < 0 || kind > NL_CB_KIND_MAX)
262 return NULL;
263
264 cb = calloc(1, sizeof(*cb));
265 if (!cb) {
266 nl_errno(ENOMEM);
267 return NULL;
268 }
269
270 cb->cb_refcnt = 1;
271
272 for (i = 0; i <= NL_CB_TYPE_MAX; i++)
273 nl_cb_set(cb, i, kind, NULL, NULL);
274
275 nl_cb_err(cb, kind, NULL, NULL);
276
277 return cb;
278}
279
280/**
281 * Clone an existing callback handle
282 * @arg orig original callback handle
283 * @return Newly allocated callback handle being a duplicate of
284 * orig or NULL
285 */
286struct nl_cb *nl_cb_clone(struct nl_cb *orig)
287{
288 struct nl_cb *cb;
289
291 if (!cb)
292 return NULL;
293
294 memcpy(cb, orig, sizeof(*orig));
295 cb->cb_refcnt = 1;
296
297 return cb;
298}
299
300struct nl_cb *nl_cb_get(struct nl_cb *cb)
301{
302 cb->cb_refcnt++;
303
304 return cb;
305}
306
307void nl_cb_put(struct nl_cb *cb)
308{
309 if (!cb)
310 return;
311
312 cb->cb_refcnt--;
313
314 if (cb->cb_refcnt < 0)
315 BUG();
316
317 if (cb->cb_refcnt <= 0)
318 free(cb);
319}
320
321/** @} */
322
323/**
324 * @name Callback Setup
325 * @{
326 */
327
328/**
329 * Set up a callback
330 * @arg cb callback set
331 * @arg type callback to modify
332 * @arg kind kind of implementation
333 * @arg func callback function (NL_CB_CUSTOM)
334 * @arg arg argument passed to callback
335 *
336 * @return 0 on success or a negative error code
337 */
338int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
339 nl_recvmsg_msg_cb_t func, void *arg)
340{
341 if (type < 0 || type > NL_CB_TYPE_MAX)
342 return nl_error(ERANGE, "Callback type out of range");
343
344 if (kind < 0 || kind > NL_CB_KIND_MAX)
345 return nl_error(ERANGE, "Callback kind out of range");
346
347 if (kind == NL_CB_CUSTOM) {
348 cb->cb_set[type] = func;
349 cb->cb_args[type] = arg;
350 } else {
351 cb->cb_set[type] = cb_def[type][kind];
352 cb->cb_args[type] = arg;
353 }
354
355 return 0;
356}
357
358/**
359 * Set up a all callbacks
360 * @arg cb callback set
361 * @arg kind kind of callback
362 * @arg func callback function
363 * @arg arg argument to be passwd to callback function
364 *
365 * @return 0 on success or a negative error code
366 */
367int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
368 nl_recvmsg_msg_cb_t func, void *arg)
369{
370 int i, err;
371
372 for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
373 err = nl_cb_set(cb, i, kind, func, arg);
374 if (err < 0)
375 return err;
376 }
377
378 return 0;
379}
380
381/**
382 * Set up an error callback
383 * @arg cb callback set
384 * @arg kind kind of callback
385 * @arg func callback function
386 * @arg arg argument to be passed to callback function
387 */
388int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
389 nl_recvmsg_err_cb_t func, void *arg)
390{
391 if (kind < 0 || kind > NL_CB_KIND_MAX)
392 return nl_error(ERANGE, "Callback kind out of range");
393
394 if (kind == NL_CB_CUSTOM) {
395 cb->cb_err = func;
396 cb->cb_err_arg = arg;
397 } else {
398 cb->cb_err = cb_err_def[kind];
399 cb->cb_err_arg = arg;
400 }
401
402 return 0;
403}
404
405/** @} */
406
407/**
408 * @name Overwriting
409 * @{
410 */
411
412/**
413 * Overwrite internal calls to nl_recvmsgs()
414 * @arg cb callback set
415 * @arg func replacement callback for nl_recvmsgs()
416 */
417void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
418 int (*func)(struct nl_handle *, struct nl_cb *))
419{
420 cb->cb_recvmsgs_ow = func;
421}
422
423/**
424 * Overwrite internal calls to nl_recv()
425 * @arg cb callback set
426 * @arg func replacement callback for nl_recv()
427 */
428void nl_cb_overwrite_recv(struct nl_cb *cb,
429 int (*func)(struct nl_handle *, struct sockaddr_nl *,
430 unsigned char **, struct ucred **))
431{
432 cb->cb_recv_ow = func;
433}
434
435/**
436 * Overwrite internal calls to nl_send()
437 * @arg cb callback set
438 * @arg func replacement callback for nl_send()
439 */
440void nl_cb_overwrite_send(struct nl_cb *cb,
441 int (*func)(struct nl_handle *, struct nl_msg *))
442{
443 cb->cb_send_ow = func;
444}
445
446/** @} */
447
448/** @} */
int(* nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg)
nl_recvmsgs() callback for error message processing customization
Definition: handlers.h:50
void nl_cb_overwrite_recv(struct nl_cb *cb, int(*func)(struct nl_handle *, struct sockaddr_nl *, unsigned char **, struct ucred **))
Overwrite internal calls to nl_recv()
Definition: handlers.c:428
nl_cb_type
Callback types.
Definition: handlers.h:94
int(* nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg)
nl_recvmsgs() callback for message processing customization
Definition: handlers.h:41
nl_cb_kind
Callback kinds.
Definition: handlers.h:76
void nl_cb_overwrite_send(struct nl_cb *cb, int(*func)(struct nl_handle *, struct nl_msg *))
Overwrite internal calls to nl_send()
Definition: handlers.c:440
int 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)
Set up a callback.
Definition: handlers.c:338
int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func, void *arg)
Set up a all callbacks.
Definition: handlers.c:367
struct nl_cb * nl_cb_clone(struct nl_cb *orig)
Clone an existing callback handle.
Definition: handlers.c:286
void nl_cb_overwrite_recvmsgs(struct nl_cb *cb, int(*func)(struct nl_handle *, struct nl_cb *))
Overwrite internal calls to nl_recvmsgs()
Definition: handlers.c:417
struct nl_cb * nl_cb_alloc(enum nl_cb_kind kind)
Allocate a new callback handle.
Definition: handlers.c:256
int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, nl_recvmsg_err_cb_t func, void *arg)
Set up an error callback.
Definition: handlers.c:388
@ NL_STOP
Stop parsing altogether and discard remaining messages.
Definition: handlers.h:65
@ NL_OK
Proceed with wathever would come next.
Definition: handlers.h:61
@ NL_SKIP
Skip this message.
Definition: handlers.h:63
@ NL_CB_SKIPPED
Message wants to be skipped.
Definition: handlers.h:102
@ NL_CB_FINISH
Last message in a series of multi part messages received.
Definition: handlers.h:98
@ NL_CB_MSG_OUT
Called for every message sent out except for nl_sendto()
Definition: handlers.h:108
@ NL_CB_MSG_IN
Called for every message received.
Definition: handlers.h:106
@ NL_CB_OVERRUN
Report received that data was lost.
Definition: handlers.h:100
@ NL_CB_VALID
Message is valid.
Definition: handlers.h:96
@ NL_CB_ACK
Message is an acknowledge.
Definition: handlers.h:104
@ NL_CB_INVALID
Message is malformed and invalid.
Definition: handlers.h:110
@ NL_CB_DEFAULT
Default handlers (quiet)
Definition: handlers.h:78
@ NL_CB_CUSTOM
Customized handler specified by the user.
Definition: handlers.h:84
@ NL_CB_VERBOSE
Verbose default handlers (error messages printed)
Definition: handlers.h:80
@ NL_CB_DEBUG
Debug handlers for debugging.
Definition: handlers.h:82
void nl_msg_dump(struct nl_msg *msg, FILE *ofd)
Dump message in human readable format to file descriptor.
Definition: msg.c:947
struct nlmsghdr * nlmsg_hdr(struct nl_msg *n)
Return actual netlink message.
Definition: msg.c:643
Netlink error message.
struct nlmsghdr msg
Original netlink message causing the error.
int error
Error code (errno number)
Netlink message header.
uint32_t nlmsg_pid
Netlink PID of the proccess sending the message.
uint32_t nlmsg_len
Length of message including header.
uint16_t nlmsg_type
Message type (content type)
uint16_t nlmsg_flags
Message flags.
uint32_t nlmsg_seq
Sequence number.
Netlink socket address.
Definition: netlink-kernel.h:9