libnl  1.1
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 
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 /** @} */