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