handlers.c revision 1155370f520cb64657e25153255cf7dc1424317f
144d362409d5469aed47d19e7908d19bd194493aThomas Graf/*
244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/handlers.c	default netlink message handlers
344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
444d362409d5469aed47d19e7908d19bd194493aThomas Graf *	This library is free software; you can redistribute it and/or
544d362409d5469aed47d19e7908d19bd194493aThomas Graf *	modify it under the terms of the GNU Lesser General Public
644d362409d5469aed47d19e7908d19bd194493aThomas Graf *	License as published by the Free Software Foundation version 2.1
744d362409d5469aed47d19e7908d19bd194493aThomas Graf *	of the License.
844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
98a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
1044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1144d362409d5469aed47d19e7908d19bd194493aThomas Graf
1244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
1344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @ingroup nl
1444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @defgroup cb Callbacks/Customization
1544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @brief
1644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
1744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Callbacks and overwriting capabilities are provided to take influence
1844d362409d5469aed47d19e7908d19bd194493aThomas Graf * in various control flows inside the library. All callbacks are packed
1944d362409d5469aed47d19e7908d19bd194493aThomas Graf * together in struct nl_cb which is then attached to a netlink socket or
2044d362409d5469aed47d19e7908d19bd194493aThomas Graf * passed on to the respective functions directly.
2144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
2244d362409d5469aed47d19e7908d19bd194493aThomas Graf * Callbacks can control the flow of the underlying layer by returning
2344d362409d5469aed47d19e7908d19bd194493aThomas Graf * the appropriate error codes:
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf * Action ID        | Description
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf * -----------------+-------------------------------------------------------
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_OK       | Proceed with whatever comes next.
2844d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_SKIP          | Skip message currently being processed and continue
2944d362409d5469aed47d19e7908d19bd194493aThomas Graf *                  | with next message.
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_STOP          | Stop parsing and discard all remaining messages in
3144d362409d5469aed47d19e7908d19bd194493aThomas Graf *                  | this set of messages.
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
3344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
3444d362409d5469aed47d19e7908d19bd194493aThomas Graf * All callbacks are optional and a default action is performed if no
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf * application specific implementation is provided:
3644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
3744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
3844d362409d5469aed47d19e7908d19bd194493aThomas Graf * Callback ID       | Default Return Value
3944d362409d5469aed47d19e7908d19bd194493aThomas Graf * ------------------+----------------------
4044d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_VALID       | NL_OK
4144d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_FINISH      | NL_STOP
4244d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_OVERRUN     | NL_STOP
4344d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_SKIPPED     | NL_SKIP
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_ACK         | NL_STOP
4544d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_MSG_IN      | NL_OK
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_MSG_OUT     | NL_OK
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_INVALID     | NL_STOP
4844d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_SEQ_CHECK   | NL_OK
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_SEND_ACK    | NL_OK
5044d362409d5469aed47d19e7908d19bd194493aThomas Graf *                   |
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Error Callback    | NL_STOP
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf * In order to simplify typical usages of the library, different sets of
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf * default callback implementations exist:
5644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_DEFAULT: No additional actions
5844d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_VERBOSE: Automatically print warning and error messages to a file
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf *                descriptor as appropriate. This is useful for CLI based
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf *                applications.
6144d362409d5469aed47d19e7908d19bd194493aThomas Graf * NL_CB_DEBUG:   Print informal debugging information for each message
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf *                received. This will result in every message beint sent or
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf *                received to be printed to the screen in a decoded,
6444d362409d5469aed47d19e7908d19bd194493aThomas Graf *                human-readable format.
6544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
6644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
6744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 1) Setting up a callback set
6844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
6944d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Allocate a callback set and initialize it to the verbose default set
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE);
7144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
7244d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Modify the set to call my_func() for all valid messages
7344d362409d5469aed47d19e7908d19bd194493aThomas Graf * nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL);
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Set the error message handler to the verbose default implementation
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // and direct it to print all errors to the given file descriptor.
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf * FILE *file = fopen(...);
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf * nl_cb_err(cb, NL_CB_VERBOSE, NULL, file);
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h>
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h>
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h>
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/msg.h>
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/handlers.h>
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf
8944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void print_header_content(FILE *ofd, struct nlmsghdr *n)
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf	char flags[128];
9244d362409d5469aed47d19e7908d19bd194493aThomas Graf	char type[32];
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "type=%s length=%u flags=<%s> sequence-nr=%u pid=%u",
9544d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_nlmsgtype2str(n->nlmsg_type, type, sizeof(type)),
9644d362409d5469aed47d19e7908d19bd194493aThomas Graf		n->nlmsg_len, nl_nlmsg_flags2str(n->nlmsg_flags, flags,
9744d362409d5469aed47d19e7908d19bd194493aThomas Graf		sizeof(flags)), n->nlmsg_seq, n->nlmsg_pid);
9844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
9944d362409d5469aed47d19e7908d19bd194493aThomas Graf
10044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int nl_valid_handler_verbose(struct nl_msg *msg, void *arg)
10144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf	FILE *ofd = arg ? arg : stdout;
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "-- Warning: unhandled valid message: ");
10544d362409d5469aed47d19e7908d19bd194493aThomas Graf	print_header_content(ofd, nlmsg_hdr(msg));
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "\n");
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NL_OK;
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf
11144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int nl_invalid_handler_verbose(struct nl_msg *msg, void *arg)
11244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf	FILE *ofd = arg ? arg : stderr;
11444d362409d5469aed47d19e7908d19bd194493aThomas Graf
11544d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "-- Error: Invalid message: ");
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf	print_header_content(ofd, nlmsg_hdr(msg));
11744d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "\n");
11844d362409d5469aed47d19e7908d19bd194493aThomas Graf
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NL_STOP;
12044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf
12244d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int nl_overrun_handler_verbose(struct nl_msg *msg, void *arg)
12344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf	FILE *ofd = arg ? arg : stderr;
12544d362409d5469aed47d19e7908d19bd194493aThomas Graf
12644d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "-- Error: Netlink Overrun: ");
12744d362409d5469aed47d19e7908d19bd194493aThomas Graf	print_header_content(ofd, nlmsg_hdr(msg));
12844d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "\n");
12944d362409d5469aed47d19e7908d19bd194493aThomas Graf
13044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NL_STOP;
13144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf
13344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int nl_error_handler_verbose(struct sockaddr_nl *who,
13444d362409d5469aed47d19e7908d19bd194493aThomas Graf				    struct nlmsgerr *e, void *arg)
13544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
13644d362409d5469aed47d19e7908d19bd194493aThomas Graf	FILE *ofd = arg ? arg : stderr;
13744d362409d5469aed47d19e7908d19bd194493aThomas Graf
13844d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "-- Error received: %s\n-- Original message: ",
13944d362409d5469aed47d19e7908d19bd194493aThomas Graf		strerror(-e->error));
14044d362409d5469aed47d19e7908d19bd194493aThomas Graf	print_header_content(ofd, &e->msg);
14144d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "\n");
14244d362409d5469aed47d19e7908d19bd194493aThomas Graf
1438a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return -nl_syserr2nlerr(e->error);
14444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
14544d362409d5469aed47d19e7908d19bd194493aThomas Graf
14644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
14744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
14844d362409d5469aed47d19e7908d19bd194493aThomas Graf	FILE *ofd = arg ? arg : stderr;
14944d362409d5469aed47d19e7908d19bd194493aThomas Graf
15044d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "-- Debug: Unhandled Valid message: ");
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf	print_header_content(ofd, nlmsg_hdr(msg));
15244d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "\n");
15344d362409d5469aed47d19e7908d19bd194493aThomas Graf
15444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NL_OK;
15544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
15644d362409d5469aed47d19e7908d19bd194493aThomas Graf
15744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int nl_finish_handler_debug(struct nl_msg *msg, void *arg)
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
15944d362409d5469aed47d19e7908d19bd194493aThomas Graf	FILE *ofd = arg ? arg : stderr;
16044d362409d5469aed47d19e7908d19bd194493aThomas Graf
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "-- Debug: End of multipart message block: ");
16244d362409d5469aed47d19e7908d19bd194493aThomas Graf	print_header_content(ofd, nlmsg_hdr(msg));
16344d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "\n");
16444d362409d5469aed47d19e7908d19bd194493aThomas Graf
16544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NL_STOP;
16644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
16744d362409d5469aed47d19e7908d19bd194493aThomas Graf
16844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg)
16944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf	FILE *ofd = arg ? arg : stderr;
17144d362409d5469aed47d19e7908d19bd194493aThomas Graf
17244d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "-- Debug: Received Message:\n");
17344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_msg_dump(msg, ofd);
17444d362409d5469aed47d19e7908d19bd194493aThomas Graf
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NL_OK;
17644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
17744d362409d5469aed47d19e7908d19bd194493aThomas Graf
17844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg)
17944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
18044d362409d5469aed47d19e7908d19bd194493aThomas Graf	FILE *ofd = arg ? arg : stderr;
18144d362409d5469aed47d19e7908d19bd194493aThomas Graf
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "-- Debug: Sent Message:\n");
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_msg_dump(msg, ofd);
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf
18544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NL_OK;
18644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
18744d362409d5469aed47d19e7908d19bd194493aThomas Graf
18844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int nl_skipped_handler_debug(struct nl_msg *msg, void *arg)
18944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
19044d362409d5469aed47d19e7908d19bd194493aThomas Graf	FILE *ofd = arg ? arg : stderr;
19144d362409d5469aed47d19e7908d19bd194493aThomas Graf
19244d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "-- Debug: Skipped message: ");
19344d362409d5469aed47d19e7908d19bd194493aThomas Graf	print_header_content(ofd, nlmsg_hdr(msg));
19444d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "\n");
19544d362409d5469aed47d19e7908d19bd194493aThomas Graf
19644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NL_SKIP;
19744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
19844d362409d5469aed47d19e7908d19bd194493aThomas Graf
19944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int nl_ack_handler_debug(struct nl_msg *msg, void *arg)
20044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
20144d362409d5469aed47d19e7908d19bd194493aThomas Graf	FILE *ofd = arg ? arg : stderr;
20244d362409d5469aed47d19e7908d19bd194493aThomas Graf
20344d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "-- Debug: ACK: ");
20444d362409d5469aed47d19e7908d19bd194493aThomas Graf	print_header_content(ofd, nlmsg_hdr(msg));
20544d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(ofd, "\n");
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf
20744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NL_STOP;
20844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
20944d362409d5469aed47d19e7908d19bd194493aThomas Graf
21044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = {
21144d362409d5469aed47d19e7908d19bd194493aThomas Graf	[NL_CB_VALID] = {
21244d362409d5469aed47d19e7908d19bd194493aThomas Graf		[NL_CB_VERBOSE]	= nl_valid_handler_verbose,
21344d362409d5469aed47d19e7908d19bd194493aThomas Graf		[NL_CB_DEBUG]	= nl_valid_handler_debug,
21444d362409d5469aed47d19e7908d19bd194493aThomas Graf	},
21544d362409d5469aed47d19e7908d19bd194493aThomas Graf	[NL_CB_FINISH] = {
21644d362409d5469aed47d19e7908d19bd194493aThomas Graf		[NL_CB_DEBUG]	= nl_finish_handler_debug,
21744d362409d5469aed47d19e7908d19bd194493aThomas Graf	},
21844d362409d5469aed47d19e7908d19bd194493aThomas Graf	[NL_CB_INVALID] = {
21944d362409d5469aed47d19e7908d19bd194493aThomas Graf		[NL_CB_VERBOSE]	= nl_invalid_handler_verbose,
22044d362409d5469aed47d19e7908d19bd194493aThomas Graf		[NL_CB_DEBUG]	= nl_invalid_handler_verbose,
22144d362409d5469aed47d19e7908d19bd194493aThomas Graf	},
22244d362409d5469aed47d19e7908d19bd194493aThomas Graf	[NL_CB_MSG_IN] = {
22344d362409d5469aed47d19e7908d19bd194493aThomas Graf		[NL_CB_DEBUG]	= nl_msg_in_handler_debug,
22444d362409d5469aed47d19e7908d19bd194493aThomas Graf	},
22544d362409d5469aed47d19e7908d19bd194493aThomas Graf	[NL_CB_MSG_OUT] = {
22644d362409d5469aed47d19e7908d19bd194493aThomas Graf		[NL_CB_DEBUG]	= nl_msg_out_handler_debug,
22744d362409d5469aed47d19e7908d19bd194493aThomas Graf	},
22844d362409d5469aed47d19e7908d19bd194493aThomas Graf	[NL_CB_OVERRUN] = {
22944d362409d5469aed47d19e7908d19bd194493aThomas Graf		[NL_CB_VERBOSE]	= nl_overrun_handler_verbose,
23044d362409d5469aed47d19e7908d19bd194493aThomas Graf		[NL_CB_DEBUG]	= nl_overrun_handler_verbose,
23144d362409d5469aed47d19e7908d19bd194493aThomas Graf	},
23244d362409d5469aed47d19e7908d19bd194493aThomas Graf	[NL_CB_SKIPPED] = {
23344d362409d5469aed47d19e7908d19bd194493aThomas Graf		[NL_CB_DEBUG]	= nl_skipped_handler_debug,
23444d362409d5469aed47d19e7908d19bd194493aThomas Graf	},
23544d362409d5469aed47d19e7908d19bd194493aThomas Graf	[NL_CB_ACK] = {
23644d362409d5469aed47d19e7908d19bd194493aThomas Graf		[NL_CB_DEBUG]	= nl_ack_handler_debug,
23744d362409d5469aed47d19e7908d19bd194493aThomas Graf	},
23844d362409d5469aed47d19e7908d19bd194493aThomas Graf};
23944d362409d5469aed47d19e7908d19bd194493aThomas Graf
24044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = {
24144d362409d5469aed47d19e7908d19bd194493aThomas Graf	[NL_CB_VERBOSE]	= nl_error_handler_verbose,
24244d362409d5469aed47d19e7908d19bd194493aThomas Graf	[NL_CB_DEBUG]	= nl_error_handler_verbose,
24344d362409d5469aed47d19e7908d19bd194493aThomas Graf};
24444d362409d5469aed47d19e7908d19bd194493aThomas Graf
24544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
24644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Callback Handle Management
24744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
24944d362409d5469aed47d19e7908d19bd194493aThomas Graf
25044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
25144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Allocate a new callback handle
25244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg kind		callback kind to be used for initialization
25344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Newly allocated callback handle or NULL
25444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
25544d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
25644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
25744d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i;
25844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cb *cb;
25944d362409d5469aed47d19e7908d19bd194493aThomas Graf
26044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (kind < 0 || kind > NL_CB_KIND_MAX)
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
26244d362409d5469aed47d19e7908d19bd194493aThomas Graf
26344d362409d5469aed47d19e7908d19bd194493aThomas Graf	cb = calloc(1, sizeof(*cb));
2648a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	if (!cb)
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
26644d362409d5469aed47d19e7908d19bd194493aThomas Graf
26744d362409d5469aed47d19e7908d19bd194493aThomas Graf	cb->cb_refcnt = 1;
26844d362409d5469aed47d19e7908d19bd194493aThomas Graf
26944d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (i = 0; i <= NL_CB_TYPE_MAX; i++)
27044d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_cb_set(cb, i, kind, NULL, NULL);
27144d362409d5469aed47d19e7908d19bd194493aThomas Graf
27244d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_cb_err(cb, kind, NULL, NULL);
27344d362409d5469aed47d19e7908d19bd194493aThomas Graf
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return cb;
27544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
27644d362409d5469aed47d19e7908d19bd194493aThomas Graf
27744d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
27844d362409d5469aed47d19e7908d19bd194493aThomas Graf * Clone an existing callback handle
27944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg orig		original callback handle
28044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Newly allocated callback handle being a duplicate of
28144d362409d5469aed47d19e7908d19bd194493aThomas Graf *         orig or NULL
28244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
28344d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_cb *nl_cb_clone(struct nl_cb *orig)
28444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
28544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cb *cb;
28644d362409d5469aed47d19e7908d19bd194493aThomas Graf
28744d362409d5469aed47d19e7908d19bd194493aThomas Graf	cb = nl_cb_alloc(NL_CB_DEFAULT);
28844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!cb)
28944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
29044d362409d5469aed47d19e7908d19bd194493aThomas Graf
29144d362409d5469aed47d19e7908d19bd194493aThomas Graf	memcpy(cb, orig, sizeof(*orig));
29244d362409d5469aed47d19e7908d19bd194493aThomas Graf	cb->cb_refcnt = 1;
29344d362409d5469aed47d19e7908d19bd194493aThomas Graf
29444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return cb;
29544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
29644d362409d5469aed47d19e7908d19bd194493aThomas Graf
29744d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_cb *nl_cb_get(struct nl_cb *cb)
29844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
29944d362409d5469aed47d19e7908d19bd194493aThomas Graf	cb->cb_refcnt++;
30044d362409d5469aed47d19e7908d19bd194493aThomas Graf
30144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return cb;
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
30344d362409d5469aed47d19e7908d19bd194493aThomas Graf
30444d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid nl_cb_put(struct nl_cb *cb)
30544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
30644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!cb)
30744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return;
30844d362409d5469aed47d19e7908d19bd194493aThomas Graf
30944d362409d5469aed47d19e7908d19bd194493aThomas Graf	cb->cb_refcnt--;
31044d362409d5469aed47d19e7908d19bd194493aThomas Graf
31144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cb->cb_refcnt < 0)
31244d362409d5469aed47d19e7908d19bd194493aThomas Graf		BUG();
31344d362409d5469aed47d19e7908d19bd194493aThomas Graf
31444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cb->cb_refcnt <= 0)
31544d362409d5469aed47d19e7908d19bd194493aThomas Graf		free(cb);
31644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
31744d362409d5469aed47d19e7908d19bd194493aThomas Graf
31844d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
31944d362409d5469aed47d19e7908d19bd194493aThomas Graf
32044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
32144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Callback Setup
32244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
32344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
32444d362409d5469aed47d19e7908d19bd194493aThomas Graf
32544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
32644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Set up a callback
32744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cb		callback set
32844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg type		callback to modify
32944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg kind		kind of implementation
33044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg func		callback function (NL_CB_CUSTOM)
33144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg arg		argument passed to callback
33244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
33344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code
33444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
33544d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
33644d362409d5469aed47d19e7908d19bd194493aThomas Graf	      nl_recvmsg_msg_cb_t func, void *arg)
33744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
33844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (type < 0 || type > NL_CB_TYPE_MAX)
3398a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_RANGE;
34044d362409d5469aed47d19e7908d19bd194493aThomas Graf
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (kind < 0 || kind > NL_CB_KIND_MAX)
3428a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_RANGE;
34344d362409d5469aed47d19e7908d19bd194493aThomas Graf
34444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (kind == NL_CB_CUSTOM) {
34544d362409d5469aed47d19e7908d19bd194493aThomas Graf		cb->cb_set[type] = func;
34644d362409d5469aed47d19e7908d19bd194493aThomas Graf		cb->cb_args[type] = arg;
34744d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else {
34844d362409d5469aed47d19e7908d19bd194493aThomas Graf		cb->cb_set[type] = cb_def[type][kind];
34944d362409d5469aed47d19e7908d19bd194493aThomas Graf		cb->cb_args[type] = arg;
35044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
35144d362409d5469aed47d19e7908d19bd194493aThomas Graf
35244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
35344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
35444d362409d5469aed47d19e7908d19bd194493aThomas Graf
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
35644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Set up a all callbacks
35744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cb		callback set
35844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg kind		kind of callback
35944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg func		callback function
36044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg arg		argument to be passwd to callback function
36144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
36244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code
36344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
36444d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
36544d362409d5469aed47d19e7908d19bd194493aThomas Graf		  nl_recvmsg_msg_cb_t func, void *arg)
36644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
36744d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i, err;
36844d362409d5469aed47d19e7908d19bd194493aThomas Graf
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = nl_cb_set(cb, i, kind, func, arg);
37144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
37244d362409d5469aed47d19e7908d19bd194493aThomas Graf			return err;
37344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
37444d362409d5469aed47d19e7908d19bd194493aThomas Graf
37544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
37644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf
37844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
37944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Set up an error callback
38044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cb		callback set
38144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg kind		kind of callback
38244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg func		callback function
38344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg arg		argument to be passed to callback function
38444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
38544d362409d5469aed47d19e7908d19bd194493aThomas Grafint nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
38644d362409d5469aed47d19e7908d19bd194493aThomas Graf	      nl_recvmsg_err_cb_t func, void *arg)
38744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
38844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (kind < 0 || kind > NL_CB_KIND_MAX)
3898a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_RANGE;
39044d362409d5469aed47d19e7908d19bd194493aThomas Graf
39144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (kind == NL_CB_CUSTOM) {
39244d362409d5469aed47d19e7908d19bd194493aThomas Graf		cb->cb_err = func;
39344d362409d5469aed47d19e7908d19bd194493aThomas Graf		cb->cb_err_arg = arg;
39444d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else {
39544d362409d5469aed47d19e7908d19bd194493aThomas Graf		cb->cb_err = cb_err_def[kind];
39644d362409d5469aed47d19e7908d19bd194493aThomas Graf		cb->cb_err_arg = arg;
39744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
39844d362409d5469aed47d19e7908d19bd194493aThomas Graf
39944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
40044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
40144d362409d5469aed47d19e7908d19bd194493aThomas Graf
40244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
40344d362409d5469aed47d19e7908d19bd194493aThomas Graf
40444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
40544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Overwriting
40644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
40744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
40844d362409d5469aed47d19e7908d19bd194493aThomas Graf
40944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
41044d362409d5469aed47d19e7908d19bd194493aThomas Graf * Overwrite internal calls to nl_recvmsgs()
41144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cb		callback set
41244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg func		replacement callback for nl_recvmsgs()
41344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
41444d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
4151155370f520cb64657e25153255cf7dc1424317fThomas Graf			      int (*func)(struct nl_sock *, struct nl_cb *))
41644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
41744d362409d5469aed47d19e7908d19bd194493aThomas Graf	cb->cb_recvmsgs_ow = func;
41844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
41944d362409d5469aed47d19e7908d19bd194493aThomas Graf
42044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
42144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Overwrite internal calls to nl_recv()
42244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cb		callback set
42344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg func		replacement callback for nl_recv()
42444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
42544d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid nl_cb_overwrite_recv(struct nl_cb *cb,
4261155370f520cb64657e25153255cf7dc1424317fThomas Graf			  int (*func)(struct nl_sock *, struct sockaddr_nl *,
42744d362409d5469aed47d19e7908d19bd194493aThomas Graf				      unsigned char **, struct ucred **))
42844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
42944d362409d5469aed47d19e7908d19bd194493aThomas Graf	cb->cb_recv_ow = func;
43044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
43144d362409d5469aed47d19e7908d19bd194493aThomas Graf
43244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
43344d362409d5469aed47d19e7908d19bd194493aThomas Graf * Overwrite internal calls to nl_send()
43444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cb		callback set
43544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg func		replacement callback for nl_send()
43644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
43744d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid nl_cb_overwrite_send(struct nl_cb *cb,
4381155370f520cb64657e25153255cf7dc1424317fThomas Graf			  int (*func)(struct nl_sock *, struct nl_msg *))
43944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
44044d362409d5469aed47d19e7908d19bd194493aThomas Graf	cb->cb_send_ow = func;
44144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
44244d362409d5469aed47d19e7908d19bd194493aThomas Graf
44344d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
44444d362409d5469aed47d19e7908d19bd194493aThomas Graf
44544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
446