X-Git-Url: http://git.onelab.eu/?p=libnl.git;a=blobdiff_plain;f=lib%2Fhandlers.c;fp=lib%2Fhandlers.c;h=c433230a6d7352282bac4316e11aa4d0fc79d48d;hp=0000000000000000000000000000000000000000;hb=4cee2ecb3b8afa0637e6f5fe4c57985a4bc740ff;hpb=2df2fbe518d5a221ce6e3ee88a3fb23fb1b94b27 diff --git a/lib/handlers.c b/lib/handlers.c new file mode 100644 index 0000000..c433230 --- /dev/null +++ b/lib/handlers.c @@ -0,0 +1,581 @@ +/* + * 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 + */ + +/** + * @ingroup nl + * @defgroup cb Callbacks/Customization + * + * Customization via callbacks. + * @{ + */ + +#include +#include +#include +#include +#include + +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 inline void dump_hex(FILE *ofd, char *start, int len) +{ + int i, a, c, limit; + char ascii[21] = {0}; + + limit = 18; + fprintf(ofd, " "); + + for (i = 0, a = 0, c = 0; i < len; i++) { + int v = *(uint8_t *) (start + i); + + fprintf(ofd, "%02x ", v); + ascii[a++] = isprint(v) ? v : '.'; + + if (c == limit-1) { + fprintf(ofd, "%s\n", ascii); + if (i < (len - 1)) + fprintf(ofd, " "); + a = c = 0; + memset(ascii, 0, sizeof(ascii)); + } else + c++; + } + + if (c != 0) { + for (i = 0; i < (limit - c); i++) + fprintf(ofd, " "); + fprintf(ofd, "%s\n", ascii); + } +} + +static void print_hdr(FILE *ofd, struct nl_msg *msg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nl_cache_ops *ops; + char buf[128]; + + fprintf(ofd, " .nlmsg_len = %d\n", nlh->nlmsg_len); + + ops = nl_cache_mngt_associate(nlmsg_get_proto(msg), nlh->nlmsg_type); + + fprintf(ofd, " .nlmsg_type = %d <%s>\n", nlh->nlmsg_type, + ops ? nl_cache_mngt_type2name(ops, nlh->nlmsg_type, + buf, sizeof(buf)) + : nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf))); + fprintf(ofd, " .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags, + nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf))); + fprintf(ofd, " .nlmsg_seq = %d\n", nlh->nlmsg_seq); + fprintf(ofd, " .nlmsg_pid = %d\n", nlh->nlmsg_pid); + +} + +static void raw_dump_msg(FILE *ofd, struct nl_msg *msg) +{ + struct nlmsghdr *hdr = nlmsg_hdr(msg); + + fprintf(ofd, + "-------------------------- BEGIN NETLINK MESSAGE " + "---------------------------\n"); + + fprintf(ofd, " [HEADER] %Zu octets\n", sizeof(struct nlmsghdr)); + print_hdr(ofd, msg); + + if (hdr->nlmsg_type == NLMSG_ERROR && + hdr->nlmsg_len >= nlmsg_msg_size(sizeof(struct nlmsgerr))) { + struct nl_msg *errmsg; + struct nlmsgerr *err = nlmsg_data(hdr); + + fprintf(ofd, " [ERRORMSG] %Zu octets\n", sizeof(*err)); + fprintf(ofd, " .error = %d \"%s\"\n", err->error, + strerror(-err->error)); + fprintf(ofd, " [ORIGINAL MESSAGE] %Zu octets\n", sizeof(*hdr)); + + errmsg = nlmsg_build(&err->msg); + print_hdr(ofd, errmsg); + nlmsg_free(msg); + } else if (nlmsg_len(hdr) > 0) { + struct nl_cache_ops *ops; + int payloadlen = nlmsg_len(hdr); + int attrlen = 0; + + ops = nl_cache_mngt_associate(nlmsg_get_proto(msg), + hdr->nlmsg_type); + if (ops) { + attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); + payloadlen -= attrlen; + } + + fprintf(ofd, " [PAYLOAD] %d octets\n", payloadlen); + dump_hex(ofd, nlmsg_data(hdr), payloadlen); + + if (attrlen) { + int rem, padlen; + struct nlattr *nla; + + nlmsg_for_each_attr(nla, hdr, ops->co_hdrsize, rem) { + int alen = nla_len(nla); + + fprintf(ofd, " [ATTR %02d] %d octets\n", + nla->nla_type, alen); + dump_hex(ofd, nla_data(nla), alen); + + padlen = nla_padlen(alen); + if (padlen > 0) { + fprintf(ofd, " [PADDING] %d octets\n", + padlen); + dump_hex(ofd, nla_data(nla) + alen, + padlen); + } + } + } + } + + fprintf(ofd, + "--------------------------- END NETLINK MESSAGE " + "---------------------------\n"); +} + +static int nl_valid_handler_default(struct nl_msg *msg, void *arg) +{ + return NL_PROCEED; +} + +static int nl_finish_handler_default(struct nl_msg *msg, void *arg) +{ + return NL_EXIT; +} + +static int nl_invalid_handler_default(struct nl_msg *msg, void *arg) +{ + return NL_EXIT; +} + +static int nl_msg_in_handler_default(struct nl_msg *msg, void *arg) +{ + return NL_PROCEED; +} + +static int nl_msg_out_handler_default(struct nl_msg *msg, void *arg) +{ + return NL_PROCEED; +} + +static int nl_overrun_handler_default(struct nl_msg *msg, void *arg) +{ + return NL_EXIT; +} + +static int nl_skipped_handler_default(struct nl_msg *msg, void *arg) +{ + return NL_SKIP; +} + +static int nl_ack_handler_default(struct nl_msg *msg, void *arg) +{ + return NL_EXIT; +} + +static int nl_error_handler_default(struct sockaddr_nl *who, + struct nlmsgerr *e, void *arg) +{ + return NL_EXIT; +} + +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_PROCEED; +} + +static int nl_finish_handler_verbose(struct nl_msg *msg, void *arg) +{ + return NL_EXIT; +} + +static int nl_msg_in_handler_verbose(struct nl_msg *msg, void *arg) +{ + return NL_PROCEED; +} + +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_EXIT; +} + +static int nl_msg_out_handler_verbose(struct nl_msg *msg, void *arg) +{ + return NL_PROCEED; +} + +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_EXIT; +} + +static int nl_ack_handler_verbose(struct nl_msg *msg, void *arg) +{ + return NL_EXIT; +} + +static int nl_skipped_handler_verbose(struct nl_msg *msg, void *arg) +{ + return NL_SKIP; +} + +static int nl_error_handler_verbose(struct sockaddr_nl *who, + struct nlmsgerr *e, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Error received: %s\n-- Original message: ", + strerror(-e->error)); + print_header_content(ofd, &e->msg); + fprintf(ofd, "\n"); + + return NL_EXIT; +} + +static int nl_valid_handler_debug(struct nl_msg *msg, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Debug: Valid message: "); + print_header_content(ofd, nlmsg_hdr(msg)); + fprintf(ofd, "\n"); + + return NL_PROCEED; +} + +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_EXIT; +} + +static int nl_invalid_handler_debug(struct nl_msg *msg, void *arg) +{ + return nl_invalid_handler_verbose(msg, arg); +} + +static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Debug: Received Message:\n"); + raw_dump_msg(ofd, msg); + + return NL_PROCEED; +} + +static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Debug: Sent Message:\n"); + raw_dump_msg(ofd, msg); + + return NL_PROCEED; +} + +static int nl_overrun_handler_debug(struct nl_msg *msg, void *arg) +{ + return nl_overrun_handler_verbose(msg, arg); +} + +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_EXIT; +} + +static int nl_error_handler_debug(struct sockaddr_nl *who, + struct nlmsgerr *e, void *arg) +{ + return nl_error_handler_verbose(who, e, arg); +} + +static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = { + [NL_CB_VALID] = { + [NL_CB_DEFAULT] = nl_valid_handler_default, + [NL_CB_VERBOSE] = nl_valid_handler_verbose, + [NL_CB_DEBUG] = nl_valid_handler_debug, + }, + [NL_CB_FINISH] = { + [NL_CB_DEFAULT] = nl_finish_handler_default, + [NL_CB_VERBOSE] = nl_finish_handler_verbose, + [NL_CB_DEBUG] = nl_finish_handler_debug, + }, + [NL_CB_INVALID] = { + [NL_CB_DEFAULT] = nl_invalid_handler_default, + [NL_CB_VERBOSE] = nl_invalid_handler_verbose, + [NL_CB_DEBUG] = nl_invalid_handler_debug, + }, + [NL_CB_MSG_IN] = { + [NL_CB_DEFAULT] = nl_msg_in_handler_default, + [NL_CB_VERBOSE] = nl_msg_in_handler_verbose, + [NL_CB_DEBUG] = nl_msg_in_handler_debug, + }, + [NL_CB_MSG_OUT] = { + [NL_CB_DEFAULT] = nl_msg_out_handler_default, + [NL_CB_VERBOSE] = nl_msg_out_handler_verbose, + [NL_CB_DEBUG] = nl_msg_out_handler_debug, + }, + [NL_CB_OVERRUN] = { + [NL_CB_DEFAULT] = nl_overrun_handler_default, + [NL_CB_VERBOSE] = nl_overrun_handler_verbose, + [NL_CB_DEBUG] = nl_overrun_handler_debug, + }, + [NL_CB_SKIPPED] = { + [NL_CB_DEFAULT] = nl_skipped_handler_default, + [NL_CB_VERBOSE] = nl_skipped_handler_verbose, + [NL_CB_DEBUG] = nl_skipped_handler_debug, + }, + [NL_CB_ACK] = { + [NL_CB_DEFAULT] = nl_ack_handler_default, + [NL_CB_VERBOSE] = nl_ack_handler_verbose, + [NL_CB_DEBUG] = nl_ack_handler_debug, + }, +}; + +static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = { + [NL_CB_DEFAULT] = nl_error_handler_default, + [NL_CB_VERBOSE] = nl_error_handler_verbose, + [NL_CB_DEBUG] = nl_error_handler_debug, +}; + +/** + * @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_new(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; + } + + 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; +} + +/** + * Destroy a callback handle + * @arg cb callback handle + */ +void nl_cb_destroy(struct nl_cb *cb) +{ + free(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_new(NL_CB_DEFAULT); + if (!cb) + return NULL; + + memcpy(cb, orig, sizeof(*orig)); + + return cb; +} + +/** @} */ + +/** + * @name Callback Setup + * @{ + */ + +/** + * Set up a callback + * @arg cb callback configuration + * @arg type which type callback to 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(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 configuration + * @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 configuration + * @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; +} + +/** + * Overwrite internal calls to nl_recvmsgs() + * @arg cb callback configuration + * @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 configuration + * @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 configuration + * @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; +} + +/** @} */ + +/** @} */