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