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 
print_header_content(FILE * ofd,struct nlmsghdr * n)39 static 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 
nl_valid_handler_verbose(struct nl_msg * msg,void * arg)50 static 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 
nl_invalid_handler_verbose(struct nl_msg * msg,void * arg)61 static 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 
nl_overrun_handler_verbose(struct nl_msg * msg,void * arg)72 static 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 
nl_error_handler_verbose(struct sockaddr_nl * who,struct nlmsgerr * e,void * arg)83 static 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 
nl_valid_handler_debug(struct nl_msg * msg,void * arg)96 static 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 
nl_finish_handler_debug(struct nl_msg * msg,void * arg)107 static 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 
nl_msg_in_handler_debug(struct nl_msg * msg,void * arg)118 static 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 
nl_msg_out_handler_debug(struct nl_msg * msg,void * arg)128 static 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 
nl_skipped_handler_debug(struct nl_msg * msg,void * arg)138 static 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 
nl_ack_handler_debug(struct nl_msg * msg,void * arg)149 static 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 
160 static 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 
190 static 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  */
nl_cb_alloc(enum nl_cb_kind kind)205 struct 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  */
nl_cb_clone(struct nl_cb * orig)233 struct 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 
nl_cb_get(struct nl_cb * cb)247 struct nl_cb *nl_cb_get(struct nl_cb *cb)
248 {
249 	cb->cb_refcnt++;
250 
251 	return cb;
252 }
253 
nl_cb_put(struct nl_cb * cb)254 void 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  */
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)285 int 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  */
nl_cb_set_all(struct nl_cb * cb,enum nl_cb_kind kind,nl_recvmsg_msg_cb_t func,void * arg)314 int 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  */
nl_cb_err(struct nl_cb * cb,enum nl_cb_kind kind,nl_recvmsg_err_cb_t func,void * arg)335 int 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  */
nl_cb_overwrite_recvmsgs(struct nl_cb * cb,int (* func)(struct nl_sock *,struct nl_cb *))364 void 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  */
nl_cb_overwrite_recv(struct nl_cb * cb,int (* func)(struct nl_sock *,struct sockaddr_nl *,unsigned char **,struct ucred **))375 void 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  */
nl_cb_overwrite_send(struct nl_cb * cb,int (* func)(struct nl_sock *,struct nl_msg *))387 void 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