handlers.c revision 44d362409d5469aed47d19e7908d19bd194493a4
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 89static 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 100static 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 111static 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 122static 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 133static 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 146static 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 157static 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 168static 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 178static 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 188static 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 199static 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 210static 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 240static 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 */ 255struct 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 */ 285struct nl_cb *nl_cb_clone(struct nl_cb *orig) 286{ 287 struct nl_cb *cb; 288 289 cb = nl_cb_alloc(NL_CB_DEFAULT); 290 if (!cb) 291 return NULL; 292 293 memcpy(cb, orig, sizeof(*orig)); 294 cb->cb_refcnt = 1; 295 296 return cb; 297} 298 299struct nl_cb *nl_cb_get(struct nl_cb *cb) 300{ 301 cb->cb_refcnt++; 302 303 return cb; 304} 305 306void 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 */ 337int 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 */ 366int 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 */ 387int 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 */ 416void 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 */ 427void 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 */ 439void 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/** @} */ 448