Logo Search packages:      
Sourcecode: libnl version File versions  Download package

handlers.c

/*
 * 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
 * 
 * Customization via callbacks.
 * @{
 */

#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 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
 */
00411 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
 */
00437 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
 */
00448 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
 */
00478 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
 */
00507 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
 */
00528 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()
 */
00550 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()
 */
00561 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()
 */
00573 void nl_cb_overwrite_send(struct nl_cb *cb,
                    int (*func)(struct nl_handle *, struct nl_msg *))
{
      cb->cb_send_ow = func;
}

/** @} */

/** @} */

Generated by  Doxygen 1.6.0   Back to index