This commit was generated by cvs2svn to compensate for changes in r786,
[libnl.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  * 
16  * Customization via callbacks.
17  * @{
18  */
19
20 #include <netlink-local.h>
21 #include <netlink/netlink.h>
22 #include <netlink/utils.h>
23 #include <netlink/msg.h>
24 #include <netlink/handlers.h>
25
26 static void print_header_content(FILE *ofd, struct nlmsghdr *n)
27 {
28         char flags[128];
29         char type[32];
30         
31         fprintf(ofd, "type=%s length=%u flags=<%s> sequence-nr=%u pid=%u",
32                 nl_nlmsgtype2str(n->nlmsg_type, type, sizeof(type)),
33                 n->nlmsg_len, nl_nlmsg_flags2str(n->nlmsg_flags, flags,
34                 sizeof(flags)), n->nlmsg_seq, n->nlmsg_pid);
35 }
36
37 static inline void dump_hex(FILE *ofd, char *start, int len)
38 {
39         int i, a, c, limit;
40         char ascii[21] = {0};
41
42         limit = 18;
43         fprintf(ofd, "    ");
44
45         for (i = 0, a = 0, c = 0; i < len; i++) {
46                 int v = *(uint8_t *) (start + i);
47
48                 fprintf(ofd, "%02x ", v);
49                 ascii[a++] = isprint(v) ? v : '.';
50
51                 if (c == limit-1) {
52                         fprintf(ofd, "%s\n", ascii);
53                         if (i < (len - 1))
54                                 fprintf(ofd, "    ");
55                         a = c = 0;
56                         memset(ascii, 0, sizeof(ascii));
57                 } else
58                         c++;
59         }
60
61         if (c != 0) {
62                 for (i = 0; i < (limit - c); i++)
63                         fprintf(ofd, "   ");
64                 fprintf(ofd, "%s\n", ascii);
65         }
66 }
67
68 static void print_hdr(FILE *ofd, struct nl_msg *msg)
69 {
70         struct nlmsghdr *nlh = nlmsg_hdr(msg);
71         struct nl_cache_ops *ops;
72         char buf[128];
73
74         fprintf(ofd, "    .nlmsg_len = %d\n", nlh->nlmsg_len);
75
76         ops = nl_cache_mngt_associate(nlmsg_get_proto(msg), nlh->nlmsg_type);
77
78         fprintf(ofd, "    .nlmsg_type = %d <%s>\n", nlh->nlmsg_type,
79                 ops ? nl_cache_mngt_type2name(ops, nlh->nlmsg_type,
80                                               buf, sizeof(buf))
81                 : nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf)));
82         fprintf(ofd, "    .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags,
83                 nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf)));
84         fprintf(ofd, "    .nlmsg_seq = %d\n", nlh->nlmsg_seq);
85         fprintf(ofd, "    .nlmsg_pid = %d\n", nlh->nlmsg_pid);
86
87 }
88
89 static void raw_dump_msg(FILE *ofd, struct nl_msg *msg)
90 {
91         struct nlmsghdr *hdr = nlmsg_hdr(msg);
92         
93         fprintf(ofd, 
94         "--------------------------   BEGIN NETLINK MESSAGE "
95         "---------------------------\n");
96
97         fprintf(ofd, "  [HEADER] %Zu octets\n", sizeof(struct nlmsghdr));
98         print_hdr(ofd, msg);
99
100         if (hdr->nlmsg_type == NLMSG_ERROR &&
101             hdr->nlmsg_len >= nlmsg_msg_size(sizeof(struct nlmsgerr))) {
102                 struct nl_msg *errmsg;
103                 struct nlmsgerr *err = nlmsg_data(hdr);
104
105                 fprintf(ofd, "  [ERRORMSG] %Zu octets\n", sizeof(*err));
106                 fprintf(ofd, "    .error = %d \"%s\"\n", err->error,
107                         strerror(-err->error));
108                 fprintf(ofd, "  [ORIGINAL MESSAGE] %Zu octets\n", sizeof(*hdr));
109
110                 errmsg = nlmsg_build(&err->msg);
111                 print_hdr(ofd, errmsg);
112                 nlmsg_free(msg);
113         } else if (nlmsg_len(hdr) > 0) {
114                 struct nl_cache_ops *ops;
115                 int payloadlen = nlmsg_len(hdr);
116                 int attrlen = 0;
117
118                 ops = nl_cache_mngt_associate(nlmsg_get_proto(msg),
119                                               hdr->nlmsg_type);
120                 if (ops) {
121                         attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
122                         payloadlen -= attrlen;
123                 }
124
125                 fprintf(ofd, "  [PAYLOAD] %d octets\n", payloadlen);
126                 dump_hex(ofd, nlmsg_data(hdr), payloadlen);
127
128                 if (attrlen) {
129                         int rem, padlen;
130                         struct nlattr *nla;
131         
132                         nlmsg_for_each_attr(nla, hdr, ops->co_hdrsize, rem) {
133                                 int alen = nla_len(nla);
134
135                                 fprintf(ofd, "  [ATTR %02d] %d octets\n",
136                                         nla->nla_type, alen);
137                                 dump_hex(ofd, nla_data(nla), alen);
138
139                                 padlen = nla_padlen(alen);
140                                 if (padlen > 0) {
141                                         fprintf(ofd, "  [PADDING] %d octets\n",
142                                                 padlen);
143                                         dump_hex(ofd, nla_data(nla) + alen,
144                                                  padlen);
145                                 }
146                         }
147                 }
148         }
149
150         fprintf(ofd, 
151         "---------------------------  END NETLINK MESSAGE   "
152         "---------------------------\n");
153 }
154
155 static int nl_valid_handler_default(struct nl_msg *msg, void *arg)
156 {
157         return NL_PROCEED;
158 }
159
160 static int nl_finish_handler_default(struct nl_msg *msg, void *arg)
161 {
162         return NL_EXIT;
163 }
164
165 static int nl_invalid_handler_default(struct nl_msg *msg, void *arg)
166 {
167         return NL_EXIT;
168 }
169
170 static int nl_msg_in_handler_default(struct nl_msg *msg, void *arg)
171 {
172         return NL_PROCEED;
173 }
174
175 static int nl_msg_out_handler_default(struct nl_msg *msg, void *arg)
176 {
177         return NL_PROCEED;
178 }
179
180 static int nl_overrun_handler_default(struct nl_msg *msg, void *arg)
181 {
182         return NL_EXIT;
183 }
184
185 static int nl_skipped_handler_default(struct nl_msg *msg, void *arg)
186 {
187         return NL_SKIP;
188 }
189
190 static int nl_ack_handler_default(struct nl_msg *msg, void *arg)
191 {
192         return NL_EXIT;
193 }
194
195 static int nl_error_handler_default(struct sockaddr_nl *who,
196                                     struct nlmsgerr *e, void *arg)
197 {
198         return NL_EXIT;
199 }
200
201 static int nl_valid_handler_verbose(struct nl_msg *msg, void *arg)
202 {
203         FILE *ofd = arg ? arg : stdout;
204
205         fprintf(ofd, "-- Warning: unhandled valid message: ");
206         print_header_content(ofd, nlmsg_hdr(msg));
207         fprintf(ofd, "\n");
208
209         return NL_PROCEED;
210 }
211
212 static int nl_finish_handler_verbose(struct nl_msg *msg, void *arg)
213 {
214         return NL_EXIT;
215 }
216
217 static int nl_msg_in_handler_verbose(struct nl_msg *msg, void *arg)
218 {
219         return NL_PROCEED;
220 }
221
222 static int nl_invalid_handler_verbose(struct nl_msg *msg, void *arg)
223 {
224         FILE *ofd = arg ? arg : stderr;
225
226         fprintf(ofd, "-- Error: Invalid message: ");
227         print_header_content(ofd, nlmsg_hdr(msg));
228         fprintf(ofd, "\n");
229
230         return NL_EXIT;
231 }
232
233 static int nl_msg_out_handler_verbose(struct nl_msg *msg, void *arg)
234 {
235         return NL_PROCEED;
236 }
237
238 static int nl_overrun_handler_verbose(struct nl_msg *msg, void *arg)
239 {
240         FILE *ofd = arg ? arg : stderr;
241
242         fprintf(ofd, "-- Error: Netlink Overrun: ");
243         print_header_content(ofd, nlmsg_hdr(msg));
244         fprintf(ofd, "\n");
245         
246         return NL_EXIT;
247 }
248
249 static int nl_ack_handler_verbose(struct nl_msg *msg, void *arg)
250 {
251         return NL_EXIT;
252 }
253
254 static int nl_skipped_handler_verbose(struct nl_msg *msg, void *arg)
255 {
256         return NL_SKIP;
257 }
258
259 static int nl_error_handler_verbose(struct sockaddr_nl *who,
260                                     struct nlmsgerr *e, void *arg)
261 {
262         FILE *ofd = arg ? arg : stderr;
263
264         fprintf(ofd, "-- Error received: %s\n-- Original message: ",
265                 strerror(-e->error));
266         print_header_content(ofd, &e->msg);
267         fprintf(ofd, "\n");
268
269         return NL_EXIT;
270 }
271
272 static int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
273 {
274         FILE *ofd = arg ? arg : stderr;
275
276         fprintf(ofd, "-- Debug: Valid message: ");
277         print_header_content(ofd, nlmsg_hdr(msg));
278         fprintf(ofd, "\n");
279
280         return NL_PROCEED;
281 }
282
283 static int nl_finish_handler_debug(struct nl_msg *msg, void *arg)
284 {
285         FILE *ofd = arg ? arg : stderr;
286
287         fprintf(ofd, "-- Debug: End of multipart message block: ");
288         print_header_content(ofd, nlmsg_hdr(msg));
289         fprintf(ofd, "\n");
290         
291         return NL_EXIT;
292 }
293
294 static int nl_invalid_handler_debug(struct nl_msg *msg, void *arg)
295 {
296         return nl_invalid_handler_verbose(msg, arg);
297 }
298
299 static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg)
300 {
301         FILE *ofd = arg ? arg : stderr;
302
303         fprintf(ofd, "-- Debug: Received Message:\n");
304         raw_dump_msg(ofd, msg);
305         
306         return NL_PROCEED;
307 }
308
309 static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg)
310 {
311         FILE *ofd = arg ? arg : stderr;
312
313         fprintf(ofd, "-- Debug: Sent Message:\n");
314         raw_dump_msg(ofd, msg);
315
316         return NL_PROCEED;
317 }
318
319 static int nl_overrun_handler_debug(struct nl_msg *msg, void *arg)
320 {
321         return nl_overrun_handler_verbose(msg, arg);
322 }
323
324 static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg)
325 {
326         FILE *ofd = arg ? arg : stderr;
327
328         fprintf(ofd, "-- Debug: Skipped message: ");
329         print_header_content(ofd, nlmsg_hdr(msg));
330         fprintf(ofd, "\n");
331
332         return NL_SKIP;
333 }
334
335 static int nl_ack_handler_debug(struct nl_msg *msg, void *arg)
336 {
337         FILE *ofd = arg ? arg : stderr;
338
339         fprintf(ofd, "-- Debug: ACK: ");
340         print_header_content(ofd, nlmsg_hdr(msg));
341         fprintf(ofd, "\n");
342
343         return NL_EXIT;
344 }
345
346 static int nl_error_handler_debug(struct sockaddr_nl *who,
347                                   struct nlmsgerr *e, void *arg)
348 {
349         return nl_error_handler_verbose(who, e, arg);
350 }
351
352 static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = {
353         [NL_CB_VALID] = {
354                 [NL_CB_DEFAULT] = nl_valid_handler_default,
355                 [NL_CB_VERBOSE] = nl_valid_handler_verbose,
356                 [NL_CB_DEBUG]   = nl_valid_handler_debug,
357         },
358         [NL_CB_FINISH] = {
359                 [NL_CB_DEFAULT] = nl_finish_handler_default,
360                 [NL_CB_VERBOSE] = nl_finish_handler_verbose,
361                 [NL_CB_DEBUG]   = nl_finish_handler_debug,
362         },
363         [NL_CB_INVALID] = {
364                 [NL_CB_DEFAULT] = nl_invalid_handler_default,
365                 [NL_CB_VERBOSE] = nl_invalid_handler_verbose,
366                 [NL_CB_DEBUG]   = nl_invalid_handler_debug,
367         },
368         [NL_CB_MSG_IN] = {
369                 [NL_CB_DEFAULT] = nl_msg_in_handler_default,
370                 [NL_CB_VERBOSE] = nl_msg_in_handler_verbose,
371                 [NL_CB_DEBUG]   = nl_msg_in_handler_debug,
372         },
373         [NL_CB_MSG_OUT] = {
374                 [NL_CB_DEFAULT] = nl_msg_out_handler_default,
375                 [NL_CB_VERBOSE] = nl_msg_out_handler_verbose,
376                 [NL_CB_DEBUG]   = nl_msg_out_handler_debug,
377         },
378         [NL_CB_OVERRUN] = {
379                 [NL_CB_DEFAULT] = nl_overrun_handler_default,
380                 [NL_CB_VERBOSE] = nl_overrun_handler_verbose,
381                 [NL_CB_DEBUG]   = nl_overrun_handler_debug,
382         },
383         [NL_CB_SKIPPED] = {
384                 [NL_CB_DEFAULT] = nl_skipped_handler_default,
385                 [NL_CB_VERBOSE] = nl_skipped_handler_verbose,
386                 [NL_CB_DEBUG]   = nl_skipped_handler_debug,
387         },
388         [NL_CB_ACK] = {
389                 [NL_CB_DEFAULT] = nl_ack_handler_default,
390                 [NL_CB_VERBOSE] = nl_ack_handler_verbose,
391                 [NL_CB_DEBUG]   = nl_ack_handler_debug,
392         },
393 };
394
395 static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = {
396         [NL_CB_DEFAULT] = nl_error_handler_default,
397         [NL_CB_VERBOSE] = nl_error_handler_verbose,
398         [NL_CB_DEBUG]   = nl_error_handler_debug,
399 };
400
401 /**
402  * @name Callback Handle Management
403  * @{
404  */
405
406 /**
407  * Allocate a new callback handle
408  * @arg kind            callback kind to be used for initialization
409  * @return Newly allocated callback handle or NULL
410  */
411 struct nl_cb *nl_cb_new(enum nl_cb_kind kind)
412 {
413         int i;
414         struct nl_cb *cb;
415
416         if (kind < 0 || kind > NL_CB_KIND_MAX)
417                 return NULL;
418
419         cb = calloc(1, sizeof(*cb));
420         if (!cb) {
421                 nl_errno(ENOMEM);
422                 return NULL;
423         }
424
425         for (i = 0; i <= NL_CB_TYPE_MAX; i++)
426                 nl_cb_set(cb, i, kind, NULL, NULL);
427
428         nl_cb_err(cb, kind, NULL, NULL);
429
430         return cb;
431 }
432
433 /**
434  * Destroy a callback handle
435  * @arg cb              callback handle
436  */
437 void nl_cb_destroy(struct nl_cb *cb)
438 {
439         free(cb);
440 }
441
442 /**
443  * Clone an existing callback handle
444  * @arg orig            original callback handle
445  * @return Newly allocated callback handle being a duplicate of
446  *         orig or NULL
447  */
448 struct nl_cb *nl_cb_clone(struct nl_cb *orig)
449 {
450         struct nl_cb *cb;
451         
452         cb = nl_cb_new(NL_CB_DEFAULT);
453         if (!cb)
454                 return NULL;
455
456         memcpy(cb, orig, sizeof(*orig));
457
458         return cb;
459 }
460
461 /** @} */
462
463 /**
464  * @name Callback Setup
465  * @{
466  */
467
468 /**
469  * Set up a callback 
470  * @arg cb              callback configuration
471  * @arg type            which type callback to set
472  * @arg kind            kind of callback
473  * @arg func            callback function
474  * @arg arg             argument to be passwd to callback function
475  *
476  * @return 0 on success or a negative error code
477  */
478 int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
479               nl_recvmsg_msg_cb_t func, void *arg)
480 {
481         if (type < 0 || type > NL_CB_TYPE_MAX)
482                 return nl_error(ERANGE, "Callback type out of range");
483
484         if (kind < 0 || kind > NL_CB_KIND_MAX)
485                 return nl_error(ERANGE, "Callback kind out of range");
486
487         if (kind == NL_CB_CUSTOM) {
488                 cb->cb_set[type] = func;
489                 cb->cb_args[type] = arg;
490         } else {
491                 cb->cb_set[type] = cb_def[type][kind];
492                 cb->cb_args[type] = arg;
493         }
494
495         return 0;
496 }
497
498 /**
499  * Set up a all callbacks
500  * @arg cb              callback configuration
501  * @arg kind            kind of callback
502  * @arg func            callback function
503  * @arg arg             argument to be passwd to callback function
504  *
505  * @return 0 on success or a negative error code
506  */
507 int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
508                   nl_recvmsg_msg_cb_t func, void *arg)
509 {
510         int i, err;
511
512         for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
513                 err = nl_cb_set(cb, i, kind, func, arg);
514                 if (err < 0)
515                         return err;
516         }
517
518         return 0;
519 }
520
521 /**
522  * Set up an error callback
523  * @arg cb              callback configuration
524  * @arg kind            kind of callback
525  * @arg func            callback function
526  * @arg arg             argument to be passed to callback function
527  */
528 int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
529               nl_recvmsg_err_cb_t func, void *arg)
530 {
531         if (kind < 0 || kind > NL_CB_KIND_MAX)
532                 return nl_error(ERANGE, "Callback kind out of range");
533
534         if (kind == NL_CB_CUSTOM) {
535                 cb->cb_err = func;
536                 cb->cb_err_arg = arg;
537         } else {
538                 cb->cb_err = cb_err_def[kind];
539                 cb->cb_err_arg = arg;
540         }
541
542         return 0;
543 }
544
545 /**
546  * Overwrite internal calls to nl_recvmsgs()
547  * @arg cb              callback configuration
548  * @arg func            replacement callback for nl_recvmsgs()
549  */
550 void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
551                               int (*func)(struct nl_handle *, struct nl_cb *))
552 {
553         cb->cb_recvmsgs_ow = func;
554 }
555
556 /**
557  * Overwrite internal calls to nl_recv()
558  * @arg cb              callback configuration
559  * @arg func            replacement callback for nl_recv()
560  */
561 void nl_cb_overwrite_recv(struct nl_cb *cb,
562                           int (*func)(struct nl_handle *, struct sockaddr_nl *,
563                                       unsigned char **, struct ucred **))
564 {
565         cb->cb_recv_ow = func;
566 }
567
568 /**
569  * Overwrite internal calls to nl_send()
570  * @arg cb              callback configuration
571  * @arg func            replacement callback for nl_send()
572  */
573 void nl_cb_overwrite_send(struct nl_cb *cb,
574                           int (*func)(struct nl_handle *, struct nl_msg *))
575 {
576         cb->cb_send_ow = func;
577 }
578
579 /** @} */
580
581 /** @} */