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