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