libnl  3.2.7
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-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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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  */
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  */
233 struct nl_cb *nl_cb_clone(struct nl_cb *orig)
234 {
235  struct nl_cb *cb;
236 
238  if (!cb)
239  return NULL;
240 
241  memcpy(cb, orig, sizeof(*orig));
242  cb->cb_refcnt = 1;
243 
244  return cb;
245 }
246 
247 struct nl_cb *nl_cb_get(struct nl_cb *cb)
248 {
249  cb->cb_refcnt++;
250 
251  return cb;
252 }
253 
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  */
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  */
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  */
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  */
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  */
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  */
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 /** @} */