add packaging
[platform/upstream/libnl1.git] / lib / handlers.c
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-2006 Thomas Graf <tgraf@suug.ch>
10  */
11
12 /**
13  * @ingroup nl
14  * @defgroup cb Callbacks/Customization
15  * @brief
16  *
17  * Callbacks and overwriting capabilities are provided to take influence
18  * in various control flows inside the library. All callbacks are packed
19  * together in struct nl_cb which is then attached to a netlink socket or
20  * passed on to the respective functions directly.
21  *
22  * Callbacks can control the flow of the underlying layer by returning
23  * the appropriate error codes:
24  * @code
25  * Action ID        | Description
26  * -----------------+-------------------------------------------------------
27  * NL_OK       | Proceed with whatever comes next.
28  * NL_SKIP          | Skip message currently being processed and continue
29  *                  | with next message.
30  * NL_STOP          | Stop parsing and discard all remaining messages in
31  *                  | this set of messages.
32  * @endcode
33  *
34  * All callbacks are optional and a default action is performed if no 
35  * application specific implementation is provided:
36  *
37  * @code
38  * Callback ID       | Default Return Value
39  * ------------------+----------------------
40  * NL_CB_VALID       | NL_OK
41  * NL_CB_FINISH      | NL_STOP
42  * NL_CB_OVERRUN     | NL_STOP
43  * NL_CB_SKIPPED     | NL_SKIP
44  * NL_CB_ACK         | NL_STOP
45  * NL_CB_MSG_IN      | NL_OK
46  * NL_CB_MSG_OUT     | NL_OK
47  * NL_CB_INVALID     | NL_STOP
48  * NL_CB_SEQ_CHECK   | NL_OK
49  * NL_CB_SEND_ACK    | NL_OK
50  *                   |
51  * Error Callback    | NL_STOP
52  * @endcode
53  *
54  * In order to simplify typical usages of the library, different sets of
55  * default callback implementations exist:
56  * @code
57  * NL_CB_DEFAULT: No additional actions
58  * NL_CB_VERBOSE: Automatically print warning and error messages to a file
59  *                descriptor as appropriate. This is useful for CLI based
60  *                applications.
61  * NL_CB_DEBUG:   Print informal debugging information for each message
62  *                received. This will result in every message beint sent or
63  *                received to be printed to the screen in a decoded,
64  *                human-readable format.
65  * @endcode
66  *
67  * @par 1) Setting up a callback set
68  * @code
69  * // Allocate a callback set and initialize it to the verbose default set
70  * struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE);
71  *
72  * // Modify the set to call my_func() for all valid messages
73  * nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL);
74  *
75  * // Set the error message handler to the verbose default implementation
76  * // and direct it to print all errors to the given file descriptor.
77  * FILE *file = fopen(...);
78  * nl_cb_err(cb, NL_CB_VERBOSE, NULL, file);
79  * @endcode
80  * @{
81  */
82
83 #include <netlink-local.h>
84 #include <netlink/netlink.h>
85 #include <netlink/utils.h>
86 #include <netlink/msg.h>
87 #include <netlink/handlers.h>
88
89 static void print_header_content(FILE *ofd, struct nlmsghdr *n)
90 {
91         char flags[128];
92         char type[32];
93         
94         fprintf(ofd, "type=%s length=%u flags=<%s> sequence-nr=%u pid=%u",
95                 nl_nlmsgtype2str(n->nlmsg_type, type, sizeof(type)),
96                 n->nlmsg_len, nl_nlmsg_flags2str(n->nlmsg_flags, flags,
97                 sizeof(flags)), n->nlmsg_seq, n->nlmsg_pid);
98 }
99
100 static int nl_valid_handler_verbose(struct nl_msg *msg, void *arg)
101 {
102         FILE *ofd = arg ? arg : stdout;
103
104         fprintf(ofd, "-- Warning: unhandled valid message: ");
105         print_header_content(ofd, nlmsg_hdr(msg));
106         fprintf(ofd, "\n");
107
108         return NL_OK;
109 }
110
111 static int nl_invalid_handler_verbose(struct nl_msg *msg, void *arg)
112 {
113         FILE *ofd = arg ? arg : stderr;
114
115         fprintf(ofd, "-- Error: Invalid message: ");
116         print_header_content(ofd, nlmsg_hdr(msg));
117         fprintf(ofd, "\n");
118
119         return NL_STOP;
120 }
121
122 static int nl_overrun_handler_verbose(struct nl_msg *msg, void *arg)
123 {
124         FILE *ofd = arg ? arg : stderr;
125
126         fprintf(ofd, "-- Error: Netlink Overrun: ");
127         print_header_content(ofd, nlmsg_hdr(msg));
128         fprintf(ofd, "\n");
129         
130         return NL_STOP;
131 }
132
133 static int nl_error_handler_verbose(struct sockaddr_nl *who,
134                                     struct nlmsgerr *e, void *arg)
135 {
136         FILE *ofd = arg ? arg : stderr;
137
138         fprintf(ofd, "-- Error received: %s\n-- Original message: ",
139                 strerror(-e->error));
140         print_header_content(ofd, &e->msg);
141         fprintf(ofd, "\n");
142
143         return e->error;
144 }
145
146 static int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
147 {
148         FILE *ofd = arg ? arg : stderr;
149
150         fprintf(ofd, "-- Debug: Unhandled Valid message: ");
151         print_header_content(ofd, nlmsg_hdr(msg));
152         fprintf(ofd, "\n");
153
154         return NL_OK;
155 }
156
157 static int nl_finish_handler_debug(struct nl_msg *msg, void *arg)
158 {
159         FILE *ofd = arg ? arg : stderr;
160
161         fprintf(ofd, "-- Debug: End of multipart message block: ");
162         print_header_content(ofd, nlmsg_hdr(msg));
163         fprintf(ofd, "\n");
164         
165         return NL_STOP;
166 }
167
168 static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg)
169 {
170         FILE *ofd = arg ? arg : stderr;
171
172         fprintf(ofd, "-- Debug: Received Message:\n");
173         nl_msg_dump(msg, ofd);
174         
175         return NL_OK;
176 }
177
178 static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg)
179 {
180         FILE *ofd = arg ? arg : stderr;
181
182         fprintf(ofd, "-- Debug: Sent Message:\n");
183         nl_msg_dump(msg, ofd);
184
185         return NL_OK;
186 }
187
188 static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg)
189 {
190         FILE *ofd = arg ? arg : stderr;
191
192         fprintf(ofd, "-- Debug: Skipped message: ");
193         print_header_content(ofd, nlmsg_hdr(msg));
194         fprintf(ofd, "\n");
195
196         return NL_SKIP;
197 }
198
199 static int nl_ack_handler_debug(struct nl_msg *msg, void *arg)
200 {
201         FILE *ofd = arg ? arg : stderr;
202
203         fprintf(ofd, "-- Debug: ACK: ");
204         print_header_content(ofd, nlmsg_hdr(msg));
205         fprintf(ofd, "\n");
206
207         return NL_STOP;
208 }
209
210 static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = {
211         [NL_CB_VALID] = {
212                 [NL_CB_VERBOSE] = nl_valid_handler_verbose,
213                 [NL_CB_DEBUG]   = nl_valid_handler_debug,
214         },
215         [NL_CB_FINISH] = {
216                 [NL_CB_DEBUG]   = nl_finish_handler_debug,
217         },
218         [NL_CB_INVALID] = {
219                 [NL_CB_VERBOSE] = nl_invalid_handler_verbose,
220                 [NL_CB_DEBUG]   = nl_invalid_handler_verbose,
221         },
222         [NL_CB_MSG_IN] = {
223                 [NL_CB_DEBUG]   = nl_msg_in_handler_debug,
224         },
225         [NL_CB_MSG_OUT] = {
226                 [NL_CB_DEBUG]   = nl_msg_out_handler_debug,
227         },
228         [NL_CB_OVERRUN] = {
229                 [NL_CB_VERBOSE] = nl_overrun_handler_verbose,
230                 [NL_CB_DEBUG]   = nl_overrun_handler_verbose,
231         },
232         [NL_CB_SKIPPED] = {
233                 [NL_CB_DEBUG]   = nl_skipped_handler_debug,
234         },
235         [NL_CB_ACK] = {
236                 [NL_CB_DEBUG]   = nl_ack_handler_debug,
237         },
238 };
239
240 static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = {
241         [NL_CB_VERBOSE] = nl_error_handler_verbose,
242         [NL_CB_DEBUG]   = nl_error_handler_verbose,
243 };
244
245 /**
246  * @name Callback Handle Management
247  * @{
248  */
249
250 /**
251  * Allocate a new callback handle
252  * @arg kind            callback kind to be used for initialization
253  * @return Newly allocated callback handle or NULL
254  */
255 struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
256 {
257         int i;
258         struct nl_cb *cb;
259
260         if (kind < 0 || kind > NL_CB_KIND_MAX)
261                 return NULL;
262
263         cb = calloc(1, sizeof(*cb));
264         if (!cb) {
265                 nl_errno(ENOMEM);
266                 return NULL;
267         }
268
269         cb->cb_refcnt = 1;
270
271         for (i = 0; i <= NL_CB_TYPE_MAX; i++)
272                 nl_cb_set(cb, i, kind, NULL, NULL);
273
274         nl_cb_err(cb, kind, NULL, NULL);
275
276         return cb;
277 }
278
279 /**
280  * Clone an existing callback handle
281  * @arg orig            original callback handle
282  * @return Newly allocated callback handle being a duplicate of
283  *         orig or NULL
284  */
285 struct nl_cb *nl_cb_clone(struct nl_cb *orig)
286 {
287         struct nl_cb *cb;
288         
289         cb = nl_cb_alloc(NL_CB_DEFAULT);
290         if (!cb)
291                 return NULL;
292
293         memcpy(cb, orig, sizeof(*orig));
294         cb->cb_refcnt = 1;
295
296         return cb;
297 }
298
299 struct nl_cb *nl_cb_get(struct nl_cb *cb)
300 {
301         cb->cb_refcnt++;
302
303         return cb;
304 }
305
306 void nl_cb_put(struct nl_cb *cb)
307 {
308         if (!cb)
309                 return;
310
311         cb->cb_refcnt--;
312
313         if (cb->cb_refcnt < 0)
314                 BUG();
315
316         if (cb->cb_refcnt <= 0)
317                 free(cb);
318 }
319
320 /** @} */
321
322 /**
323  * @name Callback Setup
324  * @{
325  */
326
327 /**
328  * Set up a callback 
329  * @arg cb              callback set
330  * @arg type            callback to modify
331  * @arg kind            kind of implementation
332  * @arg func            callback function (NL_CB_CUSTOM)
333  * @arg arg             argument passed to callback
334  *
335  * @return 0 on success or a negative error code
336  */
337 int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
338               nl_recvmsg_msg_cb_t func, void *arg)
339 {
340         if (type < 0 || type > NL_CB_TYPE_MAX)
341                 return nl_error(ERANGE, "Callback type out of range");
342
343         if (kind < 0 || kind > NL_CB_KIND_MAX)
344                 return nl_error(ERANGE, "Callback kind out of range");
345
346         if (kind == NL_CB_CUSTOM) {
347                 cb->cb_set[type] = func;
348                 cb->cb_args[type] = arg;
349         } else {
350                 cb->cb_set[type] = cb_def[type][kind];
351                 cb->cb_args[type] = arg;
352         }
353
354         return 0;
355 }
356
357 /**
358  * Set up a all callbacks
359  * @arg cb              callback set
360  * @arg kind            kind of callback
361  * @arg func            callback function
362  * @arg arg             argument to be passwd to callback function
363  *
364  * @return 0 on success or a negative error code
365  */
366 int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
367                   nl_recvmsg_msg_cb_t func, void *arg)
368 {
369         int i, err;
370
371         for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
372                 err = nl_cb_set(cb, i, kind, func, arg);
373                 if (err < 0)
374                         return err;
375         }
376
377         return 0;
378 }
379
380 /**
381  * Set up an error callback
382  * @arg cb              callback set
383  * @arg kind            kind of callback
384  * @arg func            callback function
385  * @arg arg             argument to be passed to callback function
386  */
387 int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
388               nl_recvmsg_err_cb_t func, void *arg)
389 {
390         if (kind < 0 || kind > NL_CB_KIND_MAX)
391                 return nl_error(ERANGE, "Callback kind out of range");
392
393         if (kind == NL_CB_CUSTOM) {
394                 cb->cb_err = func;
395                 cb->cb_err_arg = arg;
396         } else {
397                 cb->cb_err = cb_err_def[kind];
398                 cb->cb_err_arg = arg;
399         }
400
401         return 0;
402 }
403
404 /** @} */
405
406 /**
407  * @name Overwriting
408  * @{
409  */
410
411 /**
412  * Overwrite internal calls to nl_recvmsgs()
413  * @arg cb              callback set
414  * @arg func            replacement callback for nl_recvmsgs()
415  */
416 void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
417                               int (*func)(struct nl_handle *, struct nl_cb *))
418 {
419         cb->cb_recvmsgs_ow = func;
420 }
421
422 /**
423  * Overwrite internal calls to nl_recv()
424  * @arg cb              callback set
425  * @arg func            replacement callback for nl_recv()
426  */
427 void nl_cb_overwrite_recv(struct nl_cb *cb,
428                           int (*func)(struct nl_handle *, struct sockaddr_nl *,
429                                       unsigned char **, struct ucred **))
430 {
431         cb->cb_recv_ow = func;
432 }
433
434 /**
435  * Overwrite internal calls to nl_send()
436  * @arg cb              callback set
437  * @arg func            replacement callback for nl_send()
438  */
439 void nl_cb_overwrite_send(struct nl_cb *cb,
440                           int (*func)(struct nl_handle *, struct nl_msg *))
441 {
442         cb->cb_send_ow = func;
443 }
444
445 /** @} */
446
447 /** @} */