handlers.c revision 44d362409d5469aed47d19e7908d19bd194493a4
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
138	fprintf(ofd, "-- Error received: %s\n-- Original message: ",
139		strerror(-e->error));
140	print_header_content(ofd, &e->msg);
141	fprintf(ofd, "\n");
142
143	return e->error;
144}
145
146static int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
147{
148	FILE *ofd = arg ? arg : stderr;
149
150	fprintf(ofd, "-- Debug: Unhandled Valid message: ");
151	print_header_content(ofd, nlmsg_hdr(msg));
152	fprintf(ofd, "\n");
153
154	return NL_OK;
155}
156
157static int nl_finish_handler_debug(struct nl_msg *msg, void *arg)
158{
159	FILE *ofd = arg ? arg : stderr;
160
161	fprintf(ofd, "-- Debug: End of multipart message block: ");
162	print_header_content(ofd, nlmsg_hdr(msg));
163	fprintf(ofd, "\n");
164
165	return NL_STOP;
166}
167
168static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg)
169{
170	FILE *ofd = arg ? arg : stderr;
171
172	fprintf(ofd, "-- Debug: Received Message:\n");
173	nl_msg_dump(msg, ofd);
174
175	return NL_OK;
176}
177
178static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg)
179{
180	FILE *ofd = arg ? arg : stderr;
181
182	fprintf(ofd, "-- Debug: Sent Message:\n");
183	nl_msg_dump(msg, ofd);
184
185	return NL_OK;
186}
187
188static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg)
189{
190	FILE *ofd = arg ? arg : stderr;
191
192	fprintf(ofd, "-- Debug: Skipped message: ");
193	print_header_content(ofd, nlmsg_hdr(msg));
194	fprintf(ofd, "\n");
195
196	return NL_SKIP;
197}
198
199static int nl_ack_handler_debug(struct nl_msg *msg, void *arg)
200{
201	FILE *ofd = arg ? arg : stderr;
202
203	fprintf(ofd, "-- Debug: ACK: ");
204	print_header_content(ofd, nlmsg_hdr(msg));
205	fprintf(ofd, "\n");
206
207	return NL_STOP;
208}
209
210static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = {
211	[NL_CB_VALID] = {
212		[NL_CB_VERBOSE]	= nl_valid_handler_verbose,
213		[NL_CB_DEBUG]	= nl_valid_handler_debug,
214	},
215	[NL_CB_FINISH] = {
216		[NL_CB_DEBUG]	= nl_finish_handler_debug,
217	},
218	[NL_CB_INVALID] = {
219		[NL_CB_VERBOSE]	= nl_invalid_handler_verbose,
220		[NL_CB_DEBUG]	= nl_invalid_handler_verbose,
221	},
222	[NL_CB_MSG_IN] = {
223		[NL_CB_DEBUG]	= nl_msg_in_handler_debug,
224	},
225	[NL_CB_MSG_OUT] = {
226		[NL_CB_DEBUG]	= nl_msg_out_handler_debug,
227	},
228	[NL_CB_OVERRUN] = {
229		[NL_CB_VERBOSE]	= nl_overrun_handler_verbose,
230		[NL_CB_DEBUG]	= nl_overrun_handler_verbose,
231	},
232	[NL_CB_SKIPPED] = {
233		[NL_CB_DEBUG]	= nl_skipped_handler_debug,
234	},
235	[NL_CB_ACK] = {
236		[NL_CB_DEBUG]	= nl_ack_handler_debug,
237	},
238};
239
240static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = {
241	[NL_CB_VERBOSE]	= nl_error_handler_verbose,
242	[NL_CB_DEBUG]	= nl_error_handler_verbose,
243};
244
245/**
246 * @name Callback Handle Management
247 * @{
248 */
249
250/**
251 * Allocate a new callback handle
252 * @arg kind		callback kind to be used for initialization
253 * @return Newly allocated callback handle or NULL
254 */
255struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
256{
257	int i;
258	struct nl_cb *cb;
259
260	if (kind < 0 || kind > NL_CB_KIND_MAX)
261		return NULL;
262
263	cb = calloc(1, sizeof(*cb));
264	if (!cb) {
265		nl_errno(ENOMEM);
266		return NULL;
267	}
268
269	cb->cb_refcnt = 1;
270
271	for (i = 0; i <= NL_CB_TYPE_MAX; i++)
272		nl_cb_set(cb, i, kind, NULL, NULL);
273
274	nl_cb_err(cb, kind, NULL, NULL);
275
276	return cb;
277}
278
279/**
280 * Clone an existing callback handle
281 * @arg orig		original callback handle
282 * @return Newly allocated callback handle being a duplicate of
283 *         orig or NULL
284 */
285struct nl_cb *nl_cb_clone(struct nl_cb *orig)
286{
287	struct nl_cb *cb;
288
289	cb = nl_cb_alloc(NL_CB_DEFAULT);
290	if (!cb)
291		return NULL;
292
293	memcpy(cb, orig, sizeof(*orig));
294	cb->cb_refcnt = 1;
295
296	return cb;
297}
298
299struct nl_cb *nl_cb_get(struct nl_cb *cb)
300{
301	cb->cb_refcnt++;
302
303	return cb;
304}
305
306void nl_cb_put(struct nl_cb *cb)
307{
308	if (!cb)
309		return;
310
311	cb->cb_refcnt--;
312
313	if (cb->cb_refcnt < 0)
314		BUG();
315
316	if (cb->cb_refcnt <= 0)
317		free(cb);
318}
319
320/** @} */
321
322/**
323 * @name Callback Setup
324 * @{
325 */
326
327/**
328 * Set up a callback
329 * @arg cb		callback set
330 * @arg type		callback to modify
331 * @arg kind		kind of implementation
332 * @arg func		callback function (NL_CB_CUSTOM)
333 * @arg arg		argument passed to callback
334 *
335 * @return 0 on success or a negative error code
336 */
337int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
338	      nl_recvmsg_msg_cb_t func, void *arg)
339{
340	if (type < 0 || type > NL_CB_TYPE_MAX)
341		return nl_error(ERANGE, "Callback type out of range");
342
343	if (kind < 0 || kind > NL_CB_KIND_MAX)
344		return nl_error(ERANGE, "Callback kind out of range");
345
346	if (kind == NL_CB_CUSTOM) {
347		cb->cb_set[type] = func;
348		cb->cb_args[type] = arg;
349	} else {
350		cb->cb_set[type] = cb_def[type][kind];
351		cb->cb_args[type] = arg;
352	}
353
354	return 0;
355}
356
357/**
358 * Set up a all callbacks
359 * @arg cb		callback set
360 * @arg kind		kind of callback
361 * @arg func		callback function
362 * @arg arg		argument to be passwd to callback function
363 *
364 * @return 0 on success or a negative error code
365 */
366int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
367		  nl_recvmsg_msg_cb_t func, void *arg)
368{
369	int i, err;
370
371	for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
372		err = nl_cb_set(cb, i, kind, func, arg);
373		if (err < 0)
374			return err;
375	}
376
377	return 0;
378}
379
380/**
381 * Set up an error callback
382 * @arg cb		callback set
383 * @arg kind		kind of callback
384 * @arg func		callback function
385 * @arg arg		argument to be passed to callback function
386 */
387int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
388	      nl_recvmsg_err_cb_t func, void *arg)
389{
390	if (kind < 0 || kind > NL_CB_KIND_MAX)
391		return nl_error(ERANGE, "Callback kind out of range");
392
393	if (kind == NL_CB_CUSTOM) {
394		cb->cb_err = func;
395		cb->cb_err_arg = arg;
396	} else {
397		cb->cb_err = cb_err_def[kind];
398		cb->cb_err_arg = arg;
399	}
400
401	return 0;
402}
403
404/** @} */
405
406/**
407 * @name Overwriting
408 * @{
409 */
410
411/**
412 * Overwrite internal calls to nl_recvmsgs()
413 * @arg cb		callback set
414 * @arg func		replacement callback for nl_recvmsgs()
415 */
416void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
417			      int (*func)(struct nl_handle *, struct nl_cb *))
418{
419	cb->cb_recvmsgs_ow = func;
420}
421
422/**
423 * Overwrite internal calls to nl_recv()
424 * @arg cb		callback set
425 * @arg func		replacement callback for nl_recv()
426 */
427void nl_cb_overwrite_recv(struct nl_cb *cb,
428			  int (*func)(struct nl_handle *, struct sockaddr_nl *,
429				      unsigned char **, struct ucred **))
430{
431	cb->cb_recv_ow = func;
432}
433
434/**
435 * Overwrite internal calls to nl_send()
436 * @arg cb		callback set
437 * @arg func		replacement callback for nl_send()
438 */
439void nl_cb_overwrite_send(struct nl_cb *cb,
440			  int (*func)(struct nl_handle *, struct nl_msg *))
441{
442	cb->cb_send_ow = func;
443}
444
445/** @} */
446
447/** @} */
448