123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- /*
- * lib/handlers.c default netlink message handlers
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation version 2.1
- * of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- */
- /**
- * @ingroup nl
- * @defgroup cb Callbacks/Customization
- * @brief
- *
- * Callbacks and overwriting capabilities are provided to take influence
- * in various control flows inside the library. All callbacks are packed
- * together in struct nl_cb which is then attached to a netlink socket or
- * passed on to the respective functions directly.
- *
- * Callbacks can control the flow of the underlying layer by returning
- * the appropriate error codes:
- * @code
- * Action ID | Description
- * -----------------+-------------------------------------------------------
- * NL_OK | Proceed with whatever comes next.
- * NL_SKIP | Skip message currently being processed and continue
- * | with next message.
- * NL_STOP | Stop parsing and discard all remaining messages in
- * | this set of messages.
- * @endcode
- *
- * All callbacks are optional and a default action is performed if no
- * application specific implementation is provided:
- *
- * @code
- * Callback ID | Default Return Value
- * ------------------+----------------------
- * NL_CB_VALID | NL_OK
- * NL_CB_FINISH | NL_STOP
- * NL_CB_OVERRUN | NL_STOP
- * NL_CB_SKIPPED | NL_SKIP
- * NL_CB_ACK | NL_STOP
- * NL_CB_MSG_IN | NL_OK
- * NL_CB_MSG_OUT | NL_OK
- * NL_CB_INVALID | NL_STOP
- * NL_CB_SEQ_CHECK | NL_OK
- * NL_CB_SEND_ACK | NL_OK
- * |
- * Error Callback | NL_STOP
- * @endcode
- *
- * In order to simplify typical usages of the library, different sets of
- * default callback implementations exist:
- * @code
- * NL_CB_DEFAULT: No additional actions
- * NL_CB_VERBOSE: Automatically print warning and error messages to a file
- * descriptor as appropriate. This is useful for CLI based
- * applications.
- * NL_CB_DEBUG: Print informal debugging information for each message
- * received. This will result in every message beint sent or
- * received to be printed to the screen in a decoded,
- * human-readable format.
- * @endcode
- *
- * @par 1) Setting up a callback set
- * @code
- * // Allocate a callback set and initialize it to the verbose default set
- * struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE);
- *
- * // Modify the set to call my_func() for all valid messages
- * nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL);
- *
- * // Set the error message handler to the verbose default implementation
- * // and direct it to print all errors to the given file descriptor.
- * FILE *file = fopen(...);
- * nl_cb_err(cb, NL_CB_VERBOSE, NULL, file);
- * @endcode
- * @{
- */
- #include <netlink-local.h>
- #include <netlink/netlink.h>
- #include <netlink/utils.h>
- #include <netlink/msg.h>
- #include <netlink/handlers.h>
- static void print_header_content(FILE *ofd, struct nlmsghdr *n)
- {
- char flags[128];
- char type[32];
-
- fprintf(ofd, "type=%s length=%u flags=<%s> sequence-nr=%u pid=%u",
- nl_nlmsgtype2str(n->nlmsg_type, type, sizeof(type)),
- n->nlmsg_len, nl_nlmsg_flags2str(n->nlmsg_flags, flags,
- sizeof(flags)), n->nlmsg_seq, n->nlmsg_pid);
- }
- static int nl_valid_handler_verbose(struct nl_msg *msg, void *arg)
- {
- FILE *ofd = arg ? arg : stdout;
- fprintf(ofd, "-- Warning: unhandled valid message: ");
- print_header_content(ofd, nlmsg_hdr(msg));
- fprintf(ofd, "\n");
- return NL_OK;
- }
- static int nl_invalid_handler_verbose(struct nl_msg *msg, void *arg)
- {
- FILE *ofd = arg ? arg : stderr;
- fprintf(ofd, "-- Error: Invalid message: ");
- print_header_content(ofd, nlmsg_hdr(msg));
- fprintf(ofd, "\n");
- return NL_STOP;
- }
- static int nl_overrun_handler_verbose(struct nl_msg *msg, void *arg)
- {
- FILE *ofd = arg ? arg : stderr;
- fprintf(ofd, "-- Error: Netlink Overrun: ");
- print_header_content(ofd, nlmsg_hdr(msg));
- fprintf(ofd, "\n");
-
- return NL_STOP;
- }
- static int nl_error_handler_verbose(struct sockaddr_nl *who,
- struct nlmsgerr *e, void *arg)
- {
- FILE *ofd = arg ? arg : stderr;
- char buf[256];
- fprintf(ofd, "-- Error received: %s\n-- Original message: ",
- strerror_r(-e->error, buf, sizeof(buf)));
- print_header_content(ofd, &e->msg);
- fprintf(ofd, "\n");
- return e->error;
- }
- static int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
- {
- FILE *ofd = arg ? arg : stderr;
- fprintf(ofd, "-- Debug: Unhandled Valid message: ");
- print_header_content(ofd, nlmsg_hdr(msg));
- fprintf(ofd, "\n");
- return NL_OK;
- }
- static int nl_finish_handler_debug(struct nl_msg *msg, void *arg)
- {
- FILE *ofd = arg ? arg : stderr;
- fprintf(ofd, "-- Debug: End of multipart message block: ");
- print_header_content(ofd, nlmsg_hdr(msg));
- fprintf(ofd, "\n");
-
- return NL_STOP;
- }
- static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg)
- {
- FILE *ofd = arg ? arg : stderr;
- fprintf(ofd, "-- Debug: Received Message:\n");
- nl_msg_dump(msg, ofd);
-
- return NL_OK;
- }
- static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg)
- {
- FILE *ofd = arg ? arg : stderr;
- fprintf(ofd, "-- Debug: Sent Message:\n");
- nl_msg_dump(msg, ofd);
- return NL_OK;
- }
- static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg)
- {
- FILE *ofd = arg ? arg : stderr;
- fprintf(ofd, "-- Debug: Skipped message: ");
- print_header_content(ofd, nlmsg_hdr(msg));
- fprintf(ofd, "\n");
- return NL_SKIP;
- }
- static int nl_ack_handler_debug(struct nl_msg *msg, void *arg)
- {
- FILE *ofd = arg ? arg : stderr;
- fprintf(ofd, "-- Debug: ACK: ");
- print_header_content(ofd, nlmsg_hdr(msg));
- fprintf(ofd, "\n");
- return NL_STOP;
- }
- static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = {
- [NL_CB_VALID] = {
- [NL_CB_VERBOSE] = nl_valid_handler_verbose,
- [NL_CB_DEBUG] = nl_valid_handler_debug,
- },
- [NL_CB_FINISH] = {
- [NL_CB_DEBUG] = nl_finish_handler_debug,
- },
- [NL_CB_INVALID] = {
- [NL_CB_VERBOSE] = nl_invalid_handler_verbose,
- [NL_CB_DEBUG] = nl_invalid_handler_verbose,
- },
- [NL_CB_MSG_IN] = {
- [NL_CB_DEBUG] = nl_msg_in_handler_debug,
- },
- [NL_CB_MSG_OUT] = {
- [NL_CB_DEBUG] = nl_msg_out_handler_debug,
- },
- [NL_CB_OVERRUN] = {
- [NL_CB_VERBOSE] = nl_overrun_handler_verbose,
- [NL_CB_DEBUG] = nl_overrun_handler_verbose,
- },
- [NL_CB_SKIPPED] = {
- [NL_CB_DEBUG] = nl_skipped_handler_debug,
- },
- [NL_CB_ACK] = {
- [NL_CB_DEBUG] = nl_ack_handler_debug,
- },
- };
- static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = {
- [NL_CB_VERBOSE] = nl_error_handler_verbose,
- [NL_CB_DEBUG] = nl_error_handler_verbose,
- };
- /**
- * @name Callback Handle Management
- * @{
- */
- /**
- * Allocate a new callback handle
- * @arg kind callback kind to be used for initialization
- * @return Newly allocated callback handle or NULL
- */
- struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
- {
- int i;
- struct nl_cb *cb;
- if (kind < 0 || kind > NL_CB_KIND_MAX)
- return NULL;
- cb = calloc(1, sizeof(*cb));
- if (!cb) {
- nl_errno(ENOMEM);
- return NULL;
- }
- cb->cb_refcnt = 1;
- for (i = 0; i <= NL_CB_TYPE_MAX; i++)
- nl_cb_set(cb, i, kind, NULL, NULL);
- nl_cb_err(cb, kind, NULL, NULL);
- return cb;
- }
- /**
- * Clone an existing callback handle
- * @arg orig original callback handle
- * @return Newly allocated callback handle being a duplicate of
- * orig or NULL
- */
- struct nl_cb *nl_cb_clone(struct nl_cb *orig)
- {
- struct nl_cb *cb;
-
- cb = nl_cb_alloc(NL_CB_DEFAULT);
- if (!cb)
- return NULL;
- memcpy(cb, orig, sizeof(*orig));
- cb->cb_refcnt = 1;
- return cb;
- }
- struct nl_cb *nl_cb_get(struct nl_cb *cb)
- {
- cb->cb_refcnt++;
- return cb;
- }
- void nl_cb_put(struct nl_cb *cb)
- {
- if (!cb)
- return;
- cb->cb_refcnt--;
- if (cb->cb_refcnt < 0)
- BUG();
- if (cb->cb_refcnt <= 0)
- free(cb);
- }
- /** @} */
- /**
- * @name Callback Setup
- * @{
- */
- /**
- * Set up a callback
- * @arg cb callback set
- * @arg type callback to modify
- * @arg kind kind of implementation
- * @arg func callback function (NL_CB_CUSTOM)
- * @arg arg argument passed to callback
- *
- * @return 0 on success or a negative error code
- */
- int 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)
- {
- if (type < 0 || type > NL_CB_TYPE_MAX)
- return nl_error(ERANGE, "Callback type out of range");
- if (kind < 0 || kind > NL_CB_KIND_MAX)
- return nl_error(ERANGE, "Callback kind out of range");
- if (kind == NL_CB_CUSTOM) {
- cb->cb_set[type] = func;
- cb->cb_args[type] = arg;
- } else {
- cb->cb_set[type] = cb_def[type][kind];
- cb->cb_args[type] = arg;
- }
- return 0;
- }
- /**
- * Set up a all callbacks
- * @arg cb callback set
- * @arg kind kind of callback
- * @arg func callback function
- * @arg arg argument to be passwd to callback function
- *
- * @return 0 on success or a negative error code
- */
- int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
- nl_recvmsg_msg_cb_t func, void *arg)
- {
- int i, err;
- for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
- err = nl_cb_set(cb, i, kind, func, arg);
- if (err < 0)
- return err;
- }
- return 0;
- }
- /**
- * Set up an error callback
- * @arg cb callback set
- * @arg kind kind of callback
- * @arg func callback function
- * @arg arg argument to be passed to callback function
- */
- int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
- nl_recvmsg_err_cb_t func, void *arg)
- {
- if (kind < 0 || kind > NL_CB_KIND_MAX)
- return nl_error(ERANGE, "Callback kind out of range");
- if (kind == NL_CB_CUSTOM) {
- cb->cb_err = func;
- cb->cb_err_arg = arg;
- } else {
- cb->cb_err = cb_err_def[kind];
- cb->cb_err_arg = arg;
- }
- return 0;
- }
- /** @} */
- /**
- * @name Overwriting
- * @{
- */
- /**
- * Overwrite internal calls to nl_recvmsgs()
- * @arg cb callback set
- * @arg func replacement callback for nl_recvmsgs()
- */
- void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
- int (*func)(struct nl_handle *, struct nl_cb *))
- {
- cb->cb_recvmsgs_ow = func;
- }
- /**
- * Overwrite internal calls to nl_recv()
- * @arg cb callback set
- * @arg func replacement callback for nl_recv()
- */
- void nl_cb_overwrite_recv(struct nl_cb *cb,
- int (*func)(struct nl_handle *, struct sockaddr_nl *,
- unsigned char **, struct ucred **))
- {
- cb->cb_recv_ow = func;
- }
- /**
- * Overwrite internal calls to nl_send()
- * @arg cb callback set
- * @arg func replacement callback for nl_send()
- */
- void nl_cb_overwrite_send(struct nl_cb *cb,
- int (*func)(struct nl_handle *, struct nl_msg *))
- {
- cb->cb_send_ow = func;
- }
- /** @} */
- /** @} */
|