libnl 1.1

lib/handlers.c

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 /** @} */