| /* |
| * 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-2008 Thomas Graf <tgraf@suug.ch> |
| */ |
| |
| /** |
| * @ingroup core |
| * @defgroup cb Callbacks/Customization |
| * |
| * Related sections in the development guide: |
| * - @core_doc{core_cb, Callback Configuration} |
| * |
| * @{ |
| * |
| * Header |
| * ------ |
| * ~~~~{.c} |
| * #include <netlink/handlers.h> |
| * ~~~~ |
| */ |
| |
| #include <netlink-private/netlink.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 -nl_syserr2nlerr(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) |
| return NULL; |
| |
| cb->cb_refcnt = 1; |
| cb->cb_active = NL_CB_TYPE_MAX + 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); |
| } |
| |
| /** |
| * Obtain type of current active callback |
| * @arg cb callback to query |
| * |
| * @return type or __NL_CB_TYPE_MAX if none active |
| */ |
| enum nl_cb_type nl_cb_active_type(struct nl_cb *cb) |
| { |
| return cb->cb_active; |
| } |
| |
| /** @} */ |
| |
| /** |
| * @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 -NLE_RANGE; |
| |
| if (kind < 0 || kind > NL_CB_KIND_MAX) |
| return -NLE_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 -NLE_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_sock *, 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_sock *, 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_sock *, struct nl_msg *)) |
| { |
| cb->cb_send_ow = func; |
| } |
| |
| /** @} */ |
| |
| /** @} */ |