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