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 * Related sections in the development guide:
17 * - @core_doc{core_cb, Callback Configuration}
18 *
19 * @{
20 *
21 * Header
22 * ------
23 * ~~~~{.c}
24 * #include <netlink/handlers.h>
25 * ~~~~
26 */
27
28 #include <netlink-private/netlink.h>
29 #include <netlink/netlink.h>
30 #include <netlink/utils.h>
31 #include <netlink/msg.h>
32 #include <netlink/handlers.h>
33
print_header_content(FILE * ofd,struct nlmsghdr * n)34 static void print_header_content(FILE *ofd, struct nlmsghdr *n)
35 {
36 char flags[128];
37 char type[32];
38
39 fprintf(ofd, "type=%s length=%u flags=<%s> sequence-nr=%u pid=%u",
40 nl_nlmsgtype2str(n->nlmsg_type, type, sizeof(type)),
41 n->nlmsg_len, nl_nlmsg_flags2str(n->nlmsg_flags, flags,
42 sizeof(flags)), n->nlmsg_seq, n->nlmsg_pid);
43 }
44
nl_valid_handler_verbose(struct nl_msg * msg,void * arg)45 static int nl_valid_handler_verbose(struct nl_msg *msg, void *arg)
46 {
47 FILE *ofd = arg ? arg : stdout;
48
49 fprintf(ofd, "-- Warning: unhandled valid message: ");
50 print_header_content(ofd, nlmsg_hdr(msg));
51 fprintf(ofd, "\n");
52
53 return NL_OK;
54 }
55
nl_invalid_handler_verbose(struct nl_msg * msg,void * arg)56 static int nl_invalid_handler_verbose(struct nl_msg *msg, void *arg)
57 {
58 FILE *ofd = arg ? arg : stderr;
59
60 fprintf(ofd, "-- Error: Invalid message: ");
61 print_header_content(ofd, nlmsg_hdr(msg));
62 fprintf(ofd, "\n");
63
64 return NL_STOP;
65 }
66
nl_overrun_handler_verbose(struct nl_msg * msg,void * arg)67 static int nl_overrun_handler_verbose(struct nl_msg *msg, void *arg)
68 {
69 FILE *ofd = arg ? arg : stderr;
70
71 fprintf(ofd, "-- Error: Netlink Overrun: ");
72 print_header_content(ofd, nlmsg_hdr(msg));
73 fprintf(ofd, "\n");
74
75 return NL_STOP;
76 }
77
nl_error_handler_verbose(struct sockaddr_nl * who,struct nlmsgerr * e,void * arg)78 static int nl_error_handler_verbose(struct sockaddr_nl *who,
79 struct nlmsgerr *e, void *arg)
80 {
81 FILE *ofd = arg ? arg : stderr;
82 char buf[256];
83
84 fprintf(ofd, "-- Error received: %s\n-- Original message: ",
85 strerror_r(-e->error, buf, sizeof(buf)));
86 print_header_content(ofd, &e->msg);
87 fprintf(ofd, "\n");
88
89 return -nl_syserr2nlerr(e->error);
90 }
91
nl_valid_handler_debug(struct nl_msg * msg,void * arg)92 static int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
93 {
94 FILE *ofd = arg ? arg : stderr;
95
96 fprintf(ofd, "-- Debug: Unhandled Valid message: ");
97 print_header_content(ofd, nlmsg_hdr(msg));
98 fprintf(ofd, "\n");
99
100 return NL_OK;
101 }
102
nl_finish_handler_debug(struct nl_msg * msg,void * arg)103 static int nl_finish_handler_debug(struct nl_msg *msg, void *arg)
104 {
105 FILE *ofd = arg ? arg : stderr;
106
107 fprintf(ofd, "-- Debug: End of multipart message block: ");
108 print_header_content(ofd, nlmsg_hdr(msg));
109 fprintf(ofd, "\n");
110
111 return NL_STOP;
112 }
113
nl_msg_in_handler_debug(struct nl_msg * msg,void * arg)114 static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg)
115 {
116 FILE *ofd = arg ? arg : stderr;
117
118 fprintf(ofd, "-- Debug: Received Message:\n");
119 nl_msg_dump(msg, ofd);
120
121 return NL_OK;
122 }
123
nl_msg_out_handler_debug(struct nl_msg * msg,void * arg)124 static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg)
125 {
126 FILE *ofd = arg ? arg : stderr;
127
128 fprintf(ofd, "-- Debug: Sent Message:\n");
129 nl_msg_dump(msg, ofd);
130
131 return NL_OK;
132 }
133
nl_skipped_handler_debug(struct nl_msg * msg,void * arg)134 static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg)
135 {
136 FILE *ofd = arg ? arg : stderr;
137
138 fprintf(ofd, "-- Debug: Skipped message: ");
139 print_header_content(ofd, nlmsg_hdr(msg));
140 fprintf(ofd, "\n");
141
142 return NL_SKIP;
143 }
144
nl_ack_handler_debug(struct nl_msg * msg,void * arg)145 static int nl_ack_handler_debug(struct nl_msg *msg, void *arg)
146 {
147 FILE *ofd = arg ? arg : stderr;
148
149 fprintf(ofd, "-- Debug: ACK: ");
150 print_header_content(ofd, nlmsg_hdr(msg));
151 fprintf(ofd, "\n");
152
153 return NL_STOP;
154 }
155
156 static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = {
157 [NL_CB_VALID] = {
158 [NL_CB_VERBOSE] = nl_valid_handler_verbose,
159 [NL_CB_DEBUG] = nl_valid_handler_debug,
160 },
161 [NL_CB_FINISH] = {
162 [NL_CB_DEBUG] = nl_finish_handler_debug,
163 },
164 [NL_CB_INVALID] = {
165 [NL_CB_VERBOSE] = nl_invalid_handler_verbose,
166 [NL_CB_DEBUG] = nl_invalid_handler_verbose,
167 },
168 [NL_CB_MSG_IN] = {
169 [NL_CB_DEBUG] = nl_msg_in_handler_debug,
170 },
171 [NL_CB_MSG_OUT] = {
172 [NL_CB_DEBUG] = nl_msg_out_handler_debug,
173 },
174 [NL_CB_OVERRUN] = {
175 [NL_CB_VERBOSE] = nl_overrun_handler_verbose,
176 [NL_CB_DEBUG] = nl_overrun_handler_verbose,
177 },
178 [NL_CB_SKIPPED] = {
179 [NL_CB_DEBUG] = nl_skipped_handler_debug,
180 },
181 [NL_CB_ACK] = {
182 [NL_CB_DEBUG] = nl_ack_handler_debug,
183 },
184 };
185
186 static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = {
187 [NL_CB_VERBOSE] = nl_error_handler_verbose,
188 [NL_CB_DEBUG] = nl_error_handler_verbose,
189 };
190
191 /**
192 * @name Callback Handle Management
193 * @{
194 */
195
196 /**
197 * Allocate a new callback handle
198 * @arg kind callback kind to be used for initialization
199 * @return Newly allocated callback handle or NULL
200 */
nl_cb_alloc(enum nl_cb_kind kind)201 struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
202 {
203 int i;
204 struct nl_cb *cb;
205
206 if (kind < 0 || kind > NL_CB_KIND_MAX)
207 return NULL;
208
209 cb = calloc(1, sizeof(*cb));
210 if (!cb)
211 return NULL;
212
213 cb->cb_refcnt = 1;
214 cb->cb_active = NL_CB_TYPE_MAX + 1;
215
216 for (i = 0; i <= NL_CB_TYPE_MAX; i++)
217 nl_cb_set(cb, i, kind, NULL, NULL);
218
219 nl_cb_err(cb, kind, NULL, NULL);
220
221 return cb;
222 }
223
224 /**
225 * Clone an existing callback handle
226 * @arg orig original callback handle
227 * @return Newly allocated callback handle being a duplicate of
228 * orig or NULL
229 */
nl_cb_clone(struct nl_cb * orig)230 struct nl_cb *nl_cb_clone(struct nl_cb *orig)
231 {
232 struct nl_cb *cb;
233
234 cb = nl_cb_alloc(NL_CB_DEFAULT);
235 if (!cb)
236 return NULL;
237
238 memcpy(cb, orig, sizeof(*orig));
239 cb->cb_refcnt = 1;
240
241 return cb;
242 }
243
nl_cb_get(struct nl_cb * cb)244 struct nl_cb *nl_cb_get(struct nl_cb *cb)
245 {
246 cb->cb_refcnt++;
247
248 return cb;
249 }
250
nl_cb_put(struct nl_cb * cb)251 void nl_cb_put(struct nl_cb *cb)
252 {
253 if (!cb)
254 return;
255
256 cb->cb_refcnt--;
257
258 if (cb->cb_refcnt < 0)
259 BUG();
260
261 if (cb->cb_refcnt <= 0)
262 free(cb);
263 }
264
265 /**
266 * Obtain type of current active callback
267 * @arg cb callback to query
268 *
269 * @return type or __NL_CB_TYPE_MAX if none active
270 */
nl_cb_active_type(struct nl_cb * cb)271 enum nl_cb_type nl_cb_active_type(struct nl_cb *cb)
272 {
273 return cb->cb_active;
274 }
275
276 /** @} */
277
278 /**
279 * @name Callback Setup
280 * @{
281 */
282
283 /**
284 * Set up a callback
285 * @arg cb callback set
286 * @arg type callback to modify
287 * @arg kind kind of implementation
288 * @arg func callback function (NL_CB_CUSTOM)
289 * @arg arg argument passed to callback
290 *
291 * @return 0 on success or a negative error code
292 */
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)293 int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
294 nl_recvmsg_msg_cb_t func, void *arg)
295 {
296 if (type < 0 || type > NL_CB_TYPE_MAX)
297 return -NLE_RANGE;
298
299 if (kind < 0 || kind > NL_CB_KIND_MAX)
300 return -NLE_RANGE;
301
302 if (kind == NL_CB_CUSTOM) {
303 cb->cb_set[type] = func;
304 cb->cb_args[type] = arg;
305 } else {
306 cb->cb_set[type] = cb_def[type][kind];
307 cb->cb_args[type] = arg;
308 }
309
310 return 0;
311 }
312
313 /**
314 * Set up a all callbacks
315 * @arg cb callback set
316 * @arg kind kind of callback
317 * @arg func callback function
318 * @arg arg argument to be passwd to callback function
319 *
320 * @return 0 on success or a negative error code
321 */
nl_cb_set_all(struct nl_cb * cb,enum nl_cb_kind kind,nl_recvmsg_msg_cb_t func,void * arg)322 int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
323 nl_recvmsg_msg_cb_t func, void *arg)
324 {
325 int i, err;
326
327 for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
328 err = nl_cb_set(cb, i, kind, func, arg);
329 if (err < 0)
330 return err;
331 }
332
333 return 0;
334 }
335
336 /**
337 * Set up an error callback
338 * @arg cb callback set
339 * @arg kind kind of callback
340 * @arg func callback function
341 * @arg arg argument to be passed to callback function
342 */
nl_cb_err(struct nl_cb * cb,enum nl_cb_kind kind,nl_recvmsg_err_cb_t func,void * arg)343 int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
344 nl_recvmsg_err_cb_t func, void *arg)
345 {
346 if (kind < 0 || kind > NL_CB_KIND_MAX)
347 return -NLE_RANGE;
348
349 if (kind == NL_CB_CUSTOM) {
350 cb->cb_err = func;
351 cb->cb_err_arg = arg;
352 } else {
353 cb->cb_err = cb_err_def[kind];
354 cb->cb_err_arg = arg;
355 }
356
357 return 0;
358 }
359
360 /** @} */
361
362 /**
363 * @name Overwriting
364 * @{
365 */
366
367 /**
368 * Overwrite internal calls to nl_recvmsgs()
369 * @arg cb callback set
370 * @arg func replacement callback for nl_recvmsgs()
371 */
nl_cb_overwrite_recvmsgs(struct nl_cb * cb,int (* func)(struct nl_sock *,struct nl_cb *))372 void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
373 int (*func)(struct nl_sock *, struct nl_cb *))
374 {
375 cb->cb_recvmsgs_ow = func;
376 }
377
378 /**
379 * Overwrite internal calls to nl_recv()
380 * @arg cb callback set
381 * @arg func replacement callback for nl_recv()
382 */
nl_cb_overwrite_recv(struct nl_cb * cb,int (* func)(struct nl_sock *,struct sockaddr_nl *,unsigned char **,struct ucred **))383 void nl_cb_overwrite_recv(struct nl_cb *cb,
384 int (*func)(struct nl_sock *, struct sockaddr_nl *,
385 unsigned char **, struct ucred **))
386 {
387 cb->cb_recv_ow = func;
388 }
389
390 /**
391 * Overwrite internal calls to nl_send()
392 * @arg cb callback set
393 * @arg func replacement callback for nl_send()
394 */
nl_cb_overwrite_send(struct nl_cb * cb,int (* func)(struct nl_sock *,struct nl_msg *))395 void nl_cb_overwrite_send(struct nl_cb *cb,
396 int (*func)(struct nl_sock *, struct nl_msg *))
397 {
398 cb->cb_send_ow = func;
399 }
400
401 /** @} */
402
403 /** @} */
404