libnl  1.1.4
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  char buf[256];
138 
139  fprintf(ofd, "-- Error received: %s\n-- Original message: ",
140  strerror_r(-e->error, buf, sizeof(buf)));
141  print_header_content(ofd, &e->msg);
142  fprintf(ofd, "\n");
143 
144  return e->error;
145 }
146 
147 static int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
148 {
149  FILE *ofd = arg ? arg : stderr;
150 
151  fprintf(ofd, "-- Debug: Unhandled Valid message: ");
152  print_header_content(ofd, nlmsg_hdr(msg));
153  fprintf(ofd, "\n");
154 
155  return NL_OK;
156 }
157 
158 static int nl_finish_handler_debug(struct nl_msg *msg, void *arg)
159 {
160  FILE *ofd = arg ? arg : stderr;
161 
162  fprintf(ofd, "-- Debug: End of multipart message block: ");
163  print_header_content(ofd, nlmsg_hdr(msg));
164  fprintf(ofd, "\n");
165 
166  return NL_STOP;
167 }
168 
169 static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg)
170 {
171  FILE *ofd = arg ? arg : stderr;
172 
173  fprintf(ofd, "-- Debug: Received Message:\n");
174  nl_msg_dump(msg, ofd);
175 
176  return NL_OK;
177 }
178 
179 static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg)
180 {
181  FILE *ofd = arg ? arg : stderr;
182 
183  fprintf(ofd, "-- Debug: Sent Message:\n");
184  nl_msg_dump(msg, ofd);
185 
186  return NL_OK;
187 }
188 
189 static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg)
190 {
191  FILE *ofd = arg ? arg : stderr;
192 
193  fprintf(ofd, "-- Debug: Skipped message: ");
194  print_header_content(ofd, nlmsg_hdr(msg));
195  fprintf(ofd, "\n");
196 
197  return NL_SKIP;
198 }
199 
200 static int nl_ack_handler_debug(struct nl_msg *msg, void *arg)
201 {
202  FILE *ofd = arg ? arg : stderr;
203 
204  fprintf(ofd, "-- Debug: ACK: ");
205  print_header_content(ofd, nlmsg_hdr(msg));
206  fprintf(ofd, "\n");
207 
208  return NL_STOP;
209 }
210 
211 static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = {
212  [NL_CB_VALID] = {
213  [NL_CB_VERBOSE] = nl_valid_handler_verbose,
214  [NL_CB_DEBUG] = nl_valid_handler_debug,
215  },
216  [NL_CB_FINISH] = {
217  [NL_CB_DEBUG] = nl_finish_handler_debug,
218  },
219  [NL_CB_INVALID] = {
220  [NL_CB_VERBOSE] = nl_invalid_handler_verbose,
221  [NL_CB_DEBUG] = nl_invalid_handler_verbose,
222  },
223  [NL_CB_MSG_IN] = {
224  [NL_CB_DEBUG] = nl_msg_in_handler_debug,
225  },
226  [NL_CB_MSG_OUT] = {
227  [NL_CB_DEBUG] = nl_msg_out_handler_debug,
228  },
229  [NL_CB_OVERRUN] = {
230  [NL_CB_VERBOSE] = nl_overrun_handler_verbose,
231  [NL_CB_DEBUG] = nl_overrun_handler_verbose,
232  },
233  [NL_CB_SKIPPED] = {
234  [NL_CB_DEBUG] = nl_skipped_handler_debug,
235  },
236  [NL_CB_ACK] = {
237  [NL_CB_DEBUG] = nl_ack_handler_debug,
238  },
239 };
240 
241 static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = {
242  [NL_CB_VERBOSE] = nl_error_handler_verbose,
243  [NL_CB_DEBUG] = nl_error_handler_verbose,
244 };
245 
246 /**
247  * @name Callback Handle Management
248  * @{
249  */
250 
251 /**
252  * Allocate a new callback handle
253  * @arg kind callback kind to be used for initialization
254  * @return Newly allocated callback handle or NULL
255  */
256 struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
257 {
258  int i;
259  struct nl_cb *cb;
260 
261  if (kind < 0 || kind > NL_CB_KIND_MAX)
262  return NULL;
263 
264  cb = calloc(1, sizeof(*cb));
265  if (!cb) {
266  nl_errno(ENOMEM);
267  return NULL;
268  }
269 
270  cb->cb_refcnt = 1;
271 
272  for (i = 0; i <= NL_CB_TYPE_MAX; i++)
273  nl_cb_set(cb, i, kind, NULL, NULL);
274 
275  nl_cb_err(cb, kind, NULL, NULL);
276 
277  return cb;
278 }
279 
280 /**
281  * Clone an existing callback handle
282  * @arg orig original callback handle
283  * @return Newly allocated callback handle being a duplicate of
284  * orig or NULL
285  */
286 struct nl_cb *nl_cb_clone(struct nl_cb *orig)
287 {
288  struct nl_cb *cb;
289 
291  if (!cb)
292  return NULL;
293 
294  memcpy(cb, orig, sizeof(*orig));
295  cb->cb_refcnt = 1;
296 
297  return cb;
298 }
299 
300 struct nl_cb *nl_cb_get(struct nl_cb *cb)
301 {
302  cb->cb_refcnt++;
303 
304  return cb;
305 }
306 
307 void nl_cb_put(struct nl_cb *cb)
308 {
309  if (!cb)
310  return;
311 
312  cb->cb_refcnt--;
313 
314  if (cb->cb_refcnt < 0)
315  BUG();
316 
317  if (cb->cb_refcnt <= 0)
318  free(cb);
319 }
320 
321 /** @} */
322 
323 /**
324  * @name Callback Setup
325  * @{
326  */
327 
328 /**
329  * Set up a callback
330  * @arg cb callback set
331  * @arg type callback to modify
332  * @arg kind kind of implementation
333  * @arg func callback function (NL_CB_CUSTOM)
334  * @arg arg argument passed to callback
335  *
336  * @return 0 on success or a negative error code
337  */
338 int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
339  nl_recvmsg_msg_cb_t func, void *arg)
340 {
341  if (type < 0 || type > NL_CB_TYPE_MAX)
342  return nl_error(ERANGE, "Callback type out of range");
343 
344  if (kind < 0 || kind > NL_CB_KIND_MAX)
345  return nl_error(ERANGE, "Callback kind out of range");
346 
347  if (kind == NL_CB_CUSTOM) {
348  cb->cb_set[type] = func;
349  cb->cb_args[type] = arg;
350  } else {
351  cb->cb_set[type] = cb_def[type][kind];
352  cb->cb_args[type] = arg;
353  }
354 
355  return 0;
356 }
357 
358 /**
359  * Set up a all callbacks
360  * @arg cb callback set
361  * @arg kind kind of callback
362  * @arg func callback function
363  * @arg arg argument to be passwd to callback function
364  *
365  * @return 0 on success or a negative error code
366  */
367 int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
368  nl_recvmsg_msg_cb_t func, void *arg)
369 {
370  int i, err;
371 
372  for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
373  err = nl_cb_set(cb, i, kind, func, arg);
374  if (err < 0)
375  return err;
376  }
377 
378  return 0;
379 }
380 
381 /**
382  * Set up an error callback
383  * @arg cb callback set
384  * @arg kind kind of callback
385  * @arg func callback function
386  * @arg arg argument to be passed to callback function
387  */
388 int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
389  nl_recvmsg_err_cb_t func, void *arg)
390 {
391  if (kind < 0 || kind > NL_CB_KIND_MAX)
392  return nl_error(ERANGE, "Callback kind out of range");
393 
394  if (kind == NL_CB_CUSTOM) {
395  cb->cb_err = func;
396  cb->cb_err_arg = arg;
397  } else {
398  cb->cb_err = cb_err_def[kind];
399  cb->cb_err_arg = arg;
400  }
401 
402  return 0;
403 }
404 
405 /** @} */
406 
407 /**
408  * @name Overwriting
409  * @{
410  */
411 
412 /**
413  * Overwrite internal calls to nl_recvmsgs()
414  * @arg cb callback set
415  * @arg func replacement callback for nl_recvmsgs()
416  */
417 void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
418  int (*func)(struct nl_handle *, struct nl_cb *))
419 {
420  cb->cb_recvmsgs_ow = func;
421 }
422 
423 /**
424  * Overwrite internal calls to nl_recv()
425  * @arg cb callback set
426  * @arg func replacement callback for nl_recv()
427  */
428 void nl_cb_overwrite_recv(struct nl_cb *cb,
429  int (*func)(struct nl_handle *, struct sockaddr_nl *,
430  unsigned char **, struct ucred **))
431 {
432  cb->cb_recv_ow = func;
433 }
434 
435 /**
436  * Overwrite internal calls to nl_send()
437  * @arg cb callback set
438  * @arg func replacement callback for nl_send()
439  */
440 void nl_cb_overwrite_send(struct nl_cb *cb,
441  int (*func)(struct nl_handle *, struct nl_msg *))
442 {
443  cb->cb_send_ow = func;
444 }
445 
446 /** @} */
447 
448 /** @} */
Report received that data was lost.
Definition: handlers.h:100
Called for every message sent out except for nl_sendto()
Definition: handlers.h:108
Message is an acknowledge.
Definition: handlers.h:104
int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func, void *arg)
Set up a all callbacks.
Definition: handlers.c:367
int(* nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg)
nl_recvmsgs() callback for error message processing customization
Definition: handlers.h:50
uint16_t nlmsg_type
Message type (content type)
Customized handler specified by the user.
Definition: handlers.h:84
uint32_t nlmsg_seq
Sequence number.
Message wants to be skipped.
Definition: handlers.h:102
int error
Error code (errno number)
Stop parsing altogether and discard remaining messages.
Definition: handlers.h:65
Netlink message header.
void nl_cb_overwrite_recv(struct nl_cb *cb, int(*func)(struct nl_handle *, struct sockaddr_nl *, unsigned char **, struct ucred **))
Overwrite internal calls to nl_recv()
Definition: handlers.c:428
Called for every message received.
Definition: handlers.h:106
uint32_t nlmsg_len
Length of message including header.
Netlink error message.
nl_cb_kind
Callback kinds.
Definition: handlers.h:76
struct nl_cb * nl_cb_clone(struct nl_cb *orig)
Clone an existing callback handle.
Definition: handlers.c:286
int 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)
Set up a callback.
Definition: handlers.c:338
int(* nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg)
nl_recvmsgs() callback for message processing customization
Definition: handlers.h:41
void nl_cb_overwrite_send(struct nl_cb *cb, int(*func)(struct nl_handle *, struct nl_msg *))
Overwrite internal calls to nl_send()
Definition: handlers.c:440
uint32_t nlmsg_pid
Netlink PID of the proccess sending the message.
Message is malformed and invalid.
Definition: handlers.h:110
void nl_msg_dump(struct nl_msg *msg, FILE *ofd)
Dump message in human readable format to file descriptor.
Definition: msg.c:947
Skip this message.
Definition: handlers.h:63
Last message in a series of multi part messages received.
Definition: handlers.h:98
struct nlmsghdr * nlmsg_hdr(struct nl_msg *n)
Return actual netlink message.
Definition: msg.c:643
Debug handlers for debugging.
Definition: handlers.h:82
Netlink socket address.
Definition: netlink-kernel.h:8
Message is valid.
Definition: handlers.h:96
uint16_t nlmsg_flags
Message flags.
struct nlmsghdr msg
Original netlink message causing the error.
Proceed with wathever would come next.
Definition: handlers.h:61
nl_cb_type
Callback types.
Definition: handlers.h:94
struct nl_cb * nl_cb_alloc(enum nl_cb_kind kind)
Allocate a new callback handle.
Definition: handlers.c:256
Default handlers (quiet)
Definition: handlers.h:78
void nl_cb_overwrite_recvmsgs(struct nl_cb *cb, int(*func)(struct nl_handle *, struct nl_cb *))
Overwrite internal calls to nl_recvmsgs()
Definition: handlers.c:417
int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, nl_recvmsg_err_cb_t func, void *arg)
Set up an error callback.
Definition: handlers.c:388
Verbose default handlers (error messages printed)
Definition: handlers.h:80