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.
The batman-adv weren't directly rejected by Jiro and thus I've started to convert all settings to netlink while still allowing sysfs as fallback.
v3: * fix kernel-doc in batman_adv.h * add three patches to use the netlink interface with the already existing setting commands v2: * drop of generic config command * reimplementation of the event command
Sven Eckelmann (4): batctl: Add support for config mcast group in event monitor batctl: Don't allocate new buffer for vlan parent device batctl: Automatically translate vlan to mesh_iface batctl: Use netlink as new configuration interface
aggregation.c | 45 ++++- ap_isolation.c | 67 ++++++- batman_adv.h | 188 +++++++++++++++++- bonding.c | 45 ++++- bridge_loop_avoidance.c | 46 ++++- distributed_arp_table.c | 46 ++++- event.c | 234 ++++++++++++++++++++++ fragmentation.c | 45 ++++- functions.c | 160 +++++++++++++--- functions.h | 24 ++- gateways.c | 10 +- gw_mode.c | 415 +++++++++++++++++++++++++++++++--------- isolation_mark.c | 123 +++++++++++- loglevel.c | 138 ++++++++++--- main.c | 10 +- main.h | 6 +- mcast_flags.c | 10 +- multicast_mode.c | 45 ++++- netlink.c | 108 ++++++++++- netlink.h | 2 + network_coding.c | 45 ++++- orig_interval.c | 84 +++++++- originators.c | 10 +- routing_algo.c | 1 - sys.c | 220 ++++++++++++++++----- sys.h | 26 ++- 26 files changed, 1897 insertions(+), 256 deletions(-)
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 --- batman_adv.h | 188 +++++++++++++++++++++++++++++++++++++++-- event.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++ netlink.c | 20 +++++ 3 files changed, 437 insertions(+), 5 deletions(-)
diff --git a/batman_adv.h b/batman_adv.h index 324a0e1..b5a245e 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"
/** @@ -138,6 +139,20 @@ enum batadv_mcast_flags_priv { BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING = (1 << 4), };
+/** + * enum batadv_gw_modes - gateway mode of node + */ +enum batadv_gw_modes { + /** @BATADV_GW_MODE_OFF: gw mode disabled */ + BATADV_GW_MODE_OFF, + + /** @BATADV_GW_MODE_CLIENT: send DHCP requests to gw servers */ + BATADV_GW_MODE_CLIENT, + + /** @BATADV_GW_MODE_SERVER: announce itself as gatway server */ + BATADV_GW_MODE_SERVER, +}; + /** * enum batadv_nl_attrs - batman-adv netlink attributes */ @@ -344,6 +359,136 @@ enum batadv_nl_attrs { */ BATADV_ATTR_MCAST_FLAGS_PRIV,
+ /** + * @BATADV_ATTR_VLANID: VLAN id on top of soft interface + */ + BATADV_ATTR_VLANID, + + /** + * @BATADV_ATTR_AGGREGATED_OGMS: whether the batman protocol messages + * of the mesh mesh interface shall be aggregated or not. + */ + BATADV_ATTR_AGGREGATED_OGMS, + + /** + * @BATADV_ATTR_AP_ISOLATION: whether the data traffic going from a + * wireless client to another wireless client will be silently dropped. + */ + BATADV_ATTR_AP_ISOLATION, + + /** + * @BATADV_ATTR_ISOLATION_MARK: the isolation mark which is used to + * classify clients as "isolated" by the Extended Isolation feature. + */ + BATADV_ATTR_ISOLATION_MARK, + + /** + * @BATADV_ATTR_ISOLATION_MASK: the isolation (bit)mask which is used to + * classify clients as "isolated" by the Extended Isolation feature. + */ + BATADV_ATTR_ISOLATION_MASK, + + /** + * @BATADV_ATTR_BONDING: whether the data traffic going through the + * mesh will be sent using multiple interfaces at the same time. + */ + BATADV_ATTR_BONDING, + + /** + * @BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE: whether the bridge loop avoidance + * feature is enabled. This feature detects and avoids loops between + * the mesh and devices bridged with the soft interface + */ + BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE, + + /** + * @BATADV_ATTR_DISTRIBUTED_ARP_TABLE: whether the distributed arp table + * feature is enabled. This feature uses a distributed hash table to + * answer ARP requests without flooding the request through the whole + * mesh. + */ + BATADV_ATTR_DISTRIBUTED_ARP_TABLE, + + /** + * @BATADV_ATTR_FRAGMENTATION: whether the data traffic going through + * the mesh will be fragmented or silently discarded if the packet size + * exceeds the outgoing interface MTU. + */ + BATADV_ATTR_FRAGMENTATION, + + /** + * @BATADV_ATTR_GW_BANDWIDTH_DOWN: defines the download bandwidth which + * is propagated by this node if %BATADV_ATTR_GW_BANDWIDTH_MODE was set + * to 'server'. + */ + BATADV_ATTR_GW_BANDWIDTH_DOWN, + + /** + * @BATADV_ATTR_GW_BANDWIDTH_UP: defines the upload bandwidth which + * is propagated by this node if %BATADV_ATTR_GW_BANDWIDTH_MODE was set + * to 'server'. + */ + BATADV_ATTR_GW_BANDWIDTH_UP, + + /** + * @BATADV_ATTR_GW_MODE: defines the state of the gateway features. + * Possible values are specified in enum batadv_gw_modes + */ + BATADV_ATTR_GW_MODE, + + /** + * @BATADV_ATTR_GW_SEL_CLASS: defines the selection criteria this node + * will use to choose a gateway if gw_mode was set to 'client'. + */ + BATADV_ATTR_GW_SEL_CLASS, + + /** + * @BATADV_ATTR_HOP_PENALTY: defines the penalty which will be applied + * to an originator message's tq-field on every hop. + */ + BATADV_ATTR_HOP_PENALTY, + + /** + * @BATADV_ATTR_LOG_LEVEL: bitmask with to define which debug messages + * should be send to the debug log/trace ring buffer + */ + BATADV_ATTR_LOG_LEVEL, + + /** + * @BATADV_ATTR_MULTICAST_MODE: whether multicast optimizations are + * enabled or disabled. If set to zero then all nodes in the mesh are + * going to use classic flooding for any multicast packet with no + * optimizations. + */ + BATADV_ATTR_MULTICAST_MODE, + + /** + * @BATADV_ATTR_NETWORK_CODING: whether Network Coding (using some magic + * to send fewer wifi packets but still the same content) is enabled or + * not. + */ + BATADV_ATTR_NETWORK_CODING, + + /** + * @BATADV_ATTR_ORIG_INTERVAL: defines the interval in milliseconds in + * which batman sends its protocol messages. + */ + BATADV_ATTR_ORIG_INTERVAL, + + /** + * @BATADV_ATTR_ELP_INTERVAL: defines the interval in milliseconds in + * which batman emits probing packets for neighbor sensing (ELP). + */ + BATADV_ATTR_ELP_INTERVAL, + + /** + * @BATADV_ATTR_THROUGHPUT_OVERRIDE: defines the throughput value to be + * used by B.A.T.M.A.N. V when estimating the link throughput using + * this interface. If the value is set to 0 then batman-adv will try to + * estimate the throughput by itself. + */ + BATADV_ATTR_THROUGHPUT_OVERRIDE, + /* add attributes above here, update the policy in netlink.c */
/** @@ -372,10 +517,14 @@ enum batadv_nl_commands { BATADV_CMD_UNSPEC,
/** - * @BATADV_CMD_GET_MESH_INFO: Query basic information about batman-adv - * device + * @BATADV_CMD_GET_MESH: Get attributes from softif/mesh + */ + BATADV_CMD_GET_MESH, + + /** + * @BATADV_CMD_GET_MESH_INFO: Alias for @BATADV_CMD_GET_MESH */ - BATADV_CMD_GET_MESH_INFO, + BATADV_CMD_GET_MESH_INFO = BATADV_CMD_GET_MESH,
/** * @BATADV_CMD_TP_METER: Start a tp meter session @@ -393,9 +542,15 @@ enum batadv_nl_commands { BATADV_CMD_GET_ROUTING_ALGOS,
/** - * @BATADV_CMD_GET_HARDIFS: Query list of hard interfaces + * @BATADV_CMD_GET_HARDIF: Get attributes from a hardif of the + * current softif */ - BATADV_CMD_GET_HARDIFS, + BATADV_CMD_GET_HARDIF, + + /** + * @BATADV_CMD_GET_HARDIFS: Alias for @BATADV_CMD_GET_HARDIF + */ + BATADV_CMD_GET_HARDIFS = BATADV_CMD_GET_HARDIF,
/** * @BATADV_CMD_GET_TRANSTABLE_LOCAL: Query list of local translations @@ -443,6 +598,29 @@ enum batadv_nl_commands { */ BATADV_CMD_GET_MCAST_FLAGS,
+ /** + * @BATADV_CMD_SET_MESH: Set attributes for softif/mesh + */ + BATADV_CMD_SET_MESH, + + /** + * @BATADV_CMD_SET_HARDIF: Set attributes for hardif of the + * current softif + */ + BATADV_CMD_SET_HARDIF, + + /** + * @BATADV_CMD_GET_VLAN: Get attributes from a VLAN of the + * current softif + */ + BATADV_CMD_GET_VLAN, + + /** + * @BATADV_CMD_SET_VLAN: Set attributes for VLAN of the + * current softif + */ + BATADV_CMD_SET_VLAN, + /* add new commands above here */
/** diff --git a/event.c b/event.c index 8eda269..28a5205 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> @@ -51,6 +52,14 @@ struct event_args { struct timeval tv; };
+static const char *u8_to_boolstr(struct nlattr *attrs) +{ + if (nla_get_u8(attrs)) + return "true"; + else + return "false"; +} + static void event_usage(void) { fprintf(stderr, "Usage: batctl [options] event [parameters]\n"); @@ -87,6 +96,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 +173,203 @@ static void event_parse_tp_meter(struct nlattr **attrs) printf("tp_meter 0x%08x: %s\n", cookie, result_str); }
+static void event_parse_set_mesh(struct nlattr **attrs) +{ + static const int mesh_mandatory[] = { + BATADV_ATTR_MESH_IFINDEX, + BATADV_ATTR_ALGO_NAME, + }; + char meshif_buf[IF_NAMESIZE]; + char *meshif_name; + uint32_t mesh_ifindex; + + /* ignore entry when attributes are missing */ + if (missing_mandatory_attrs(attrs, mesh_mandatory, + ARRAY_SIZE(mesh_mandatory))) + return; + + mesh_ifindex = nla_get_u32(attrs[BATADV_ATTR_MESH_IFINDEX]); + meshif_name = if_indextoname(mesh_ifindex, meshif_buf); + if (!meshif_name) + return; + + printf("%s: set mesh:\n", meshif_name); + + if (attrs[BATADV_ATTR_AGGREGATED_OGMS]) + printf("* aggregated_ogms %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_AGGREGATED_OGMS])); + + if (attrs[BATADV_ATTR_AP_ISOLATION]) + printf("* ap_isolation %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_AP_ISOLATION])); + + if (attrs[BATADV_ATTR_ISOLATION_MARK]) + printf("* isolation_mark 0x%08x\n", + nla_get_u32(attrs[BATADV_ATTR_ISOLATION_MARK])); + + if (attrs[BATADV_ATTR_ISOLATION_MASK]) + printf("* isolation_mask 0x%08x\n", + nla_get_u32(attrs[BATADV_ATTR_ISOLATION_MASK])); + + if (attrs[BATADV_ATTR_BONDING]) + printf("* bonding %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_BONDING])); + + if (attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE]) + printf("* bridge_loop_avoidance %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE])); + + if (attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE]) + printf("* distributed_arp_table %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE])); + + if (attrs[BATADV_ATTR_FRAGMENTATION]) + printf("* fragmentation %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_FRAGMENTATION])); + + if (attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]) { + uint32_t val; + + val = nla_get_u32(attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]); + printf("* gw_bandwidth_down %u.%01u MBit/s\n", val / 10, + val % 10); + } + + if (attrs[BATADV_ATTR_GW_BANDWIDTH_UP]) { + uint32_t val; + + val = nla_get_u32(attrs[BATADV_ATTR_GW_BANDWIDTH_UP]); + printf("* gw_bandwidth_up %u.%01u MBit/s\n", val / 10, + val % 10); + } + + if (attrs[BATADV_ATTR_GW_MODE]) { + uint8_t val = nla_get_u8(attrs[BATADV_ATTR_GW_MODE]); + const char *valstr; + + switch (val) { + case BATADV_GW_MODE_OFF: + valstr = "off"; + break; + case BATADV_GW_MODE_CLIENT: + valstr = "client"; + break; + case BATADV_GW_MODE_SERVER: + valstr = "server"; + break; + default: + valstr = "unknown"; + break; + } + + printf("* gw_mode %s\n", valstr); + } + + if (attrs[BATADV_ATTR_GW_SEL_CLASS]) { + uint32_t val = nla_get_u32(attrs[BATADV_ATTR_GW_SEL_CLASS]); + const char *algo = nla_data(attrs[BATADV_ATTR_ALGO_NAME]); + + if (strcmp(algo, "BATMAN_V") == 0) + printf("* gw_sel_class %u.%01u MBit/s\n", val / 10, + val % 10); + else + printf("* gw_sel_class %u\n", val); + } + + if (attrs[BATADV_ATTR_HOP_PENALTY]) + printf("* hop_penalty %u\n", + nla_get_u8(attrs[BATADV_ATTR_HOP_PENALTY])); + + if (attrs[BATADV_ATTR_LOG_LEVEL]) + printf("* log_level 0x%08x\n", + nla_get_u32(attrs[BATADV_ATTR_LOG_LEVEL])); + + if (attrs[BATADV_ATTR_MULTICAST_MODE]) + printf("* multicast_mode %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_MULTICAST_MODE])); + + if (attrs[BATADV_ATTR_NETWORK_CODING]) + printf("* network_coding %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_NETWORK_CODING])); + + if (attrs[BATADV_ATTR_ORIG_INTERVAL]) + printf("* orig_interval %u ms\n", + nla_get_u32(attrs[BATADV_ATTR_ORIG_INTERVAL])); +} + +static void event_parse_set_hardif(struct nlattr **attrs) +{ + static const int hardif_mandatory[] = { + BATADV_ATTR_MESH_IFINDEX, + BATADV_ATTR_HARD_IFINDEX, + }; + char meshif_buf[IF_NAMESIZE]; + char hardif_buf[IF_NAMESIZE]; + char *meshif_name; + char *hardif_name; + uint32_t hardif_ifindex; + uint32_t mesh_ifindex; + + /* ignore entry when attributes are missing */ + if (missing_mandatory_attrs(attrs, hardif_mandatory, + ARRAY_SIZE(hardif_mandatory))) + return; + + mesh_ifindex = nla_get_u32(attrs[BATADV_ATTR_MESH_IFINDEX]); + meshif_name = if_indextoname(mesh_ifindex, meshif_buf); + if (!meshif_name) + return; + + hardif_ifindex = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); + hardif_name = if_indextoname(hardif_ifindex, hardif_buf); + if (!hardif_name) + return; + + printf("%s (%s): set hardif:\n", meshif_name, hardif_name); + + if (attrs[BATADV_ATTR_ELP_INTERVAL]) + printf("* elp_interval %u ms\n", + nla_get_u32(attrs[BATADV_ATTR_ELP_INTERVAL])); + + if (attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]) { + uint32_t val; + + val = nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]); + printf("* throughput_override %u.%01u MBit/s\n", val / 10, + val % 10); + } +} + +static void event_parse_set_vlan(struct nlattr **attrs) +{ + static const int vlan_mandatory[] = { + BATADV_ATTR_MESH_IFINDEX, + BATADV_ATTR_VLANID, + }; + char meshif_buf[IF_NAMESIZE]; + char *meshif_name; + uint32_t mesh_ifindex; + uint16_t vid; + + /* ignore entry when attributes are missing */ + if (missing_mandatory_attrs(attrs, vlan_mandatory, + ARRAY_SIZE(vlan_mandatory))) + return; + + mesh_ifindex = nla_get_u32(attrs[BATADV_ATTR_MESH_IFINDEX]); + meshif_name = if_indextoname(mesh_ifindex, meshif_buf); + if (!meshif_name) + return; + + vid = nla_get_u16(attrs[BATADV_ATTR_VLANID]); + + printf("%s (vid %u): set vlan:\n", meshif_name, vid); + + if (attrs[BATADV_ATTR_AP_ISOLATION]) + printf("* ap_isolation %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_AP_ISOLATION])); +} + static unsigned long long get_timestamp(struct event_args *event_args) { unsigned long long prevtime = 0; @@ -190,6 +415,15 @@ 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_MESH: + event_parse_set_mesh(attrs); + break; + case BATADV_CMD_SET_HARDIF: + event_parse_set_hardif(attrs); + break; + case BATADV_CMD_SET_VLAN: + event_parse_set_vlan(attrs); + break; default: printf("Received unknown event %u\n", ghdr->cmd); break; diff --git a/netlink.c b/netlink.c index 5285759..1829544 100644 --- a/netlink.c +++ b/netlink.c @@ -107,6 +107,26 @@ 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_AGGREGATED_OGMS] = { .type = NLA_U8 }, + [BATADV_ATTR_AP_ISOLATION] = { .type = NLA_U8 }, + [BATADV_ATTR_ISOLATION_MARK] = { .type = NLA_U32 }, + [BATADV_ATTR_ISOLATION_MASK] = { .type = NLA_U32 }, + [BATADV_ATTR_BONDING] = { .type = NLA_U8 }, + [BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE] = { .type = NLA_U8 }, + [BATADV_ATTR_DISTRIBUTED_ARP_TABLE] = { .type = NLA_U8 }, + [BATADV_ATTR_FRAGMENTATION] = { .type = NLA_U8 }, + [BATADV_ATTR_GW_BANDWIDTH_DOWN] = { .type = NLA_U32 }, + [BATADV_ATTR_GW_BANDWIDTH_UP] = { .type = NLA_U32 }, + [BATADV_ATTR_GW_MODE] = { .type = NLA_U8 }, + [BATADV_ATTR_GW_SEL_CLASS] = { .type = NLA_U32 }, + [BATADV_ATTR_HOP_PENALTY] = { .type = NLA_U8 }, + [BATADV_ATTR_LOG_LEVEL] = { .type = NLA_U32 }, + [BATADV_ATTR_MULTICAST_MODE] = { .type = NLA_U8 }, + [BATADV_ATTR_NETWORK_CODING] = { .type = NLA_U8 }, + [BATADV_ATTR_ORIG_INTERVAL] = { .type = NLA_U32 }, + [BATADV_ATTR_ELP_INTERVAL] = { .type = NLA_U32 }, + [BATADV_ATTR_THROUGHPUT_OVERRIDE] = { .type = NLA_U32 }, };
int netlink_create(struct state *state)
The buffer size is limited by IF_NAMESIZE and can easily be stored on the stack. This will also make it easier to store this as part of the the state of batctl.
Signed-off-by: Sven Eckelmann sven@narfation.org --- functions.c | 23 ++++++----------------- functions.h | 2 +- sys.c | 6 +++--- 3 files changed, 10 insertions(+), 21 deletions(-)
diff --git a/functions.c b/functions.c index bdede8b..ecfd202 100644 --- a/functions.c +++ b/functions.c @@ -830,10 +830,6 @@ static int vlan_get_link_parse(struct nl_msg *msg, void *arg)
/* get parent link name */ idx = *(int *)nla_data(tb[IFLA_LINK]); - free(nl_arg->iface); - nl_arg->iface = malloc(IFNAMSIZ + 1); - if (!nl_arg->iface) - goto err;
if (!if_indextoname(idx, nl_arg->iface)) goto err; @@ -851,12 +847,12 @@ static int vlan_get_link_parse(struct nl_msg *msg, void *arg) /** * vlan_get_link - convert a VLAN interface into its parent one * @ifname: the interface to convert - * @parent: buffer where the parent interface name will be written (allocated by - * this function) + * @parent: buffer where the parent interface name will be written + * (minimum IF_NAMESIZE) * * Returns the vlan identifier on success or -1 on error */ -int vlan_get_link(const char *ifname, char **parent) +int vlan_get_link(const char *ifname, char *parent) { struct nl_sock *sock; int ret; @@ -866,12 +862,10 @@ int vlan_get_link(const char *ifname, char **parent) }; struct nl_cb *cb = NULL; struct vlan_get_link_nl_arg arg = { - .iface = NULL, + .iface = parent, .vid = -1, };
- *parent = NULL; - sock = nl_socket_alloc(); if (!sock) goto err; @@ -894,8 +888,6 @@ int vlan_get_link(const char *ifname, char **parent) if (ret < 0) goto err;
- *parent = arg.iface; - err: if (cb) nl_cb_put(cb); @@ -1029,13 +1021,13 @@ int netlink_simple_request(struct nl_msg *msg)
int check_mesh_iface(char *mesh_iface) { - char *base_dev = NULL; char path_buff[PATH_BUFF_LEN]; + char base_dev[IF_NAMESIZE]; int ret = -1, vid; DIR *dir;
/* use the parent interface if this is a VLAN */ - vid = vlan_get_link(mesh_iface, &base_dev); + vid = vlan_get_link(mesh_iface, base_dev); if (vid >= 0) snprintf(path_buff, PATH_BUFF_LEN, SYS_VLAN_PATH, base_dev, vid); else @@ -1050,9 +1042,6 @@ int check_mesh_iface(char *mesh_iface)
ret = 0; out: - if (base_dev) - free(base_dev); - return ret; }
diff --git a/functions.h b/functions.h index c16ba2e..2680e6d 100644 --- a/functions.h +++ b/functions.h @@ -48,7 +48,7 @@ int write_file(const char *dir, const char *fname, const char *arg1, struct ether_addr *translate_mac(const char *mesh_iface, const struct ether_addr *mac); struct ether_addr *resolve_mac(const char *asc); -int vlan_get_link(const char *ifname, char **parent);\ +int vlan_get_link(const char *ifname, char *parent); int query_rtnl_link(int ifindex, nl_recvmsg_msg_cb_t func, void *arg); int netlink_simple_request(struct nl_msg *msg); int check_mesh_iface(char *mesh_iface); diff --git a/sys.c b/sys.c index 6b98ac4..5c54f08 100644 --- a/sys.c +++ b/sys.c @@ -67,7 +67,8 @@ int handle_sys_setting(struct state *state, int argc, char **argv) { struct settings_data *settings = state->cmd->arg; int vid, optchar, res = EXIT_FAILURE; - char *path_buff, *base_dev = NULL; + char base_dev[IF_NAMESIZE]; + char *path_buff; const char **ptr;
while ((optchar = getopt(argc, argv, "h")) != -1) { @@ -93,7 +94,7 @@ int handle_sys_setting(struct state *state, int argc, char **argv) /* if the specified interface is a VLAN then change the path to point * to the proper "vlan%{vid}" subfolder in the sysfs tree. */ - vid = vlan_get_link(state->mesh_iface, &base_dev); + vid = vlan_get_link(state->mesh_iface, base_dev); if (vid >= 0) snprintf(path_buff, PATH_BUFF_LEN, SYS_VLAN_PATH, base_dev, vid);
@@ -133,6 +134,5 @@ int handle_sys_setting(struct state *state, int argc, char **argv)
out: free(path_buff); - free(base_dev); return res; }
The way batctl is implementing support for VLANs is rather suboptimal. The program has to guess whether it is started with an batadv or vlan interface as argument.
Instead of distributing this over the whole program, do it on startup and already retrieve the required mesh interface index and vid before the rest of the program runs.
Signed-off-by: Sven Eckelmann sven@narfation.org --- functions.c | 34 ++++++++++++++++++++++++++-------- functions.h | 6 ++++-- gateways.c | 10 ++-------- main.c | 10 ++++++---- main.h | 6 +++++- mcast_flags.c | 10 ++-------- netlink.c | 12 ++---------- originators.c | 10 ++-------- sys.c | 14 +++++++------- 9 files changed, 56 insertions(+), 56 deletions(-)
diff --git a/functions.c b/functions.c index ecfd202..600c29a 100644 --- a/functions.c +++ b/functions.c @@ -852,7 +852,7 @@ static int vlan_get_link_parse(struct nl_msg *msg, void *arg) * * Returns the vlan identifier on success or -1 on error */ -int vlan_get_link(const char *ifname, char *parent) +static int vlan_get_link(const char *ifname, char *parent) { struct nl_sock *sock; int ret; @@ -1019,19 +1019,33 @@ int netlink_simple_request(struct nl_msg *msg) return err; }
-int check_mesh_iface(char *mesh_iface) +int translate_mesh_iface(struct state *state) +{ + state->vid = vlan_get_link(state->arg_iface, state->mesh_iface); + if (state->vid < 0) { + /* if there is no iface then the argument must be the + * mesh interface + */ + snprintf(state->mesh_iface, sizeof(state->mesh_iface), "%s", + state->arg_iface); + } + + return 0; +} + +int check_mesh_iface(struct state *state) { char path_buff[PATH_BUFF_LEN]; - char base_dev[IF_NAMESIZE]; - int ret = -1, vid; + int ret = -1; DIR *dir;
/* use the parent interface if this is a VLAN */ - vid = vlan_get_link(mesh_iface, base_dev); - if (vid >= 0) - snprintf(path_buff, PATH_BUFF_LEN, SYS_VLAN_PATH, base_dev, vid); + if (state->vid >= 0) + snprintf(path_buff, PATH_BUFF_LEN, SYS_VLAN_PATH, + state->mesh_iface, state->vid); else - snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, mesh_iface); + snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, + state->mesh_iface);
/* try to open the mesh sys directory */ dir = opendir(path_buff); @@ -1040,6 +1054,10 @@ int check_mesh_iface(char *mesh_iface)
closedir(dir);
+ state->mesh_ifindex = if_nametoindex(state->mesh_iface); + if (state->mesh_ifindex == 0) + goto out; + ret = 0; out: return ret; diff --git a/functions.h b/functions.h index 2680e6d..ea3c307 100644 --- a/functions.h +++ b/functions.h @@ -34,6 +34,8 @@
#define PATH_BUFF_LEN 400
+struct state; + /* return time delta from start to end in milliseconds */ void start_timer(void); double end_timer(void); @@ -48,10 +50,10 @@ int write_file(const char *dir, const char *fname, const char *arg1, struct ether_addr *translate_mac(const char *mesh_iface, const struct ether_addr *mac); struct ether_addr *resolve_mac(const char *asc); -int vlan_get_link(const char *ifname, char *parent); int query_rtnl_link(int ifindex, nl_recvmsg_msg_cb_t func, void *arg); int netlink_simple_request(struct nl_msg *msg); -int check_mesh_iface(char *mesh_iface); +int translate_mesh_iface(struct state *state); +int check_mesh_iface(struct state *state); int check_mesh_iface_ownership(char *mesh_iface, char *hard_iface);
void get_random_bytes(void *buf, size_t buflen); diff --git a/gateways.c b/gateways.c index ff7693f..5beddc7 100644 --- a/gateways.c +++ b/gateways.c @@ -133,17 +133,11 @@ static int netlink_print_gateways(struct state *state, char *orig_iface, { char *header = NULL; char *info_header; - int ifindex; - - ifindex = if_nametoindex(state->mesh_iface); - if (!ifindex) { - fprintf(stderr, "Interface %s is unknown\n", state->mesh_iface); - return -ENODEV; - }
/* only parse routing algorithm name */ last_err = -EINVAL; - info_header = netlink_get_info(ifindex, BATADV_CMD_GET_ORIGINATORS, NULL); + info_header = netlink_get_info(state->mesh_ifindex, + BATADV_CMD_GET_ORIGINATORS, NULL); free(info_header);
if (strlen(algo_name_buf) == 0) diff --git a/main.c b/main.c index ab7da45..37a2b5a 100644 --- a/main.c +++ b/main.c @@ -125,7 +125,7 @@ int main(int argc, char **argv) { const struct command *cmd; struct state state = { - .mesh_iface = mesh_dfl_iface, + .arg_iface = mesh_dfl_iface, .cmd = NULL, }; int opt; @@ -138,13 +138,13 @@ int main(int argc, char **argv) exit(EXIT_SUCCESS); break; case 'm': - if (state.mesh_iface != mesh_dfl_iface) { + if (state.arg_iface != mesh_dfl_iface) { fprintf(stderr, "Error - multiple mesh interfaces specified\n"); goto err; }
- state.mesh_iface = argv[2]; + state.arg_iface = argv[2]; break; case 'v': version(); @@ -173,8 +173,10 @@ int main(int argc, char **argv)
state.cmd = cmd;
+ translate_mesh_iface(&state); + if (cmd->flags & COMMAND_FLAG_MESH_IFACE && - check_mesh_iface(state.mesh_iface) < 0) { + check_mesh_iface(&state) < 0) { fprintf(stderr, "Error - interface %s is not present or not a batman-adv interface\n", state.mesh_iface); diff --git a/main.h b/main.h index 276a018..274fae5 100644 --- a/main.h +++ b/main.h @@ -25,6 +25,7 @@
#include <stdint.h>
+#include <net/if.h> #include <netlink/genl/ctrl.h> #include <netlink/genl/genl.h> #include <netlink/netlink.h> @@ -74,7 +75,10 @@ enum command_type { };
struct state { - char *mesh_iface; + char *arg_iface; + char mesh_iface[IF_NAMESIZE]; + unsigned int mesh_ifindex; + int vid; const struct command *cmd;
struct nl_sock *sock; diff --git a/mcast_flags.c b/mcast_flags.c index 0dc4227..eb9734e 100644 --- a/mcast_flags.c +++ b/mcast_flags.c @@ -113,17 +113,11 @@ static int netlink_print_mcast_flags(struct state *state, char *orig_iface, char *info_header; char *header; bool bridged; - int ifindex; int ret;
- ifindex = if_nametoindex(state->mesh_iface); - if (!ifindex) { - fprintf(stderr, "Interface %s is unknown\n", state->mesh_iface); - return -ENODEV; - } - /* only parse own multicast flags */ - info_header = netlink_get_info(ifindex, BATADV_CMD_GET_MCAST_FLAGS, NULL); + info_header = netlink_get_info(state->mesh_ifindex, + BATADV_CMD_GET_MCAST_FLAGS, NULL); free(info_header);
if (mcast_flags == -EOPNOTSUPP || mcast_flags_priv == -EOPNOTSUPP) diff --git a/netlink.c b/netlink.c index 1829544..b0d57b1 100644 --- a/netlink.c +++ b/netlink.c @@ -443,20 +443,12 @@ int netlink_print_common(struct state *state, char *orig_iface, int read_opt, }; int hardifindex = 0; struct nl_msg *msg; - int ifindex;
if (!state->sock) { last_err = -EOPNOTSUPP; return last_err; }
- ifindex = if_nametoindex(state->mesh_iface); - if (!ifindex) { - fprintf(stderr, "Interface %s is unknown\n", state->mesh_iface); - last_err = -ENODEV; - return last_err; - } - if (orig_iface) { hardifindex = if_nametoindex(orig_iface); if (!hardifindex) { @@ -479,7 +471,7 @@ int netlink_print_common(struct state *state, char *orig_iface, int read_opt, printf("\033[2J\033[0;0f");
if (!(read_opt & SKIP_HEADER)) - opts.remaining_header = netlink_get_info(ifindex, + opts.remaining_header = netlink_get_info(state->mesh_ifindex, nl_cmd, header);
@@ -490,7 +482,7 @@ int netlink_print_common(struct state *state, char *orig_iface, int read_opt, genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, state->batadv_family, 0, NLM_F_DUMP, nl_cmd, 1);
- nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex); + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, state->mesh_ifindex); if (hardifindex) nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, hardifindex); diff --git a/originators.c b/originators.c index c29300a..3c13c66 100644 --- a/originators.c +++ b/originators.c @@ -185,17 +185,11 @@ static int netlink_print_originators(struct state *state, char *orig_iface, { char *header = NULL; char *info_header; - int ifindex; - - ifindex = if_nametoindex(state->mesh_iface); - if (!ifindex) { - fprintf(stderr, "Interface %s is unknown\n", state->mesh_iface); - return -ENODEV; - }
/* only parse routing algorithm name */ last_err = -EINVAL; - info_header = netlink_get_info(ifindex, BATADV_CMD_GET_ORIGINATORS, NULL); + info_header = netlink_get_info(state->mesh_ifindex, + BATADV_CMD_GET_ORIGINATORS, NULL); free(info_header);
if (strlen(algo_name_buf) == 0) diff --git a/sys.c b/sys.c index 5c54f08..be20be7 100644 --- a/sys.c +++ b/sys.c @@ -66,8 +66,7 @@ static void settings_usage(struct state *state) int handle_sys_setting(struct state *state, int argc, char **argv) { struct settings_data *settings = state->cmd->arg; - int vid, optchar, res = EXIT_FAILURE; - char base_dev[IF_NAMESIZE]; + int optchar, res = EXIT_FAILURE; char *path_buff; const char **ptr;
@@ -89,14 +88,15 @@ int handle_sys_setting(struct state *state, int argc, char **argv) return EXIT_FAILURE; }
- snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, state->mesh_iface); - /* if the specified interface is a VLAN then change the path to point * to the proper "vlan%{vid}" subfolder in the sysfs tree. */ - vid = vlan_get_link(state->mesh_iface, base_dev); - if (vid >= 0) - snprintf(path_buff, PATH_BUFF_LEN, SYS_VLAN_PATH, base_dev, vid); + if (state->vid >= 0) + snprintf(path_buff, PATH_BUFF_LEN, SYS_VLAN_PATH, + state->mesh_iface, state->vid); + else + snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, + state->mesh_iface);
if (argc == 1) { res = read_file(path_buff, settings->sysfs_name,
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands were also reimplemented via generic netlink.
To still support older batman-adv versions, the old sysfs infrastructure is still used in case that the generic netlink command returned an error.
Signed-off-by: Sven Eckelmann sven@narfation.org --- aggregation.c | 45 ++++- ap_isolation.c | 67 ++++++- bonding.c | 45 ++++- bridge_loop_avoidance.c | 46 ++++- distributed_arp_table.c | 46 ++++- fragmentation.c | 45 ++++- functions.c | 109 +++++++++++ functions.h | 18 ++ gw_mode.c | 415 +++++++++++++++++++++++++++++++--------- isolation_mark.c | 123 +++++++++++- loglevel.c | 138 ++++++++++--- multicast_mode.c | 45 ++++- netlink.c | 76 ++++++++ netlink.h | 2 + network_coding.c | 45 ++++- orig_interval.c | 84 +++++++- routing_algo.c | 1 - sys.c | 204 ++++++++++++++++---- sys.h | 26 ++- 19 files changed, 1400 insertions(+), 180 deletions(-)
diff --git a/aggregation.c b/aggregation.c index 57c1dbb..673e0ca 100644 --- a/aggregation.c +++ b/aggregation.c @@ -21,13 +21,54 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data aggregated_ogms; + +static int print_aggregated_ogms(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, BATADV_ATTR_AGGREGATED_OGMS); +} + +static int get_aggregated_ogms(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_aggregated_ogms); +} + +static int set_attrs_aggregated_ogms(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_AGGREGATED_OGMS, data->val); + + return 0; +} + +static int set_aggregated_ogms(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_aggregated_ogms, NULL); +} + static struct settings_data batctl_settings_aggregation = { .sysfs_name = "aggregated_ogms", - .params = sysfs_param_enable, + .data = &aggregated_ogms, + .parse = parse_simple_boolean, + .netlink_get = get_aggregated_ogms, + .netlink_set = set_aggregated_ogms, };
COMMAND_NAMED(SUBCOMMAND, aggregation, "ag", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_aggregation, + COMMAND_FLAG_MESH_IFACE| COMMAND_FLAG_NETLINK, + &batctl_settings_aggregation, "[0|1] \tdisplay or modify aggregation setting"); diff --git a/ap_isolation.c b/ap_isolation.c index 2d16c68..4df46e5 100644 --- a/ap_isolation.c +++ b/ap_isolation.c @@ -21,13 +21,76 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data ap_isolation; + +static int print_ap_isolation(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, BATADV_ATTR_AP_ISOLATION); +} + +static int get_attrs_ap_isolation(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + + if (state->vid >= 0) + nla_put_u16(msg, BATADV_ATTR_VLANID, state->vid); + + return 0; +} + +static int get_ap_isolation(struct state *state) +{ + enum batadv_nl_commands nl_cmd = BATADV_CMD_SET_MESH; + + if (state->vid >= 0) + nl_cmd = BATADV_CMD_GET_VLAN; + + return sys_simple_nlquery(state, nl_cmd, get_attrs_ap_isolation, + print_ap_isolation); +} + +static int set_attrs_ap_isolation(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_AP_ISOLATION, data->val); + + if (state->vid >= 0) + nla_put_u16(msg, BATADV_ATTR_VLANID, state->vid); + + return 0; +} + +static int set_ap_isolation(struct state *state) +{ + enum batadv_nl_commands nl_cmd = BATADV_CMD_SET_MESH; + + if (state->vid >= 0) + nl_cmd = BATADV_CMD_SET_VLAN; + + return sys_simple_nlquery(state, nl_cmd, set_attrs_ap_isolation, NULL); +} + static struct settings_data batctl_settings_ap_isolation = { .sysfs_name = "ap_isolation", - .params = sysfs_param_enable, + .data = &ap_isolation, + .parse = parse_simple_boolean, + .netlink_get = get_ap_isolation, + .netlink_set = set_ap_isolation, };
COMMAND_NAMED(SUBCOMMAND, ap_isolation, "ap", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_ap_isolation, + COMMAND_FLAG_MESH_IFACE| COMMAND_FLAG_NETLINK, + &batctl_settings_ap_isolation, "[0|1] \tdisplay or modify ap_isolation setting"); diff --git a/bonding.c b/bonding.c index f7105c9..591debd 100644 --- a/bonding.c +++ b/bonding.c @@ -21,13 +21,54 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data bonding; + +static int print_bonding(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, BATADV_ATTR_BONDING); +} + +static int get_bonding(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_bonding); +} + +static int set_attrs_bonding(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_BONDING, data->val); + + return 0; +} + +static int set_bonding(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_bonding, NULL); +} + static struct settings_data batctl_settings_bonding = { .sysfs_name = "bonding", - .params = sysfs_param_enable, + .data = &bonding, + .parse = parse_simple_boolean, + .netlink_get = get_bonding, + .netlink_set = set_bonding, };
COMMAND_NAMED(SUBCOMMAND, bonding, "b", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_bonding, + COMMAND_FLAG_MESH_IFACE| COMMAND_FLAG_NETLINK, + &batctl_settings_bonding, "[0|1] \tdisplay or modify bonding setting"); diff --git a/bridge_loop_avoidance.c b/bridge_loop_avoidance.c index 0db49f2..948a6f1 100644 --- a/bridge_loop_avoidance.c +++ b/bridge_loop_avoidance.c @@ -21,13 +21,55 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data bridge_loop_avoidance; + +static int print_bridge_loop_avoidance(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, + BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE); +} + +static int get_bridge_loop_avoidance(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_bridge_loop_avoidance); +} + +static int set_attrs_bridge_loop_avoidance(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE, data->val); + + return 0; +} + +static int set_bridge_loop_avoidance(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_bridge_loop_avoidance, NULL); +} + static struct settings_data batctl_settings_bridge_loop_avoidance = { .sysfs_name = SYS_BLA, - .params = sysfs_param_enable, + .data = &bridge_loop_avoidance, + .parse = parse_simple_boolean, + .netlink_get = get_bridge_loop_avoidance, + .netlink_set = set_bridge_loop_avoidance, };
COMMAND_NAMED(SUBCOMMAND, bridge_loop_avoidance, "bl", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_bridge_loop_avoidance, + COMMAND_FLAG_MESH_IFACE| COMMAND_FLAG_NETLINK, + &batctl_settings_bridge_loop_avoidance, "[0|1] \tdisplay or modify bridge_loop_avoidance setting"); diff --git a/distributed_arp_table.c b/distributed_arp_table.c index ba6e5b7..ee09518 100644 --- a/distributed_arp_table.c +++ b/distributed_arp_table.c @@ -21,13 +21,55 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data distributed_arp_table; + +static int print_distributed_arp_table(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, + BATADV_ATTR_DISTRIBUTED_ARP_TABLE); +} + +static int get_distributed_arp_table(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_distributed_arp_table); +} + +static int set_attrs_distributed_arp_table(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_DISTRIBUTED_ARP_TABLE, data->val); + + return 0; +} + +static int set_distributed_arp_table(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_distributed_arp_table, NULL); +} + static struct settings_data batctl_settings_distributed_arp_table = { .sysfs_name = SYS_DAT, - .params = sysfs_param_enable, + .data = &distributed_arp_table, + .parse = parse_simple_boolean, + .netlink_get = get_distributed_arp_table, + .netlink_set = set_distributed_arp_table, };
COMMAND_NAMED(SUBCOMMAND, distributed_arp_table, "dat", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_distributed_arp_table, + COMMAND_FLAG_MESH_IFACE| COMMAND_FLAG_NETLINK, + &batctl_settings_distributed_arp_table, "[0|1] \tdisplay or modify distributed_arp_table setting"); diff --git a/fragmentation.c b/fragmentation.c index e159bdd..2dee1b8 100644 --- a/fragmentation.c +++ b/fragmentation.c @@ -21,13 +21,54 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data fragmentation; + +static int print_fragmentation(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, BATADV_ATTR_FRAGMENTATION); +} + +static int get_fragmentation(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_fragmentation); +} + +static int set_attrs_fragmentation(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_FRAGMENTATION, data->val); + + return 0; +} + +static int set_fragmentation(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_fragmentation, NULL); +} + static struct settings_data batctl_settings_fragmentation = { .sysfs_name = "fragmentation", - .params = sysfs_param_enable, + .data = &fragmentation, + .parse = parse_simple_boolean, + .netlink_get = get_fragmentation, + .netlink_set = set_fragmentation, };
COMMAND_NAMED(SUBCOMMAND, fragmentation, "f", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_fragmentation, + COMMAND_FLAG_MESH_IFACE| COMMAND_FLAG_NETLINK, + &batctl_settings_fragmentation, "[0|1] \tdisplay or modify fragmentation setting"); diff --git a/functions.c b/functions.c index 600c29a..bb6dc31 100644 --- a/functions.c +++ b/functions.c @@ -499,6 +499,44 @@ struct ether_addr *translate_mac(const char *mesh_iface, return mac_result; }
+int get_algoname(const char *mesh_iface, char *algoname, size_t algoname_len) +{ + char *path_buff; + int ret; + + ret = get_algoname_netlink(mesh_iface, algoname, algoname_len); + if (ret != -EOPNOTSUPP) + return ret; + + path_buff = malloc(PATH_BUFF_LEN); + if (!path_buff) { + fprintf(stderr, "Error - could not allocate path buffer: out of memory ?\n"); + return -ENOMEM; + } + + snprintf(path_buff, PATH_BUFF_LEN, SYS_ROUTING_ALGO_FMT, mesh_iface); + ret = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0, 0); + if (ret != EXIT_SUCCESS) { + ret = -ENOENT; + goto free_path_buf; + } + + if (line_ptr[strlen(line_ptr) - 1] == '\n') + line_ptr[strlen(line_ptr) - 1] = '\0'; + + strncpy(algoname, line_ptr, algoname_len); + if (algoname_len > 0) + algoname[algoname_len - 1] = '\0'; + +free_path_buf: + free(path_buff); + + free(line_ptr); + line_ptr = NULL; + + return ret; +} + static int resolve_l3addr(int ai_family, const char *asc, void *l3addr) { int ret; @@ -1162,3 +1200,74 @@ void check_root_or_die(const char *cmd) exit(EXIT_FAILURE); } } + +int parse_bool(const char *val, bool *res) +{ + if (strcasecmp(val, "0") == 0 || + strcasecmp(val, "disable") == 0 || + strcasecmp(val, "disabled") == 0) { + *res = false; + return 0; + } else if (strcasecmp(val, "1") == 0 || + strcasecmp(val, "enable") == 0 || + strcasecmp(val, "enabled") == 0) { + *res = true; + return 0; + } + + return -EINVAL; +} + +bool parse_throughput(char *buff, const char *description, uint32_t *throughput) +{ + enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT; + uint64_t lthroughput; + char *tmp_ptr; + char *endptr; + + if (strlen(buff) > 4) { + tmp_ptr = buff + strlen(buff) - 4; + + if (strncasecmp(tmp_ptr, "mbit", 4) == 0) + bw_unit_type = BATADV_BW_UNIT_MBIT; + + if (strncasecmp(tmp_ptr, "kbit", 4) == 0 || + bw_unit_type == BATADV_BW_UNIT_MBIT) + *tmp_ptr = '\0'; + } + + lthroughput = strtoull(buff, &endptr, 10); + if (!endptr || *endptr != '\0') { + fprintf(stderr, "Invalid throughput speed for %s: %s\n", + description, buff); + return false; + } + + switch (bw_unit_type) { + case BATADV_BW_UNIT_MBIT: + /* prevent overflow */ + if (UINT64_MAX / 10 < lthroughput) { + fprintf(stderr, + "Throughput speed for %s too large: %s\n", + description, buff); + return false; + } + + lthroughput *= 10; + break; + case BATADV_BW_UNIT_KBIT: + default: + lthroughput = lthroughput / 100; + break; + } + + if (lthroughput > UINT32_MAX) { + fprintf(stderr, "Throughput speed for %s too large: %s\n", + description, buff); + return false; + } + + *throughput = lthroughput; + + return true; +} diff --git a/functions.h b/functions.h index ea3c307..0331c8b 100644 --- a/functions.h +++ b/functions.h @@ -26,9 +26,22 @@ #include <net/ethernet.h> #include <netlink/netlink.h> #include <netlink/handlers.h> +#include <stdbool.h> #include <stddef.h> +#include <stdint.h>
+/** + * enum batadv_bandwidth_units - bandwidth unit types + */ +enum batadv_bandwidth_units { + /** @BATADV_BW_UNIT_KBIT: unit type kbit */ + BATADV_BW_UNIT_KBIT, + + /** @BATADV_BW_UNIT_MBIT: unit type mbit */ + BATADV_BW_UNIT_MBIT, +}; + #define ETH_STR_LEN 17 #define BATMAN_ADV_TAG "batman-adv:"
@@ -53,12 +66,17 @@ struct ether_addr *resolve_mac(const char *asc); int query_rtnl_link(int ifindex, nl_recvmsg_msg_cb_t func, void *arg); int netlink_simple_request(struct nl_msg *msg); int translate_mesh_iface(struct state *state); +int get_algoname(const char *mesh_iface, char *algoname, size_t algoname_len); int check_mesh_iface(struct state *state); int check_mesh_iface_ownership(char *mesh_iface, char *hard_iface);
void get_random_bytes(void *buf, size_t buflen); void check_root_or_die(const char *cmd);
+int parse_bool(const char *val, bool *res); +bool parse_throughput(char *buff, const char *description, + uint32_t *throughput); + extern char *line_ptr;
enum { diff --git a/gw_mode.c b/gw_mode.c index 4093f89..5b7d92b 100644 --- a/gw_mode.c +++ b/gw_mode.c @@ -20,23 +20,32 @@ * License-Filename: LICENSES/preferred/GPL-2.0 */
+#include <errno.h> #include <getopt.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
+#include "batman_adv.h" #include "functions.h" +#include "main.h" +#include "netlink.h" #include "sys.h"
#define SYS_GW_MODE "gw_mode" #define SYS_GW_SEL "gw_sel_class" #define SYS_GW_BW "gw_bandwidth"
-enum gw_modes { - GW_MODE_OFF, - GW_MODE_CLIENT, - GW_MODE_SERVER, -}; +static struct gw_data { + uint8_t bandwidth_down_found:1; + uint8_t bandwidth_up_found:1; + uint8_t sel_class_found:1; + uint8_t mode; + uint32_t bandwidth_down; + uint32_t bandwidth_up; + uint32_t sel_class; +} gw_globals;
static void gw_mode_usage(void) { @@ -45,127 +54,357 @@ static void gw_mode_usage(void) fprintf(stderr, " \t -h print this help\n"); }
-static int gw_mode(struct state *state, int argc, char **argv) +static bool is_throughput_select_class(struct state *state) { - int optchar, res = EXIT_FAILURE; - char *path_buff, gw_mode; - const char **ptr; + char algoname[32]; + int ret;
- while ((optchar = getopt(argc, argv, "h")) != -1) { - switch (optchar) { - case 'h': - gw_mode_usage(); - return EXIT_SUCCESS; - default: - gw_mode_usage(); - return EXIT_FAILURE; - } + ret = get_algoname(state->mesh_iface, algoname, sizeof(algoname)); + + /* no algo name -> assume that it is a pre-B.A.T.M.A.N. V version */ + if (ret < 0) + return false; + + if (strcmp(algoname, "BATMAN_V") == 0) + return true; + + return false; +} +static int parse_gw_limit(char *buff) +{ + char *slash_ptr; + bool ret; + + slash_ptr = strchr(buff, '/'); + if (slash_ptr) + *slash_ptr = 0; + + ret = parse_throughput(buff, "download gateway speed", + &gw_globals.bandwidth_down); + if (!ret) + return -EINVAL; + + gw_globals.bandwidth_down_found = 1; + + /* we also got some upload info */ + if (slash_ptr) { + ret = parse_throughput(slash_ptr + 1, "upload gateway speed", + &gw_globals.bandwidth_up); + if (!ret) + return -EINVAL; + + gw_globals.bandwidth_up_found = 1; }
- path_buff = malloc(PATH_BUFF_LEN); - if (!path_buff) { - fprintf(stderr, "Error - could not allocate path buffer: out of memory ?\n"); - return EXIT_FAILURE; + return 0; +} + +static int parse_gw(struct state *state, int argc, char *argv[]) +{ + char buff[256]; + char *endptr; + int ret; + + if (argc != 2 && argc != 3) { + fprintf(stderr, "Error - incorrect number of arguments (expected 1/2)\n"); + return -EINVAL; }
- snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, state->mesh_iface); + if (strcmp(argv[1], "client") == 0) { + gw_globals.mode = BATADV_GW_MODE_CLIENT; + } else if (strcmp(argv[1], "server") == 0) { + gw_globals.mode = BATADV_GW_MODE_SERVER; + } else if (strcmp(argv[1], "off") == 0) { + gw_globals.mode = BATADV_GW_MODE_OFF; + } else { + fprintf(stderr, "Error - the supplied argument is invalid: %s\n", argv[1]); + fprintf(stderr, "The following values are allowed:\n"); + fprintf(stderr, " * off\n"); + fprintf(stderr, " * client\n"); + fprintf(stderr, " * server\n");
- if (argc == 1) { - res = read_file(path_buff, SYS_GW_MODE, USE_READ_BUFF, 0, 0, 0); + return -EINVAL; + } + + if (argc <= 2) + return 0; + + strncpy(buff, argv[2], sizeof(buff)); + buff[sizeof(buff) - 1] = '\0'; + + switch (gw_globals.mode) { + case BATADV_GW_MODE_OFF: + fprintf(stderr, "Error - unexpected argument for mode "off": %s\n", argv[2]); + return -EINVAL; + case BATADV_GW_MODE_CLIENT: + if (is_throughput_select_class(state)) { + if (!parse_throughput(buff, "sel_class", + &gw_globals.sel_class)) + return -EINVAL; + } else { + gw_globals.sel_class = strtoul(buff, &endptr, 0); + if (!endptr || *endptr != '\0') { + fprintf(stderr, "Error - unexpected argument for mode "client": %s\n", buff); + return -EINVAL; + } + } + + gw_globals.sel_class_found = 1; + break; + case BATADV_GW_MODE_SERVER: + ret = parse_gw_limit(buff); + if (ret < 0) + return ret; + break; + } + + return 0; +} + +static int print_gw(struct nl_msg *msg, void *arg) +{ + static const int mandatory[] = { + BATADV_ATTR_GW_MODE, + }; + static const int mandatory_client[] = { + BATADV_ATTR_ALGO_NAME, + BATADV_ATTR_GW_SEL_CLASS, + }; + static const int mandatory_server[] = { + BATADV_ATTR_GW_BANDWIDTH_DOWN, + BATADV_ATTR_GW_BANDWIDTH_UP, + }; + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *ghdr; + int *result = arg; + const char *algo; + uint8_t gw_mode; + uint32_t val; + uint32_t down; + uint32_t up;
- if (res != EXIT_SUCCESS) - goto out; + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK;
- if (line_ptr[strlen(line_ptr) - 1] == '\n') - line_ptr[strlen(line_ptr) - 1] = '\0'; + ghdr = nlmsg_data(nlh);
- if (strcmp(line_ptr, "client") == 0) - gw_mode = GW_MODE_CLIENT; - else if (strcmp(line_ptr, "server") == 0) - gw_mode = GW_MODE_SERVER; + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + return NL_OK; + } + + /* ignore entry when attributes are missing */ + if (missing_mandatory_attrs(attrs, mandatory, ARRAY_SIZE(mandatory))) + return NL_OK; + + gw_mode = nla_get_u8(attrs[BATADV_ATTR_GW_MODE]); + switch (gw_mode) { + case BATADV_GW_MODE_OFF: + printf("off\n"); + break; + case BATADV_GW_MODE_CLIENT: + if (missing_mandatory_attrs(attrs, mandatory_client, + ARRAY_SIZE(mandatory_client))) + return NL_OK; + + algo = nla_data(attrs[BATADV_ATTR_ALGO_NAME]); + val = nla_get_u32(attrs[BATADV_ATTR_GW_SEL_CLASS]); + + if (strcmp(algo, "BATMAN_V") == 0) + printf("client (selection class: %u.%01u MBit)\n", + val / 10, val % 10); else - gw_mode = GW_MODE_OFF; + printf("client (selection class: %u)\n", val); + break; + case BATADV_GW_MODE_SERVER: + if (missing_mandatory_attrs(attrs, mandatory_server, + ARRAY_SIZE(mandatory_server))) + return NL_OK;
- free(line_ptr); - line_ptr = NULL; + down = nla_get_u32(attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]); + up = nla_get_u32(attrs[BATADV_ATTR_GW_BANDWIDTH_UP]);
- switch (gw_mode) { - case GW_MODE_CLIENT: - res = read_file(path_buff, SYS_GW_SEL, USE_READ_BUFF, 0, 0, 0); - break; - case GW_MODE_SERVER: - res = read_file(path_buff, SYS_GW_BW, USE_READ_BUFF, 0, 0, 0); - break; - default: - printf("off\n"); - goto out; - } + printf("server (announced bw: %u.%01u/%u.%01u MBit)\n", + down / 10, down % 10, up / 10, up % 10); + break; + default: + printf("unknown\n"); + break; + }
- if (res != EXIT_SUCCESS) - goto out; + *result = 0; + return NL_STOP; +}
- if (line_ptr[strlen(line_ptr) - 1] == '\n') - line_ptr[strlen(line_ptr) - 1] = '\0'; +static int get_gw(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, NULL, print_gw); +}
- switch (gw_mode) { - case GW_MODE_CLIENT: - printf("client (selection class: %s)\n", line_ptr); - break; - case GW_MODE_SERVER: - printf("server (announced bw: %s)\n", line_ptr); - break; - default: - goto out; - } +static int set_attrs_gw(struct nl_msg *msg, void *arg __maybe_unused) +{ + nla_put_u8(msg, BATADV_ATTR_GW_MODE, gw_globals.mode); + + if (gw_globals.bandwidth_down_found) + nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_DOWN, + gw_globals.bandwidth_down); + + if (gw_globals.bandwidth_up_found) + nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_UP, + gw_globals.bandwidth_up); + + if (gw_globals.sel_class_found) + nla_put_u32(msg, BATADV_ATTR_GW_SEL_CLASS, + gw_globals.sel_class);
- free(line_ptr); - line_ptr = NULL; + return 0; +} + +static int set_gw(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, set_attrs_gw, + NULL); +} + +static int gw_read_setting(struct state *state, const char *path_buff) +{ + enum batadv_gw_modes gw_mode; + int res; + + res = get_gw(state); + if (res < 0 && res != -EOPNOTSUPP) + return EXIT_FAILURE; + if (res >= 0) + return EXIT_SUCCESS; + + /* fallback to sysfs */ + res = read_file(path_buff, SYS_GW_MODE, USE_READ_BUFF, 0, 0, 0); + if (res != EXIT_SUCCESS) goto out; - }
- check_root_or_die("batctl gw_mode"); + if (line_ptr[strlen(line_ptr) - 1] == '\n') + line_ptr[strlen(line_ptr) - 1] = '\0';
- if (strcmp(argv[1], "client") == 0) - gw_mode = GW_MODE_CLIENT; - else if (strcmp(argv[1], "server") == 0) - gw_mode = GW_MODE_SERVER; - else if (strcmp(argv[1], "off") == 0) - gw_mode = GW_MODE_OFF; + if (strcmp(line_ptr, "client") == 0) + gw_mode = BATADV_GW_MODE_CLIENT; + else if (strcmp(line_ptr, "server") == 0) + gw_mode = BATADV_GW_MODE_SERVER; else - goto opt_err; + gw_mode = BATADV_GW_MODE_OFF;
- res = write_file(path_buff, SYS_GW_MODE, argv[1], NULL); - if (res != EXIT_SUCCESS) + free(line_ptr); + line_ptr = NULL; + + switch (gw_mode) { + case BATADV_GW_MODE_CLIENT: + res = read_file(path_buff, SYS_GW_SEL, USE_READ_BUFF, 0, 0, 0); + break; + case BATADV_GW_MODE_SERVER: + res = read_file(path_buff, SYS_GW_BW, USE_READ_BUFF, 0, 0, 0); + break; + default: + printf("off\n"); goto out; + }
- if (argc == 2) + if (res != EXIT_SUCCESS) goto out;
+ if (line_ptr[strlen(line_ptr) - 1] == '\n') + line_ptr[strlen(line_ptr) - 1] = '\0'; + switch (gw_mode) { - case GW_MODE_CLIENT: - res = write_file(path_buff, SYS_GW_SEL, argv[2], NULL); + case BATADV_GW_MODE_CLIENT: + printf("client (selection class: %s)\n", line_ptr); break; - case GW_MODE_SERVER: - res = write_file(path_buff, SYS_GW_BW, argv[2], NULL); + case BATADV_GW_MODE_SERVER: + printf("server (announced bw: %s)\n", line_ptr); break; + default: + goto out; + } + +out: + free(line_ptr); + line_ptr = NULL; + + return res; +} + +static int gw_write_setting(struct state *state, const char *path_buff, + int argc, char *argv[]) +{ + int res = EXIT_FAILURE; + + res = set_gw(state); + if (res < 0 && res != -EOPNOTSUPP) + return EXIT_FAILURE; + if (res >= 0) + return EXIT_SUCCESS; + + /* sysfs fallback */ + res = write_file(path_buff, SYS_GW_MODE, argv[1], NULL); + if (res != EXIT_SUCCESS) + return res; + + if (argc > 2) { + switch (gw_globals.mode) { + case BATADV_GW_MODE_CLIENT: + res = write_file(path_buff, SYS_GW_SEL, argv[2], NULL); + break; + case BATADV_GW_MODE_SERVER: + res = write_file(path_buff, SYS_GW_BW, argv[2], NULL); + break; + } }
- goto out; + return res; +}
-opt_err: - fprintf(stderr, "Error - the supplied argument is invalid: %s\n", argv[1]); - fprintf(stderr, "The following values are allowed:\n"); +static int gw_mode(struct state *state, int argc, char **argv) +{ + int optchar, res = EXIT_FAILURE; + char *path_buff;
- ptr = sysfs_param_server; - while (*ptr) { - fprintf(stderr, " * %s\n", *ptr); - ptr++; + while ((optchar = getopt(argc, argv, "h")) != -1) { + switch (optchar) { + case 'h': + gw_mode_usage(); + return EXIT_SUCCESS; + default: + gw_mode_usage(); + return EXIT_FAILURE; + } + } + + path_buff = malloc(PATH_BUFF_LEN); + if (!path_buff) { + fprintf(stderr, "Error - could not allocate path buffer: out of memory ?\n"); + return EXIT_FAILURE; + } + + snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, state->mesh_iface); + + if (argc == 1) { + res = gw_read_setting(state, path_buff); + goto out; + } + + check_root_or_die("batctl gw_mode"); + + res = parse_gw(state, argc, argv); + if (res < 0) { + res = EXIT_FAILURE; + goto out; }
+ res = gw_write_setting(state, path_buff, argc, argv); out: free(path_buff); return res; }
-COMMAND(SUBCOMMAND, gw_mode, "gw", COMMAND_FLAG_MESH_IFACE, NULL, +COMMAND(SUBCOMMAND, gw_mode, "gw", + COMMAND_FLAG_MESH_IFACE| COMMAND_FLAG_NETLINK, NULL, "[mode] \tdisplay or modify the gateway mode"); diff --git a/isolation_mark.c b/isolation_mark.c index 13ba869..e5f504f 100644 --- a/isolation_mark.c +++ b/isolation_mark.c @@ -20,16 +20,135 @@ * License-Filename: LICENSES/preferred/GPL-2.0 */
+#include <errno.h> #include <stddef.h> +#include <stdint.h> +#include <string.h>
#include "main.h" #include "sys.h"
+static struct isolation_mark_data { + uint32_t isolation_mark; + uint32_t isolation_mask; +} isolation_mark; + +static int parse_isolation_mark(struct state *state, int argc, char *argv[]) +{ + struct settings_data *settings = state->cmd->arg; + struct isolation_mark_data *data = settings->data; + char *mask_ptr; + char buff[256]; + uint32_t mark; + uint32_t mask; + char *endptr; + + if (argc != 2) { + fprintf(stderr, "Error - incorrect number of arguments (expected 1)\n"); + return -EINVAL; + } + + strncpy(buff, argv[1], sizeof(buff)); + buff[sizeof(buff) - 1] = '\0'; + + /* parse the mask if it has been specified, otherwise assume the mask is + * the biggest possible + */ + mask = 0xFFFFFFFF; + mask_ptr = strchr(buff, '/'); + if (mask_ptr) { + *mask_ptr = '\0'; + mask_ptr++; + + /* the mask must be entered in hex base as it is going to be a + * bitmask and not a prefix length + */ + mask = strtoul(mask_ptr, &endptr, 16); + if (!endptr || *endptr != '\0') + goto inval_format; + } + + /* the mark can be entered in any base */ + mark = strtoul(buff, &endptr, 0); + if (!endptr || *endptr != '\0') + goto inval_format; + + data->isolation_mask = mask; + /* erase bits not covered by the mask */ + data->isolation_mark = mark & mask; + + return 0; + +inval_format: + fprintf(stderr, "Error - incorrect number of arguments (expected 1)\n"); + fprintf(stderr, "The following formats for mark(/mask) are allowed:\n"); + fprintf(stderr, " * 0x12345678\n"); + fprintf(stderr, " * 0x12345678/0xabcdef09\n"); + return -EINVAL; +} + +static int print_isolation_mark(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *ghdr; + int *result = arg; + + 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)) { + return NL_OK; + } + + if (!attrs[BATADV_ATTR_ISOLATION_MARK] || + !attrs[BATADV_ATTR_ISOLATION_MASK]) + return NL_OK; + + printf("0x%08x/0x%08x\n", + nla_get_u32(attrs[BATADV_ATTR_ISOLATION_MARK]), + nla_get_u32(attrs[BATADV_ATTR_ISOLATION_MASK])); + + *result = 0; + return NL_STOP; +} + +static int get_isolation_mark(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_isolation_mark); +} + +static int set_attrs_isolation_mark(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct isolation_mark_data *data = settings->data; + + nla_put_u32(msg, BATADV_ATTR_ISOLATION_MARK, data->isolation_mark); + nla_put_u32(msg, BATADV_ATTR_ISOLATION_MASK, data->isolation_mask); + + return 0; +} + +static int set_isolation_mark(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_isolation_mark, NULL); +} + static struct settings_data batctl_settings_isolation_mark = { .sysfs_name = "isolation_mark", - .params = NULL, + .data = &isolation_mark, + .parse = parse_isolation_mark, + .netlink_get = get_isolation_mark, + .netlink_set = set_isolation_mark, };
COMMAND_NAMED(SUBCOMMAND, isolation_mark, "mark", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_isolation_mark, + COMMAND_FLAG_MESH_IFACE| COMMAND_FLAG_NETLINK, + &batctl_settings_isolation_mark, "[mark] \tdisplay or modify isolation_mark setting"); diff --git a/loglevel.c b/loglevel.c index fed70c8..fc5fc65 100644 --- a/loglevel.c +++ b/loglevel.c @@ -20,7 +20,9 @@ * License-Filename: LICENSES/preferred/GPL-2.0 */
+#include <errno.h> #include <getopt.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -29,6 +31,10 @@ #include "main.h" #include "sys.h"
+static struct log_level_data { + uint32_t log_level; +} log_level_globals; + static void log_level_usage(void) { fprintf(stderr, "Usage: batctl [options] loglevel [parameters] [level[ level[ level]]...]\n"); @@ -47,14 +53,93 @@ static void log_level_usage(void) fprintf(stderr, " \t tp Messages related to throughput meter\n"); }
+static int extract_log_level(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *ghdr; + int *result = arg; + + 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)) { + return NL_OK; + } + + if (!attrs[BATADV_ATTR_LOG_LEVEL]) + return NL_OK; + + log_level_globals.log_level = nla_get_u32(attrs[BATADV_ATTR_LOG_LEVEL]); + + *result = 0; + return NL_STOP; +} + +static int get_log_level(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, extract_log_level); +} + +static int set_attrs_log_level(struct nl_msg *msg, void *arg __maybe_unused) +{ + nla_put_u32(msg, BATADV_ATTR_LOG_LEVEL, log_level_globals.log_level); + + return 0; +} + +static int set_log_level(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_log_level, NULL); +} + +static int log_level_read_setting(struct state *state, const char *path_buff) +{ + int res; + + res = get_log_level(state); + if (res < 0 && res != -EOPNOTSUPP) + return EXIT_FAILURE; + if (res >= 0) + return EXIT_SUCCESS; + + res = read_file(path_buff, SYS_LOG_LEVEL, USE_READ_BUFF, 0, 0, 0); + if (res != EXIT_SUCCESS) + return res; + + log_level_globals.log_level = strtol(line_ptr, (char **) NULL, 10); + + return res; +} + +static int log_level_write_setting(struct state *state, const char *path_buff) +{ + int res; + char str[4]; + + res = set_log_level(state); + if (res < 0 && res != -EOPNOTSUPP) + return EXIT_FAILURE; + if (res >= 0) + return EXIT_SUCCESS; + + snprintf(str, sizeof(str), "%i", log_level_globals.log_level); + return write_file(path_buff, SYS_LOG_LEVEL, str, NULL); +} + static int loglevel(struct state *state, int argc, char **argv) { int optchar, res = EXIT_FAILURE; - int log_level = 0; char *path_buff; - char str[4]; int i;
+ log_level_globals.log_level = 0; + while ((optchar = getopt(argc, argv, "h")) != -1) { switch (optchar) { case 'h': @@ -79,63 +164,59 @@ static int loglevel(struct state *state, int argc, char **argv)
for (i = 1; i < argc; i++) { if (strcmp(argv[i], "none") == 0) { - log_level = 0; + log_level_globals.log_level = 0; break; } else if (strcmp(argv[i], "all") == 0) { - log_level = 255; + log_level_globals.log_level = 255; break; } else if (strcmp(argv[i], "batman") == 0) - log_level |= BIT(0); + log_level_globals.log_level |= BIT(0); else if (strcmp(argv[i], "routes") == 0) - log_level |= BIT(1); + log_level_globals.log_level |= BIT(1); else if (strcmp(argv[i], "tt") == 0) - log_level |= BIT(2); + log_level_globals.log_level |= BIT(2); else if (strcmp(argv[i], "bla") == 0) - log_level |= BIT(3); + log_level_globals.log_level |= BIT(3); else if (strcmp(argv[i], "dat") == 0) - log_level |= BIT(4); + log_level_globals.log_level |= BIT(4); else if (strcmp(argv[i], "nc") == 0) - log_level |= BIT(5); + log_level_globals.log_level |= BIT(5); else if (strcmp(argv[i], "mcast") == 0) - log_level |= BIT(6); + log_level_globals.log_level |= BIT(6); else if (strcmp(argv[i], "tp") == 0) - log_level |= BIT(7); + log_level_globals.log_level |= BIT(7); else { log_level_usage(); goto out; } }
- snprintf(str, sizeof(str), "%i", log_level); - res = write_file(path_buff, SYS_LOG_LEVEL, str, NULL); + log_level_write_setting(state, path_buff); goto out; }
- res = read_file(path_buff, SYS_LOG_LEVEL, USE_READ_BUFF, 0, 0, 0); - + res = log_level_read_setting(state, path_buff); if (res != EXIT_SUCCESS) goto out;
- log_level = strtol(line_ptr, (char **) NULL, 10); - - printf("[%c] %s (%s)\n", (!log_level) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (!log_level_globals.log_level) ? 'x' : ' ', "all debug output disabled", "none"); - printf("[%c] %s (%s)\n", (log_level & BIT(0)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(0)) ? 'x' : ' ', "messages related to routing / flooding / broadcasting", "batman"); - printf("[%c] %s (%s)\n", (log_level & BIT(1)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(1)) ? 'x' : ' ', "messages related to route added / changed / deleted", "routes"); - printf("[%c] %s (%s)\n", (log_level & BIT(2)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(2)) ? 'x' : ' ', "messages related to translation table operations", "tt"); - printf("[%c] %s (%s)\n", (log_level & BIT(3)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(3)) ? 'x' : ' ', "messages related to bridge loop avoidance", "bla"); - printf("[%c] %s (%s)\n", (log_level & BIT(4)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(4)) ? 'x' : ' ', "messages related to arp snooping and distributed arp table", "dat"); - printf("[%c] %s (%s)\n", (log_level & BIT(5)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(5)) ? 'x' : ' ', "messages related to network coding", "nc"); - printf("[%c] %s (%s)\n", (log_level & BIT(6)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(6)) ? 'x' : ' ', "messages related to multicast", "mcast"); - printf("[%c] %s (%s)\n", (log_level & BIT(7)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(7)) ? 'x' : ' ', "messages related to throughput meter", "tp");
out: @@ -143,5 +224,6 @@ static int loglevel(struct state *state, int argc, char **argv) return res; }
-COMMAND(SUBCOMMAND, loglevel, "ll", COMMAND_FLAG_MESH_IFACE, NULL, +COMMAND(SUBCOMMAND, loglevel, "ll", + COMMAND_FLAG_MESH_IFACE| COMMAND_FLAG_NETLINK, NULL, "[level] \tdisplay or modify the log level"); diff --git a/multicast_mode.c b/multicast_mode.c index 8542928..ef0da28 100644 --- a/multicast_mode.c +++ b/multicast_mode.c @@ -21,13 +21,54 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data multicast_mode; + +static int print_multicast_mode(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, BATADV_ATTR_MULTICAST_MODE); +} + +static int get_multicast_mode(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_multicast_mode); +} + +static int set_attrs_multicast_mode(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_MULTICAST_MODE, data->val); + + return 0; +} + +static int set_multicast_mode(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_multicast_mode, NULL); +} + static struct settings_data batctl_settings_multicast_mode = { .sysfs_name = SYS_MULTICAST_MODE, - .params = sysfs_param_enable, + .data = &multicast_mode, + .parse = parse_simple_boolean, + .netlink_get = get_multicast_mode, + .netlink_set = set_multicast_mode, };
COMMAND_NAMED(SUBCOMMAND, multicast_mode, "mm", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_multicast_mode, + COMMAND_FLAG_MESH_IFACE| COMMAND_FLAG_NETLINK, + &batctl_settings_multicast_mode, "[0|1] \tdisplay or modify multicast_mode setting"); diff --git a/netlink.c b/netlink.c index b0d57b1..9c29774 100644 --- a/netlink.c +++ b/netlink.c @@ -853,3 +853,79 @@ int get_primarymac_netlink(const char *mesh_iface, uint8_t *primarymac)
return 0; } + +struct get_algoname_netlink_opts { + char *algoname; + size_t algoname_len; + bool found; + struct nlquery_opts query_opts; +}; + +static int get_algoname_netlink_cb(struct nl_msg *msg, void *arg) +{ + static const int mandatory[] = { + BATADV_ATTR_ALGO_NAME, + }; + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlquery_opts *query_opts = arg; + struct get_algoname_netlink_opts *opts; + struct genlmsghdr *ghdr; + const char *algoname; + + opts = container_of(query_opts, struct get_algoname_netlink_opts, + query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_MESH) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + return NL_OK; + } + + if (missing_mandatory_attrs(attrs, mandatory, ARRAY_SIZE(mandatory))) + return NL_OK; + + algoname = nla_data(attrs[BATADV_ATTR_ALGO_NAME]); + + /* save result */ + strncpy(opts->algoname, algoname, opts->algoname_len); + if (opts->algoname_len > 0) + opts->algoname[opts->algoname_len - 1] = '\0'; + + opts->found = true; + opts->query_opts.err = 0; + + return NL_STOP; +} + +int get_algoname_netlink(const char *mesh_iface, char *algoname, + size_t algoname_len) +{ + struct get_algoname_netlink_opts opts = { + .algoname = algoname, + .algoname_len = algoname_len, + .found = false, + .query_opts = { + .err = 0, + }, + }; + int ret; + + ret = netlink_query_common(mesh_iface, BATADV_CMD_GET_MESH, + get_algoname_netlink_cb, 0, + &opts.query_opts); + if (ret < 0) + return ret; + + if (!opts.found) + return -EOPNOTSUPP; + + return 0; +} diff --git a/netlink.h b/netlink.h index b91ca10..9be49cd 100644 --- a/netlink.h +++ b/netlink.h @@ -50,6 +50,8 @@ int translate_mac_netlink(const char *mesh_iface, const struct ether_addr *mac, int get_nexthop_netlink(const char *mesh_iface, const struct ether_addr *mac, uint8_t *nexthop, char *ifname); int get_primarymac_netlink(const char *mesh_iface, uint8_t *primarymac); +int get_algoname_netlink(const char *mesh_iface, char *algoname, + size_t algoname_len);
extern struct nla_policy batadv_netlink_policy[];
diff --git a/network_coding.c b/network_coding.c index a4c4296..7fc8d36 100644 --- a/network_coding.c +++ b/network_coding.c @@ -21,13 +21,54 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data network_coding; + +static int print_network_coding(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, BATADV_ATTR_NETWORK_CODING); +} + +static int get_network_coding(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_network_coding); +} + +static int set_attrs_network_coding(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_NETWORK_CODING, data->val); + + return 0; +} + +static int set_network_coding(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_network_coding, NULL); +} + static struct settings_data batctl_settings_network_coding = { .sysfs_name = SYS_NETWORK_CODING, - .params = sysfs_param_enable, + .data = &network_coding, + .parse = parse_simple_boolean, + .netlink_get = get_network_coding, + .netlink_set = set_network_coding, };
COMMAND_NAMED(SUBCOMMAND, network_coding, "nc", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_network_coding, + COMMAND_FLAG_MESH_IFACE| COMMAND_FLAG_NETLINK, + &batctl_settings_network_coding, "[0|1] \tdisplay or modify network_coding setting"); diff --git a/orig_interval.c b/orig_interval.c index d308ea2..eb11d95 100644 --- a/orig_interval.c +++ b/orig_interval.c @@ -20,16 +20,96 @@ * License-Filename: LICENSES/preferred/GPL-2.0 */
+#include <errno.h> #include <stddef.h> +#include <stdint.h> +#include <string.h>
#include "main.h" #include "sys.h"
+static struct orig_interval_data { + uint32_t orig_interval; +} orig_interval; + +static int parse_orig_interval(struct state *state, int argc, char *argv[]) +{ + struct settings_data *settings = state->cmd->arg; + struct orig_interval_data *data = settings->data; + char *endptr; + + if (argc != 2) { + fprintf(stderr, "Error - incorrect number of arguments (expected 1)\n"); + return -EINVAL; + } + + data->orig_interval = strtoul(argv[1], &endptr, 0); + if (!endptr || *endptr != '\0') { + fprintf(stderr, "Error - the supplied argument is invalid: %s\n", argv[1]); + return -EINVAL; + } + + return 0; +} + +static int print_orig_interval(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *ghdr; + int *result = arg; + + 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)) { + return NL_OK; + } + + if (!attrs[BATADV_ATTR_ORIG_INTERVAL]) + return NL_OK; + + printf("%u\n", nla_get_u32(attrs[BATADV_ATTR_ORIG_INTERVAL])); + + *result = 0; + return NL_STOP; +} + +static int get_orig_interval(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_orig_interval); +} + +static int set_attrs_orig_interval(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct orig_interval_data *data = settings->data; + + nla_put_u32(msg, BATADV_ATTR_ORIG_INTERVAL, data->orig_interval); + + return 0; +} + +static int set_orig_interval(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_orig_interval, NULL); +} + static struct settings_data batctl_settings_orig_interval = { .sysfs_name = "orig_interval", - .params = NULL, + .data = &orig_interval, + .parse = parse_orig_interval, + .netlink_get = get_orig_interval, + .netlink_set = set_orig_interval, };
COMMAND_NAMED(SUBCOMMAND, orig_interval, "it", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_orig_interval, + COMMAND_FLAG_MESH_IFACE| COMMAND_FLAG_NETLINK, + &batctl_settings_orig_interval, "[interval] \tdisplay or modify orig_interval setting"); diff --git a/routing_algo.c b/routing_algo.c index 18d9ef7..69eac34 100644 --- a/routing_algo.c +++ b/routing_algo.c @@ -41,7 +41,6 @@ #include "sys.h"
#define SYS_SELECTED_RA_PATH "/sys/module/batman_adv/parameters/routing_algo" -#define SYS_ROUTING_ALGO_FMT SYS_IFACE_PATH"/%s/mesh/routing_algo"
static void ra_mode_usage(void) { diff --git a/sys.c b/sys.c index be20be7..dc88268 100644 --- a/sys.c +++ b/sys.c @@ -39,20 +39,120 @@ #include "functions.h" #include "debug.h"
-const char *sysfs_param_enable[] = { - "enable", - "disable", - "1", - "0", - NULL, -}; - -const char *sysfs_param_server[] = { - "off", - "client", - "server", - NULL, -}; +int parse_simple_boolean(struct state *state, int argc, char *argv[]) +{ + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + int ret; + + if (argc != 2) { + fprintf(stderr, "Error - incorrect number of arguments (expected 1)\n"); + return -EINVAL; + } + + ret = parse_bool(argv[1], &data->val); + if (ret < 0) { + fprintf(stderr, "Error - the supplied argument is invalid: %s\n", argv[1]); + fprintf(stderr, "The following values are allowed:\n"); + fprintf(stderr, " * 0\n"); + fprintf(stderr, " * disable\n"); + fprintf(stderr, " * disabled\n"); + fprintf(stderr, " * 1\n"); + fprintf(stderr, " * enable\n"); + fprintf(stderr, " * enabled\n"); + + return ret; + } + + return 0; +} + + +static int sys_simple_nlerror(struct sockaddr_nl *nla __maybe_unused, + struct nlmsgerr *nlerr, void *arg) +{ + int *result = arg; + + if (nlerr->error != -EOPNOTSUPP) + fprintf(stderr, "Error received: %s\n", + strerror(-nlerr->error)); + + *result = nlerr->error; + + return NL_STOP; +} + +int sys_simple_nlquery(struct state *state, enum batadv_nl_commands nl_cmd, + nl_recvmsg_msg_cb_t attribute_cb, + nl_recvmsg_msg_cb_t callback) +{ + int result; + struct nl_msg *msg; + int ret; + + if (!state->sock) + return -EOPNOTSUPP; + + if (callback) { + result = -EOPNOTSUPP; + nl_cb_set(state->cb, NL_CB_VALID, NL_CB_CUSTOM, callback, + &result); + } else { + result = 0; + } + + nl_cb_err(state->cb, NL_CB_CUSTOM, sys_simple_nlerror, &result); + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, state->batadv_family, 0, 0, + nl_cmd, 1); + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, state->mesh_ifindex); + + if (attribute_cb) { + ret = attribute_cb(msg, state); + if (ret < 0) { + nlmsg_free(msg); + return -ENOMEM; + } + } + + nl_send_auto_complete(state->sock, msg); + nlmsg_free(msg); + + nl_recvmsgs(state->sock, state->cb); + + return result; +} + +int sys_simple_print_boolean(struct nl_msg *msg, void *arg, + enum batadv_nl_attrs attr) +{ + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *ghdr; + int *result = arg; + + 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)) { + return NL_OK; + } + + if (!attrs[attr]) + return NL_OK; + + printf("%s\n", nla_get_u8(attrs[attr]) ? "enabled" : "disabled"); + + *result = 0; + return NL_STOP; +}
static void settings_usage(struct state *state) { @@ -63,12 +163,52 @@ static void settings_usage(struct state *state) fprintf(stderr, " \t -h print this help\n"); }
+static int sys_read_setting(struct state *state, const char *path_buff, + const char *sysfs_name) +{ + struct settings_data *settings = state->cmd->arg; + int res = EXIT_FAILURE; + + if (settings->netlink_get) { + res = settings->netlink_get(state); + if (res < 0 && res != -EOPNOTSUPP) + return EXIT_FAILURE; + if (res >= 0) + return EXIT_SUCCESS; + } + + if (sysfs_name) + res = read_file(path_buff, sysfs_name, NO_FLAGS, 0, 0, 0); + + return res; +} + +static int sys_write_setting(struct state *state, const char *path_buff, + const char *sysfs_name, int argc, char **argv) +{ + struct settings_data *settings = state->cmd->arg; + int res = EXIT_FAILURE; + + if (settings->netlink_set) { + res = settings->netlink_set(state); + if (res < 0 && res != -EOPNOTSUPP) + return EXIT_FAILURE; + if (res >= 0) + return EXIT_SUCCESS; + } + + if (sysfs_name) + res = write_file(path_buff, sysfs_name, + argv[1], argc > 2 ? argv[2] : NULL); + + return res; +} + int handle_sys_setting(struct state *state, int argc, char **argv) { struct settings_data *settings = state->cmd->arg; int optchar, res = EXIT_FAILURE; char *path_buff; - const char **ptr;
while ((optchar = getopt(argc, argv, "h")) != -1) { switch (optchar) { @@ -99,38 +239,22 @@ int handle_sys_setting(struct state *state, int argc, char **argv) state->mesh_iface);
if (argc == 1) { - res = read_file(path_buff, settings->sysfs_name, - NO_FLAGS, 0, 0, 0); + res = sys_read_setting(state, path_buff, settings->sysfs_name); goto out; }
check_root_or_die("batctl");
- if (!settings->params) - goto write_file; - - ptr = settings->params; - while (*ptr) { - if (strcmp(*ptr, argv[1]) == 0) - goto write_file; - - ptr++; - } - - fprintf(stderr, "Error - the supplied argument is invalid: %s\n", argv[1]); - fprintf(stderr, "The following values are allowed:\n"); - - ptr = settings->params; - while (*ptr) { - fprintf(stderr, " * %s\n", *ptr); - ptr++; + if (settings->parse) { + res = settings->parse(state, argc, argv); + if (res < 0) { + res = EXIT_FAILURE; + goto out; + } }
- goto out; - -write_file: - res = write_file(path_buff, settings->sysfs_name, - argv[1], argc > 2 ? argv[2] : NULL); + res = sys_write_setting(state, path_buff, settings->sysfs_name, argc, + argv);
out: free(path_buff); diff --git a/sys.h b/sys.h index 20e1934..2eaa8be 100644 --- a/sys.h +++ b/sys.h @@ -25,6 +25,13 @@
#include "main.h"
+#include <linux/genetlink.h> +#include <netlink/genl/genl.h> +#include <stdbool.h> + +#include "batman_adv.h" +#include "netlink.h" + #define SYS_BATIF_PATH_FMT "/sys/class/net/%s/mesh/" #define SYS_LOG_LEVEL "log_level" #define SYS_LOG "log" @@ -37,16 +44,29 @@ #define SYS_MESH_IFACE_FMT SYS_IFACE_PATH"/%s/batman_adv/mesh_iface" #define SYS_IFACE_STATUS_FMT SYS_IFACE_PATH"/%s/batman_adv/iface_status" #define SYS_VLAN_PATH SYS_IFACE_PATH"/%s/mesh/vlan%d/" +#define SYS_ROUTING_ALGO_FMT SYS_IFACE_PATH"/%s/mesh/routing_algo" #define VLAN_ID_MAX_LEN 4
struct settings_data { const char *sysfs_name; - const char **params; + void *data; + int (*parse)(struct state *state, int argc, char *argv[]); + int (*netlink_get)(struct state *state); + int (*netlink_set)(struct state *state); };
-extern const char *sysfs_param_enable[]; -extern const char *sysfs_param_server[]; +struct simple_boolean_data { + bool val; +};
int handle_sys_setting(struct state *state, int argc, char **argv); +int parse_simple_boolean(struct state *state, int argc, char *argv[]); + + +int sys_simple_nlquery(struct state *state, enum batadv_nl_commands nl_cmd, + nl_recvmsg_msg_cb_t attribute_cb, + nl_recvmsg_msg_cb_t callback); +int sys_simple_print_boolean(struct nl_msg *msg, void *arg, + enum batadv_nl_attrs attr);
#endif
b.a.t.m.a.n@lists.open-mesh.org