mirror of
https://gitee.com/openharmony/third_party_libnl
synced 2024-12-12 13:19:25 +00:00
448 lines
10 KiB
C
448 lines
10 KiB
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
|
||
|
* @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;
|
||
|
|
||
|
fprintf(ofd, "-- Error received: %s\n-- Original message: ",
|
||
|
strerror(-e->error));
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/** @} */
|
||
|
|
||
|
/** @} */
|