As mentioned earlier, the netlink config restructuring in batctl will be splitted in multiple steps. The first step was already merged and the RFC changes for the netlink interface in batman-adv were just posted.
Since it doesn't make sense to have a full implementation in batctl when the batman-adv part is not yet in a finished state. But it also is useless to have only the batman-adv RFC part without a userspace tool. The (by default disabled) config subcommand is (my) solution for this problem. It allows developers to play around with this interface and assign new values for specific keys and to read the current config state.
Make sure that you enable it during the build:
$ make clean; make CONFIG_config=y
Kind regards, Sven
Sven Eckelmann (2): batctl: Add generic netlink configuration subcommand batctl: Add support for config mcast group in event monitor
Makefile | 1 + batman_adv.h | 55 ++++++ config.c | 542 +++++++++++++++++++++++++++++++++++++++++++++++++++ event.c | 100 ++++++++++ man/batctl.8 | 37 ++++ netlink.c | 3 + 6 files changed, 738 insertions(+) create mode 100644 config.c
The batman-adv netlink commandset receive different new commands to read and set the configuration values for mesh interfaces, hard interfaces and VLANs. These are not yet accessible via the normal subcommands. But developers still need access to them to test the kernel interface.
The "config" subcommand provides this functionality for all previously mentioned command classes. It is not suitable for endusers because there is no pretty printing and the user must know the exact type of data (and unit) for the option he wants to change.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Makefile | 1 + batman_adv.h | 55 ++++++ config.c | 542 +++++++++++++++++++++++++++++++++++++++++++++++++++ man/batctl.8 | 37 ++++ netlink.c | 3 + 5 files changed, 638 insertions(+) create mode 100644 config.c
diff --git a/Makefile b/Makefile index e6b2412..c285658 100755 --- a/Makefile +++ b/Makefile @@ -57,6 +57,7 @@ $(eval $(call add_command,bisect_iv,$(CONFIG_BATCTL_BISECT))) $(eval $(call add_command,bonding,y)) $(eval $(call add_command,bridge_loop_avoidance,y)) $(eval $(call add_command,claimtable,y)) +$(eval $(call add_command,config,n)) $(eval $(call add_command,dat_cache,y)) $(eval $(call add_command,distributed_arp_table,y)) $(eval $(call add_command,event,y)) diff --git a/batman_adv.h b/batman_adv.h index 324a0e1..9b5f5f2 100644 --- a/batman_adv.h +++ b/batman_adv.h @@ -27,6 +27,7 @@
#define BATADV_NL_NAME "batadv"
+#define BATADV_NL_MCAST_GROUP_CONFIG "config" #define BATADV_NL_MCAST_GROUP_TPMETER "tpmeter"
/** @@ -344,6 +345,26 @@ enum batadv_nl_attrs { */ BATADV_ATTR_MCAST_FLAGS_PRIV,
+ /** + * @BATADV_ATTR_VLANID: VLAN id on top of soft interface + */ + BATADV_ATTR_VLANID, + + /** + * @BATADV_ATTR_OPTION_NAME: name of option to modify + */ + BATADV_ATTR_OPTION_NAME, + + /** + * @BATADV_ATTR_OPTION_TYPE: type of @BATADV_ATTR_OPTION_VALUE + */ + BATADV_ATTR_OPTION_TYPE, + + /** + * @BATADV_ATTR_OPTION_VALUE: value set for @BATADV_ATTR_OPTION_NAME + */ + BATADV_ATTR_OPTION_VALUE, + /* add attributes above here, update the policy in netlink.c */
/** @@ -443,6 +464,40 @@ enum batadv_nl_commands { */ BATADV_CMD_GET_MCAST_FLAGS,
+ /** + * @BATADV_CMD_GET_OPTION: Get option(s) from softif + */ + BATADV_CMD_GET_OPTION, + + /** + * @BATADV_CMD_SET_OPTION: Set option for softif + */ + BATADV_CMD_SET_OPTION, + + /** + * @BATADV_CMD_GET_OPTION_HARDIF: Get option(s) from a hardif of the + * current softif + */ + BATADV_CMD_GET_OPTION_HARDIF, + + /** + * @BATADV_CMD_SET_OPTION_HARDIF: Set option for hardif of the + * current softif + */ + BATADV_CMD_SET_OPTION_HARDIF, + + /** + * @BATADV_CMD_GET_OPTION_VLAN: Get option(s) from a VLAN of the + * current softif + */ + BATADV_CMD_GET_OPTION_VLAN, + + /** + * @BATADV_CMD_SET_OPTION_VLAN: Set option for VLAN of the + * current softif + */ + BATADV_CMD_SET_OPTION_VLAN, + /* add new commands above here */
/** diff --git a/config.c b/config.c new file mode 100644 index 0000000..2c46e8d --- /dev/null +++ b/config.c @@ -0,0 +1,542 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2007-2018 B.A.T.M.A.N. contributors: + * + * Sven Eckelmann sven@narfation.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + * License-Filename: LICENSES/preferred/GPL-2.0 + */ + +#include "main.h" +#include "functions.h" + +#include <errno.h> +#include <getopt.h> +#include <net/if.h> +#include <netinet/if_ether.h> +#include <netlink/netlink.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/ctrl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "batadv_packet.h" +#include "batman_adv.h" +#include "bat-hosts.h" +#include "debug.h" +#include "functions.h" +#include "main.h" +#include "netlink.h" + +enum config_mode { + CONFIG_MODE_MESH, + CONFIG_MODE_HARDIF, + CONFIG_MODE_VLAN, +}; + +static void config_usage(void) +{ + fprintf(stderr, "Usage: batctl [options] config [parameters] [name [type value]]\n"); + fprintf(stderr, "parameters:\n"); + fprintf(stderr, " \t -H,--hardif hardif to modify\n"); + fprintf(stderr, " \t -V,--vlan vlan to modify\n"); +} + +static int config_callback(struct nl_msg *msg, void *arg __maybe_unused) +{ + static const int config_mandatory[] = { + BATADV_ATTR_OPTION_NAME, + BATADV_ATTR_OPTION_TYPE, + /* BATADV_ATTR_OPTION_VALUE, */ + }; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlattr *attrs[NUM_BATADV_ATTR]; + struct genlmsghdr *ghdr; + const char *name; + uint8_t type; + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + fputs("Received invalid data from kernel.\n", stderr); + return NL_OK; + } + + /* ignore entry when attributes are missing */ + if (missing_mandatory_attrs(attrs, config_mandatory, + ARRAY_SIZE(config_mandatory))) + return NL_OK; + + name = nla_get_string(attrs[BATADV_ATTR_OPTION_NAME]); + type = nla_get_u8(attrs[BATADV_ATTR_OPTION_TYPE]); + + if (type != NLA_FLAG && !attrs[BATADV_ATTR_OPTION_VALUE]) + return NL_OK; + + switch (type) { + case NLA_U8: + printf("%s u8 %u\n", name, + nla_get_u8(attrs[BATADV_ATTR_OPTION_VALUE])); + break; + case NLA_U16: + printf("%s u16 %u\n", name, + nla_get_u16(attrs[BATADV_ATTR_OPTION_VALUE])); + break; + case NLA_U32: + printf("%s u32 %u\n", name, + nla_get_u32(attrs[BATADV_ATTR_OPTION_VALUE])); + break; + case NLA_NUL_STRING: + printf("%s string %s\n", name, + nla_get_string(attrs[BATADV_ATTR_OPTION_VALUE])); + break; + case NLA_FLAG: + printf("%s bool %s\n", name, + attrs[BATADV_ATTR_OPTION_VALUE] ? "true" : "false"); + break; + } + + return NL_OK; +} + +static int nl_error_cb(struct sockaddr_nl *nla __maybe_unused, + struct nlmsgerr *nlerr, void *arg) +{ + int *ret = arg; + + *ret = nlerr->error; + + return NL_STOP; +} + +static int nl_stop_cb(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + int *ret = arg; + int *error = nlmsg_data(nlh); + + if (*error) + *ret = *error; + + return NL_STOP; +} + +static int config_nl_request(struct state *state, int ifindex, + uint8_t nl_cmd, nl_recvmsg_msg_cb_t callback, + int flags, enum config_mode config_mode, + unsigned int hardif_index, + uint16_t vlan_id, const char *option, int type, + const void *val) +{ + struct nl_msg *msg; + void *user_hdr; + int ret; + int res; + + ret = 0; + + if (!state->sock) + return -EOPNOTSUPP; + + if (callback) + nl_cb_set(state->cb, NL_CB_VALID, NL_CB_CUSTOM, config_callback, &ret); + else + nl_cb_set(state->cb, NL_CB_VALID, NL_CB_DEFAULT, NULL, NULL); + + nl_cb_set(state->cb, NL_CB_FINISH, NL_CB_CUSTOM, nl_stop_cb, &ret); + nl_cb_err(state->cb, NL_CB_CUSTOM, nl_error_cb, &ret); + + msg = nlmsg_alloc(); + if (!msg) { + fprintf(stderr, "Error - could not allocate netlink message\n"); + return EXIT_FAILURE; + } + + user_hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, + state->batadv_family, 0, flags, nl_cmd, 1); + if (!user_hdr) { + fprintf(stderr, "Error - failed to store genl header in netlink message\n"); + goto err_free_msg; + } + + ret = nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex); + if (ret < 0) { + fprintf(stderr, "Error - failed to store mesh ifindex in netlink message\n"); + goto err_free_msg; + } + + if (config_mode == CONFIG_MODE_HARDIF) { + ret = nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, hardif_index); + if (ret < 0) { + fprintf(stderr, "Error - failed to store hard ifindex in netlink message\n"); + goto err_free_msg; + } + } + + if (config_mode == CONFIG_MODE_VLAN) { + ret = nla_put_u16(msg, BATADV_ATTR_VLANID, vlan_id); + if (ret < 0) { + fprintf(stderr, "Error - failed to store vlan id in netlink message\n"); + goto err_free_msg; + } + } + + if (option) { + ret = nla_put_string(msg, BATADV_ATTR_OPTION_NAME, option); + if (ret < 0) { + fprintf(stderr, "Error - failed to store option name in netlink message\n"); + goto err_free_msg; + } + } + + if (val) { + switch (type) { + case NLA_NUL_STRING: + ret = nla_put_string(msg, BATADV_ATTR_OPTION_VALUE, val); + break; + case NLA_U32: + ret = nla_put_u32(msg, BATADV_ATTR_OPTION_VALUE, + *(uint32_t *)val); + break; + case NLA_U16: + ret = nla_put_u16(msg, BATADV_ATTR_OPTION_VALUE, + *(uint16_t *)val); + break; + case NLA_U8: + ret = nla_put_u8(msg, BATADV_ATTR_OPTION_VALUE, + *(uint8_t *)val); + break; + case NLA_FLAG: + if (*(bool *)val) + ret = nla_put_flag(msg, + BATADV_ATTR_OPTION_VALUE); + else + ret = 0; + break; + default: + fprintf(stderr, "Error - unsupported type for option\n"); + ret = -EINVAL; + goto err_free_msg; + } + if (ret < 0) { + fprintf(stderr, "Error - failed to store option value in netlink message\n"); + goto err_free_msg; + } + + ret = nla_put_u8(msg, BATADV_ATTR_OPTION_TYPE, type); + if (ret < 0) { + fprintf(stderr, "Error - failed to store option type in netlink message\n"); + goto err_free_msg; + } + } + + res = nl_send_auto_complete(state->sock, msg); + nlmsg_free(msg); + + if (res < 0) { + fprintf(stderr, "Error - failed to send message: %s\n", + strerror(-res)); + return res; + } + + res = nl_recvmsgs(state->sock, state->cb); + if (res < 0 && res != -ECHILD) { + fprintf(stderr, "Error - failed to receive message: %s\n", + strerror(-res)); + return res; + } + + if (ret < 0) { + fprintf(stderr, "Error - failure while processing config request: %s\n", + strerror(-ret)); + return res; + } + + return ret; + +err_free_msg: + nlmsg_free(msg); + return ret; +} + +static int config_dump(struct state *state, int ifindex, + enum config_mode config_mode, unsigned int hardif_index, + uint16_t vlan_id) +{ + enum batadv_nl_commands cmd; + int ret; + + switch (config_mode) { + case CONFIG_MODE_MESH: + cmd = BATADV_CMD_GET_OPTION; + break; + case CONFIG_MODE_HARDIF: + cmd = BATADV_CMD_GET_OPTION_HARDIF; + break; + case CONFIG_MODE_VLAN: + cmd = BATADV_CMD_GET_OPTION_VLAN; + break; + } + + ret = config_nl_request(state, ifindex, cmd, config_callback, + NLM_F_DUMP, config_mode, hardif_index, vlan_id, + NULL, NLA_UNSPEC, NULL); + if (ret < 0) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + +static int config_get_option(struct state *state, int ifindex, + enum config_mode config_mode, + unsigned int hardif_index, uint16_t vlan_id, + const char *option) +{ + enum batadv_nl_commands cmd; + int ret; + + switch (config_mode) { + case CONFIG_MODE_MESH: + cmd = BATADV_CMD_GET_OPTION; + break; + case CONFIG_MODE_HARDIF: + cmd = BATADV_CMD_GET_OPTION_HARDIF; + break; + case CONFIG_MODE_VLAN: + cmd = BATADV_CMD_GET_OPTION_VLAN; + break; + } + + ret = config_nl_request(state, ifindex, cmd, config_callback, 0, + config_mode, hardif_index, vlan_id, option, + NLA_UNSPEC, NULL); + if (ret < 0) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + +static int config_set_option(struct state *state, int ifindex, + enum config_mode config_mode, + unsigned int hardif_index, uint16_t vlan_id, + const char *option, const char *type, + const char *value) +{ + enum batadv_nl_commands cmd; + unsigned long int val_ul; + const void *val; + uint32_t val_u32; + uint16_t val_u16; + uint8_t val_u8; + bool val_bool; + char *endptr; + int nl_type; + int ret; + + switch (config_mode) { + case CONFIG_MODE_MESH: + cmd = BATADV_CMD_SET_OPTION; + break; + case CONFIG_MODE_HARDIF: + cmd = BATADV_CMD_SET_OPTION_HARDIF; + break; + case CONFIG_MODE_VLAN: + cmd = BATADV_CMD_SET_OPTION_VLAN; + break; + } + + if (strcmp(type, "u32") == 0) { + nl_type = NLA_U32; + } else if (strcmp(type, "u16") == 0) { + nl_type = NLA_U16; + } else if (strcmp(type, "u8") == 0) { + nl_type = NLA_U8; + } else if (strcmp(type, "bool") == 0) { + nl_type = NLA_FLAG; + } else if (strcmp(type, "string") == 0) { + nl_type = NLA_NUL_STRING; + } else { + fprintf(stderr, "Error - unsupported type %s\n", type); + return EXIT_FAILURE; + } + + switch (nl_type) { + case NLA_U32: + case NLA_U16: + case NLA_U8: + val_ul = strtoul(value, &endptr, 0); + if (value[0] == '\0' || endptr[0] != '\0') { + fprintf(stderr, "Error - failed to parse value as integer\n"); + return EXIT_FAILURE; + } + break; + } + + switch (nl_type) { + case NLA_U32: + if (val_ul > UINT32_MAX) { + fprintf(stderr, "Error - value too large for u32\n"); + return EXIT_FAILURE; + } + + val_u32 = val_ul; + val = &val_u32; + break; + case NLA_U16: + if (val_ul > UINT16_MAX) { + fprintf(stderr, "Error - value too large for u16\n"); + return EXIT_FAILURE; + } + + val_u16 = val_ul; + val = &val_u16; + break; + case NLA_U8: + if (val_ul > UINT8_MAX) { + fprintf(stderr, "Error - value too large for u8\n"); + return EXIT_FAILURE; + } + + val_u8 = val_ul; + val = &val_u8; + break; + case NLA_FLAG: + if (strcmp(value, "true") == 0) { + val_bool = true; + } else if (strcmp(value, "false") == 0) { + val_bool = false; + } else { + fprintf(stderr, "Error - unsupported boolean value %s\n", value); + return EXIT_FAILURE; + } + val = &val_bool; + break; + case NLA_NUL_STRING: + val = value; + break; + } + + ret = config_nl_request(state, ifindex, cmd, NULL, 0, + config_mode, hardif_index, vlan_id, option, + nl_type, val); + if (ret < 0) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + +static int config(struct state *state, int argc, char **argv) +{ + static const struct option config_options[] = { + { "hardif", required_argument, NULL, 'H' }, + { "vlan", required_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 } + }; + + enum config_mode config_mode = CONFIG_MODE_MESH; + unsigned int hardif_index = 0; + unsigned long int vlan; + uint16_t vlan_id = 0; + const char *option; + const char *value; + const char *type; + char *endptr; + int ifindex; + int opt; + + while ((opt = getopt_long(argc, argv, "+H:V:", config_options, + NULL)) != -1) { + switch (opt) { + case 'H': + if (config_mode != CONFIG_MODE_MESH) { + fprintf(stderr, "Error - multiple targets specified\n"); + return EXIT_FAILURE; + } + + config_mode = CONFIG_MODE_HARDIF; + hardif_index = if_nametoindex(optarg); + if (hardif_index == 0) { + perror("Error - unable to get index for interface"); + return EXIT_FAILURE; + } + break; + case 'V': + if (config_mode != CONFIG_MODE_MESH) { + fprintf(stderr, "Error - multiple targets specified\n"); + return EXIT_FAILURE; + } + + config_mode = CONFIG_MODE_VLAN; + vlan = strtoul(optarg, &endptr, 0); + if (optarg[0] == '\0' || endptr[0] != '\0') { + fprintf(stderr, "Error - failed to parse vlan id\n"); + return EXIT_FAILURE; + } + + if (vlan > 4095) { + fprintf(stderr, "Error - invalid vlan id\n"); + return EXIT_FAILURE; + } + + vlan_id = vlan; + break; + default: + config_usage(); + return EXIT_FAILURE; + } + } + + argv += optind; + argc -= optind; + optind = 0; + + ifindex = if_nametoindex(state->mesh_iface); + if (!ifindex) { + perror("Error - failed to retrieve mesh interface"); + return EXIT_FAILURE; + } + + if (argc <= 0) + return config_dump(state, ifindex, config_mode, hardif_index, + vlan_id); + + option = argv[0]; + if (argc == 1) + return config_get_option(state, ifindex, config_mode, + hardif_index, vlan_id, option); + + if (argc != 3) { + config_usage(); + return EXIT_FAILURE; + } + + type = argv[1]; + value = argv[2]; + + return config_set_option(state, ifindex, config_mode, hardif_index, + vlan_id, option, type, value); +} + +COMMAND(SUBCOMMAND, config, "c", + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, NULL, + "<selector> \treceive or set config option"); diff --git a/man/batctl.8 b/man/batctl.8 index 2e3232f..c542eef 100644 --- a/man/batctl.8 +++ b/man/batctl.8 @@ -338,6 +338,43 @@ specific sequence number, min. Furthermore using "-o" you can filter the output given batctl will not replace the MAC addresses with bat-host names in the output. .RE .br +.IP "\fBconfig\fP [\fB-H hardif\fP][\fB-V VLANID\fP] \fBoption\fP [\fBtype\fP \fBvalue\fP]" +Gets or sets raw configuration options in the batman-adv module for either the +batadv soft interface, a hard (slave) interface or a VLAN of the batadv soft +interface. Providing no option name will dump all the configuration options +for the selected softif/hardif/VLAN. Providing only the option name will +retrieve the configuration configuration value. Providing a full +option-type-value tripplet will set the value in the kernel. The supported +types are u32 (0-4294967295), u16 (0-65535), u8 (0-255), bool (true/false) and +string. +For example: +.sp +.if n {\ +.RS 10 +.} +.nf +# retrieve all configuration options for the soft interface +batctl config +# retrieve all configuration options for the hard interface +batctl config -H eth0 +# retrieve all configuration options for the VLANID 0 +batctl config -V 0 + +# retrieve throughput_override for hard interface eth0 +batctl config -H eth0 throughput_override u32 + +# set fragmentation for bat0 +batctl config fragmentation bool false + +# set orig_interval for bat0 +batctl config orig_interval u32 5000 +.fi +.if n {\ +.RE +.} +.RE +.PP +.br .IP "\fBthroughputmeter\fP|\fBtp\fP \fBMAC\fP" This command starts a throughput test entirely controlled by batman module in kernel space: the computational resources needed to align memory and copy data diff --git a/netlink.c b/netlink.c index 5285759..34cd720 100644 --- a/netlink.c +++ b/netlink.c @@ -107,6 +107,9 @@ struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_DAT_CACHE_VID] = { .type = NLA_U16 }, [BATADV_ATTR_MCAST_FLAGS] = { .type = NLA_U32 }, [BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NLA_U32 }, + [BATADV_ATTR_VLANID] = { .type = NLA_U16 }, + [BATADV_ATTR_OPTION_NAME] = { .type = NLA_NUL_STRING }, + [BATADV_ATTR_OPTION_TYPE] = { .type = NLA_U8 }, };
int netlink_create(struct state *state)
The netlink set netlink messages issued by the config subcommands get as reply a multicast message with the new value. The event monitor should show these messages similar to the tp_meter results.
Signed-off-by: Sven Eckelmann sven@narfation.org --- event.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+)
diff --git a/event.c b/event.c index 8eda269..de5306f 100644 --- a/event.c +++ b/event.c @@ -22,6 +22,7 @@
#include <errno.h> #include <getopt.h> +#include <net/if.h> #include <netinet/if_ether.h> #include <netlink/netlink.h> #include <netlink/genl/genl.h> @@ -87,6 +88,25 @@ static int event_prepare(struct state *state)
skip_tp_meter:
+ mcid = nl_get_multicast_id(state->sock, BATADV_NL_NAME, + BATADV_NL_MCAST_GROUP_CONFIG); + if (mcid < 0) { + fprintf(stderr, "Failed to resolve batadv config multicast group: %d\n", + mcid); + /* ignore error for now */ + goto skip_config; + } + + ret = nl_socket_add_membership(state->sock, mcid); + if (ret) { + fprintf(stderr, "Failed to join batadv config multicast group: %d\n", + ret); + /* ignore error for now */ + goto skip_config; + } + +skip_config: + return 0; }
@@ -145,6 +165,81 @@ static void event_parse_tp_meter(struct nlattr **attrs) printf("tp_meter 0x%08x: %s\n", cookie, result_str); }
+static const int option_mandatory[] = { + BATADV_ATTR_MESH_IFINDEX, + BATADV_ATTR_OPTION_NAME, + BATADV_ATTR_OPTION_TYPE, + /* BATADV_ATTR_OPTION_VALUE, */ +}; + +static void event_parse_option(struct nlattr **attrs) +{ + char meshif_buf[IF_NAMESIZE]; + char hardif_buf[IF_NAMESIZE]; + char extra_info[256]; + char *meshif_name; + char *hardif_name; + uint32_t hardif_ifindex; + uint32_t mesh_ifindex; + const char *name; + uint16_t vid; + uint8_t type; + + /* ignore entry when attributes are missing */ + if (missing_mandatory_attrs(attrs, option_mandatory, + ARRAY_SIZE(option_mandatory))) + return; + + mesh_ifindex = nla_get_u32(attrs[BATADV_ATTR_MESH_IFINDEX]); + meshif_name = if_indextoname(mesh_ifindex, meshif_buf); + if (!meshif_name) + return; + + if (attrs[BATADV_ATTR_HARD_IFINDEX]) { + hardif_ifindex = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); + hardif_name = if_indextoname(hardif_ifindex, hardif_buf); + if (!hardif_name) + return; + + snprintf(extra_info, sizeof(extra_info), " (%s)", hardif_name); + } else if (attrs[BATADV_ATTR_VLANID]) { + vid = nla_get_u16(attrs[BATADV_ATTR_VLANID]); + + snprintf(extra_info, sizeof(extra_info), " (vid %u)", vid); + } else { + extra_info[0] = '\0'; + } + + name = nla_get_string(attrs[BATADV_ATTR_OPTION_NAME]); + type = nla_get_u8(attrs[BATADV_ATTR_OPTION_TYPE]); + + if (type != NLA_FLAG && !attrs[BATADV_ATTR_OPTION_VALUE]) + return; + + switch (type) { + case NLA_U8: + printf("%s%s: %s u8 %u\n", meshif_name, extra_info, name, + nla_get_u8(attrs[BATADV_ATTR_OPTION_VALUE])); + break; + case NLA_U16: + printf("%s%s: %s u16 %u\n", meshif_name, extra_info, name, + nla_get_u16(attrs[BATADV_ATTR_OPTION_VALUE])); + break; + case NLA_U32: + printf("%s%s: %s u32 %u\n", meshif_name, extra_info, name, + nla_get_u32(attrs[BATADV_ATTR_OPTION_VALUE])); + break; + case NLA_NUL_STRING: + printf("%s%s: %s string %s\n", meshif_name, extra_info, name, + nla_get_string(attrs[BATADV_ATTR_OPTION_VALUE])); + break; + case NLA_FLAG: + printf("%s%s: %s bool %s\n", meshif_name, extra_info, name, + attrs[BATADV_ATTR_OPTION_VALUE] ? "true" : "false"); + break; + } +} + static unsigned long long get_timestamp(struct event_args *event_args) { unsigned long long prevtime = 0; @@ -190,6 +285,11 @@ static int event_parse(struct nl_msg *msg, void *arg) case BATADV_CMD_TP_METER: event_parse_tp_meter(attrs); break; + case BATADV_CMD_SET_OPTION: + case BATADV_CMD_SET_OPTION_HARDIF: + case BATADV_CMD_SET_OPTION_VLAN: + event_parse_option(attrs); + break; default: printf("Received unknown event %u\n", ghdr->cmd); break;
b.a.t.m.a.n@lists.open-mesh.org