libnl 1.1
|
00001 /* 00002 * lib/handlers.c default netlink message handlers 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup nl 00014 * @defgroup cb Callbacks/Customization 00015 * @brief 00016 * 00017 * Callbacks and overwriting capabilities are provided to take influence 00018 * in various control flows inside the library. All callbacks are packed 00019 * together in struct nl_cb which is then attached to a netlink socket or 00020 * passed on to the respective functions directly. 00021 * 00022 * Callbacks can control the flow of the underlying layer by returning 00023 * the appropriate error codes: 00024 * @code 00025 * Action ID | Description 00026 * -----------------+------------------------------------------------------- 00027 * NL_OK | Proceed with whatever comes next. 00028 * NL_SKIP | Skip message currently being processed and continue 00029 * | with next message. 00030 * NL_STOP | Stop parsing and discard all remaining messages in 00031 * | this set of messages. 00032 * @endcode 00033 * 00034 * All callbacks are optional and a default action is performed if no 00035 * application specific implementation is provided: 00036 * 00037 * @code 00038 * Callback ID | Default Return Value 00039 * ------------------+---------------------- 00040 * NL_CB_VALID | NL_OK 00041 * NL_CB_FINISH | NL_STOP 00042 * NL_CB_OVERRUN | NL_STOP 00043 * NL_CB_SKIPPED | NL_SKIP 00044 * NL_CB_ACK | NL_STOP 00045 * NL_CB_MSG_IN | NL_OK 00046 * NL_CB_MSG_OUT | NL_OK 00047 * NL_CB_INVALID | NL_STOP 00048 * NL_CB_SEQ_CHECK | NL_OK 00049 * NL_CB_SEND_ACK | NL_OK 00050 * | 00051 * Error Callback | NL_STOP 00052 * @endcode 00053 * 00054 * In order to simplify typical usages of the library, different sets of 00055 * default callback implementations exist: 00056 * @code 00057 * NL_CB_DEFAULT: No additional actions 00058 * NL_CB_VERBOSE: Automatically print warning and error messages to a file 00059 * descriptor as appropriate. This is useful for CLI based 00060 * applications. 00061 * NL_CB_DEBUG: Print informal debugging information for each message 00062 * received. This will result in every message beint sent or 00063 * received to be printed to the screen in a decoded, 00064 * human-readable format. 00065 * @endcode 00066 * 00067 * @par 1) Setting up a callback set 00068 * @code 00069 * // Allocate a callback set and initialize it to the verbose default set 00070 * struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE); 00071 * 00072 * // Modify the set to call my_func() for all valid messages 00073 * nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL); 00074 * 00075 * // Set the error message handler to the verbose default implementation 00076 * // and direct it to print all errors to the given file descriptor. 00077 * FILE *file = fopen(...); 00078 * nl_cb_err(cb, NL_CB_VERBOSE, NULL, file); 00079 * @endcode 00080 * @{ 00081 */ 00082 00083 #include <netlink-local.h> 00084 #include <netlink/netlink.h> 00085 #include <netlink/utils.h> 00086 #include <netlink/msg.h> 00087 #include <netlink/handlers.h> 00088 00089 static void print_header_content(FILE *ofd, struct nlmsghdr *n) 00090 { 00091 char flags[128]; 00092 char type[32]; 00093 00094 fprintf(ofd, "type=%s length=%u flags=<%s> sequence-nr=%u pid=%u", 00095 nl_nlmsgtype2str(n->nlmsg_type, type, sizeof(type)), 00096 n->nlmsg_len, nl_nlmsg_flags2str(n->nlmsg_flags, flags, 00097 sizeof(flags)), n->nlmsg_seq, n->nlmsg_pid); 00098 } 00099 00100 static int nl_valid_handler_verbose(struct nl_msg *msg, void *arg) 00101 { 00102 FILE *ofd = arg ? arg : stdout; 00103 00104 fprintf(ofd, "-- Warning: unhandled valid message: "); 00105 print_header_content(ofd, nlmsg_hdr(msg)); 00106 fprintf(ofd, "\n"); 00107 00108 return NL_OK; 00109 } 00110 00111 static int nl_invalid_handler_verbose(struct nl_msg *msg, void *arg) 00112 { 00113 FILE *ofd = arg ? arg : stderr; 00114 00115 fprintf(ofd, "-- Error: Invalid message: "); 00116 print_header_content(ofd, nlmsg_hdr(msg)); 00117 fprintf(ofd, "\n"); 00118 00119 return NL_STOP; 00120 } 00121 00122 static int nl_overrun_handler_verbose(struct nl_msg *msg, void *arg) 00123 { 00124 FILE *ofd = arg ? arg : stderr; 00125 00126 fprintf(ofd, "-- Error: Netlink Overrun: "); 00127 print_header_content(ofd, nlmsg_hdr(msg)); 00128 fprintf(ofd, "\n"); 00129 00130 return NL_STOP; 00131 } 00132 00133 static int nl_error_handler_verbose(struct sockaddr_nl *who, 00134 struct nlmsgerr *e, void *arg) 00135 { 00136 FILE *ofd = arg ? arg : stderr; 00137 00138 fprintf(ofd, "-- Error received: %s\n-- Original message: ", 00139 strerror(-e->error)); 00140 print_header_content(ofd, &e->msg); 00141 fprintf(ofd, "\n"); 00142 00143 return e->error; 00144 } 00145 00146 static int nl_valid_handler_debug(struct nl_msg *msg, void *arg) 00147 { 00148 FILE *ofd = arg ? arg : stderr; 00149 00150 fprintf(ofd, "-- Debug: Unhandled Valid message: "); 00151 print_header_content(ofd, nlmsg_hdr(msg)); 00152 fprintf(ofd, "\n"); 00153 00154 return NL_OK; 00155 } 00156 00157 static int nl_finish_handler_debug(struct nl_msg *msg, void *arg) 00158 { 00159 FILE *ofd = arg ? arg : stderr; 00160 00161 fprintf(ofd, "-- Debug: End of multipart message block: "); 00162 print_header_content(ofd, nlmsg_hdr(msg)); 00163 fprintf(ofd, "\n"); 00164 00165 return NL_STOP; 00166 } 00167 00168 static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg) 00169 { 00170 FILE *ofd = arg ? arg : stderr; 00171 00172 fprintf(ofd, "-- Debug: Received Message:\n"); 00173 nl_msg_dump(msg, ofd); 00174 00175 return NL_OK; 00176 } 00177 00178 static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg) 00179 { 00180 FILE *ofd = arg ? arg : stderr; 00181 00182 fprintf(ofd, "-- Debug: Sent Message:\n"); 00183 nl_msg_dump(msg, ofd); 00184 00185 return NL_OK; 00186 } 00187 00188 static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg) 00189 { 00190 FILE *ofd = arg ? arg : stderr; 00191 00192 fprintf(ofd, "-- Debug: Skipped message: "); 00193 print_header_content(ofd, nlmsg_hdr(msg)); 00194 fprintf(ofd, "\n"); 00195 00196 return NL_SKIP; 00197 } 00198 00199 static int nl_ack_handler_debug(struct nl_msg *msg, void *arg) 00200 { 00201 FILE *ofd = arg ? arg : stderr; 00202 00203 fprintf(ofd, "-- Debug: ACK: "); 00204 print_header_content(ofd, nlmsg_hdr(msg)); 00205 fprintf(ofd, "\n"); 00206 00207 return NL_STOP; 00208 } 00209 00210 static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = { 00211 [NL_CB_VALID] = { 00212 [NL_CB_VERBOSE] = nl_valid_handler_verbose, 00213 [NL_CB_DEBUG] = nl_valid_handler_debug, 00214 }, 00215 [NL_CB_FINISH] = { 00216 [NL_CB_DEBUG] = nl_finish_handler_debug, 00217 }, 00218 [NL_CB_INVALID] = { 00219 [NL_CB_VERBOSE] = nl_invalid_handler_verbose, 00220 [NL_CB_DEBUG] = nl_invalid_handler_verbose, 00221 }, 00222 [NL_CB_MSG_IN] = { 00223 [NL_CB_DEBUG] = nl_msg_in_handler_debug, 00224 }, 00225 [NL_CB_MSG_OUT] = { 00226 [NL_CB_DEBUG] = nl_msg_out_handler_debug, 00227 }, 00228 [NL_CB_OVERRUN] = { 00229 [NL_CB_VERBOSE] = nl_overrun_handler_verbose, 00230 [NL_CB_DEBUG] = nl_overrun_handler_verbose, 00231 }, 00232 [NL_CB_SKIPPED] = { 00233 [NL_CB_DEBUG] = nl_skipped_handler_debug, 00234 }, 00235 [NL_CB_ACK] = { 00236 [NL_CB_DEBUG] = nl_ack_handler_debug, 00237 }, 00238 }; 00239 00240 static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = { 00241 [NL_CB_VERBOSE] = nl_error_handler_verbose, 00242 [NL_CB_DEBUG] = nl_error_handler_verbose, 00243 }; 00244 00245 /** 00246 * @name Callback Handle Management 00247 * @{ 00248 */ 00249 00250 /** 00251 * Allocate a new callback handle 00252 * @arg kind callback kind to be used for initialization 00253 * @return Newly allocated callback handle or NULL 00254 */ 00255 struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind) 00256 { 00257 int i; 00258 struct nl_cb *cb; 00259 00260 if (kind < 0 || kind > NL_CB_KIND_MAX) 00261 return NULL; 00262 00263 cb = calloc(1, sizeof(*cb)); 00264 if (!cb) { 00265 nl_errno(ENOMEM); 00266 return NULL; 00267 } 00268 00269 cb->cb_refcnt = 1; 00270 00271 for (i = 0; i <= NL_CB_TYPE_MAX; i++) 00272 nl_cb_set(cb, i, kind, NULL, NULL); 00273 00274 nl_cb_err(cb, kind, NULL, NULL); 00275 00276 return cb; 00277 } 00278 00279 /** 00280 * Clone an existing callback handle 00281 * @arg orig original callback handle 00282 * @return Newly allocated callback handle being a duplicate of 00283 * orig or NULL 00284 */ 00285 struct nl_cb *nl_cb_clone(struct nl_cb *orig) 00286 { 00287 struct nl_cb *cb; 00288 00289 cb = nl_cb_alloc(NL_CB_DEFAULT); 00290 if (!cb) 00291 return NULL; 00292 00293 memcpy(cb, orig, sizeof(*orig)); 00294 cb->cb_refcnt = 1; 00295 00296 return cb; 00297 } 00298 00299 struct nl_cb *nl_cb_get(struct nl_cb *cb) 00300 { 00301 cb->cb_refcnt++; 00302 00303 return cb; 00304 } 00305 00306 void nl_cb_put(struct nl_cb *cb) 00307 { 00308 if (!cb) 00309 return; 00310 00311 cb->cb_refcnt--; 00312 00313 if (cb->cb_refcnt < 0) 00314 BUG(); 00315 00316 if (cb->cb_refcnt <= 0) 00317 free(cb); 00318 } 00319 00320 /** @} */ 00321 00322 /** 00323 * @name Callback Setup 00324 * @{ 00325 */ 00326 00327 /** 00328 * Set up a callback 00329 * @arg cb callback set 00330 * @arg type callback to modify 00331 * @arg kind kind of implementation 00332 * @arg func callback function (NL_CB_CUSTOM) 00333 * @arg arg argument passed to callback 00334 * 00335 * @return 0 on success or a negative error code 00336 */ 00337 int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind, 00338 nl_recvmsg_msg_cb_t func, void *arg) 00339 { 00340 if (type < 0 || type > NL_CB_TYPE_MAX) 00341 return nl_error(ERANGE, "Callback type out of range"); 00342 00343 if (kind < 0 || kind > NL_CB_KIND_MAX) 00344 return nl_error(ERANGE, "Callback kind out of range"); 00345 00346 if (kind == NL_CB_CUSTOM) { 00347 cb->cb_set[type] = func; 00348 cb->cb_args[type] = arg; 00349 } else { 00350 cb->cb_set[type] = cb_def[type][kind]; 00351 cb->cb_args[type] = arg; 00352 } 00353 00354 return 0; 00355 } 00356 00357 /** 00358 * Set up a all callbacks 00359 * @arg cb callback set 00360 * @arg kind kind of callback 00361 * @arg func callback function 00362 * @arg arg argument to be passwd to callback function 00363 * 00364 * @return 0 on success or a negative error code 00365 */ 00366 int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind, 00367 nl_recvmsg_msg_cb_t func, void *arg) 00368 { 00369 int i, err; 00370 00371 for (i = 0; i <= NL_CB_TYPE_MAX; i++) { 00372 err = nl_cb_set(cb, i, kind, func, arg); 00373 if (err < 0) 00374 return err; 00375 } 00376 00377 return 0; 00378 } 00379 00380 /** 00381 * Set up an error callback 00382 * @arg cb callback set 00383 * @arg kind kind of callback 00384 * @arg func callback function 00385 * @arg arg argument to be passed to callback function 00386 */ 00387 int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, 00388 nl_recvmsg_err_cb_t func, void *arg) 00389 { 00390 if (kind < 0 || kind > NL_CB_KIND_MAX) 00391 return nl_error(ERANGE, "Callback kind out of range"); 00392 00393 if (kind == NL_CB_CUSTOM) { 00394 cb->cb_err = func; 00395 cb->cb_err_arg = arg; 00396 } else { 00397 cb->cb_err = cb_err_def[kind]; 00398 cb->cb_err_arg = arg; 00399 } 00400 00401 return 0; 00402 } 00403 00404 /** @} */ 00405 00406 /** 00407 * @name Overwriting 00408 * @{ 00409 */ 00410 00411 /** 00412 * Overwrite internal calls to nl_recvmsgs() 00413 * @arg cb callback set 00414 * @arg func replacement callback for nl_recvmsgs() 00415 */ 00416 void nl_cb_overwrite_recvmsgs(struct nl_cb *cb, 00417 int (*func)(struct nl_handle *, struct nl_cb *)) 00418 { 00419 cb->cb_recvmsgs_ow = func; 00420 } 00421 00422 /** 00423 * Overwrite internal calls to nl_recv() 00424 * @arg cb callback set 00425 * @arg func replacement callback for nl_recv() 00426 */ 00427 void nl_cb_overwrite_recv(struct nl_cb *cb, 00428 int (*func)(struct nl_handle *, struct sockaddr_nl *, 00429 unsigned char **, struct ucred **)) 00430 { 00431 cb->cb_recv_ow = func; 00432 } 00433 00434 /** 00435 * Overwrite internal calls to nl_send() 00436 * @arg cb callback set 00437 * @arg func replacement callback for nl_send() 00438 */ 00439 void nl_cb_overwrite_send(struct nl_cb *cb, 00440 int (*func)(struct nl_handle *, struct nl_msg *)) 00441 { 00442 cb->cb_send_ow = func; 00443 } 00444 00445 /** @} */ 00446 00447 /** @} */