The normal way of network related programs to query the state of interfaces is to use the rtnetlink. Most of these data can also be queried via sysfs but it is easier to use the same way for both retrieving the list of interfaces and modifying the list of interfaces.
Signed-off-by: Sven Eckelmann sven@narfation.org --- v2: - no change
functions.c | 64 +++++++++++++++++++++++++++++++++++ functions.h | 5 ++- sys.c | 111 +++++++++++++++++++++++++++++++++--------------------------- 3 files changed, 129 insertions(+), 51 deletions(-)
diff --git a/functions.c b/functions.c index d236d64..327ef18 100644 --- a/functions.c +++ b/functions.c @@ -37,6 +37,7 @@ #include <stdint.h> #include <linux/netlink.h> #include <net/ethernet.h> +#include <linux/if_link.h> #include <linux/rtnetlink.h> #include <linux/neighbour.h> #include <errno.h> @@ -889,3 +890,66 @@ int print_routing_algos(void) err = debug_print_routing_algos(); return err; } + +int query_rtnl_link(int ifindex, nl_recvmsg_msg_cb_t func, void *arg) +{ + struct ifinfomsg rt_hdr = { + .ifi_family = IFLA_UNSPEC, + }; + struct nl_sock *sock; + struct nl_msg *msg; + struct nl_cb *cb; + int err = 0; + int ret; + + sock = nl_socket_alloc(); + if (!sock) + return -ENOMEM; + + ret = nl_connect(sock, NETLINK_ROUTE); + if (ret < 0) { + err = -ENOMEM; + goto err_free_sock; + } + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) { + err = -ENOMEM; + goto err_free_sock; + } + + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, func, arg); + + msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP); + if (!msg) { + err = -ENOMEM; + goto err_free_cb; + } + + ret = nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + ret = nla_put_u32(msg, IFLA_MASTER, ifindex); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + ret = nl_send_auto_complete(sock, msg); + if (ret < 0) + goto err_free_msg; + + nl_recvmsgs(sock, cb); + +err_free_msg: + nlmsg_free(msg); +err_free_cb: + nl_cb_put(cb); +err_free_sock: + nl_socket_free(sock); + + return err; +} diff --git a/functions.h b/functions.h index e24dea0..a6090b6 100644 --- a/functions.h +++ b/functions.h @@ -23,6 +23,8 @@ #define _BATCTL_FUNCTIONS_H
#include <net/ethernet.h> +#include <netlink/netlink.h> +#include <netlink/handlers.h> #include <stddef.h>
@@ -43,7 +45,8 @@ 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 print_routing_algos(void); extern char *line_ptr; diff --git a/sys.c b/sys.c index ca837f6..0140b28 100644 --- a/sys.c +++ b/sys.c @@ -26,6 +26,11 @@ #include <string.h> #include <errno.h> #include <dirent.h> +#include <net/if.h> +#include <linux/if_link.h> +#include <netlink/netlink.h> +#include <netlink/msg.h> +#include <netlink/attr.h>
#include "main.h" #include "sys.h" @@ -119,72 +124,78 @@ static void interface_usage(void) fprintf(stderr, " \t -h print this help\n"); }
-static int print_interfaces(char *mesh_iface) -{ - DIR *iface_base_dir; - struct dirent *iface_dir; - char *path_buff; - int res; +static struct nla_policy link_policy[IFLA_MAX + 1] = { + [IFLA_IFNAME] = { .type = NLA_STRING, .maxlen = IFNAMSIZ }, + [IFLA_MASTER] = { .type = NLA_U32 }, +};
- if (!file_exists(module_ver_path)) { - fprintf(stderr, "Error - batman-adv module has not been loaded\n"); +struct print_interfaces_rtnl_arg { + int ifindex; +}; + +static int print_interfaces_rtnl_parse(struct nl_msg *msg, void *arg) +{ + struct print_interfaces_rtnl_arg *print_arg = arg; + struct nlattr *attrs[IFLA_MAX + 1]; + char path_buff[PATH_BUFF_LEN]; + struct ifinfomsg *ifm; + char *ifname; + int ret; + const char *status; + int master; + + ifm = nlmsg_data(nlmsg_hdr(msg)); + ret = nlmsg_parse(nlmsg_hdr(msg), sizeof(*ifm), attrs, IFLA_MAX, + link_policy); + if (ret < 0) goto err; - }
- path_buff = malloc(PATH_BUFF_LEN); - if (!path_buff) { - fprintf(stderr, "Error - could not allocate path buffer: out of memory ?\n"); + if (!attrs[IFLA_IFNAME]) goto err; - }
- iface_base_dir = opendir(SYS_IFACE_PATH); - if (!iface_base_dir) { - fprintf(stderr, "Error - the directory '%s' could not be read: %s\n", - SYS_IFACE_PATH, strerror(errno)); - fprintf(stderr, "Is the batman-adv module loaded and sysfs mounted ?\n"); - goto err_buff; - } + if (!attrs[IFLA_MASTER]) + goto err;
- while ((iface_dir = readdir(iface_base_dir)) != NULL) { - snprintf(path_buff, PATH_BUFF_LEN, SYS_MESH_IFACE_FMT, iface_dir->d_name); - res = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0, 0); - if (res != EXIT_SUCCESS) - continue; + ifname = nla_get_string(attrs[IFLA_IFNAME]); + master = nla_get_u32(attrs[IFLA_MASTER]);
- if (line_ptr[strlen(line_ptr) - 1] == '\n') - line_ptr[strlen(line_ptr) - 1] = '\0'; + /* required on older kernels which don't prefilter the results */ + if (master != print_arg->ifindex) + goto err;
- if (strcmp(line_ptr, "none") == 0) - goto free_line; + snprintf(path_buff, sizeof(path_buff), SYS_IFACE_STATUS_FMT, ifname); + ret = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0, 0); + if (ret != EXIT_SUCCESS) + status = "<error reading status>\n"; + else + status = line_ptr;
- if (strcmp(line_ptr, mesh_iface) != 0) - goto free_line; + printf("%s: %s", ifname, status);
- free(line_ptr); - line_ptr = NULL; + free(line_ptr); + line_ptr = NULL;
- snprintf(path_buff, PATH_BUFF_LEN, SYS_IFACE_STATUS_FMT, iface_dir->d_name); - res = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0, 0); - if (res != EXIT_SUCCESS) { - fprintf(stderr, "<error reading status>\n"); - continue; - } +err: + return NL_OK; +}
- printf("%s: %s", iface_dir->d_name, line_ptr); +static int print_interfaces(char *mesh_iface) +{ + struct print_interfaces_rtnl_arg print_arg;
-free_line: - free(line_ptr); - line_ptr = NULL; + if (!file_exists(module_ver_path)) { + fprintf(stderr, "Error - batman-adv module has not been loaded\n"); + return EXIT_FAILURE; }
- free(path_buff); - closedir(iface_base_dir); - return EXIT_SUCCESS; + print_arg.ifindex = if_nametoindex(mesh_iface); + if (!print_arg.ifindex) + return EXIT_FAILURE;
-err_buff: - free(path_buff); -err: - return EXIT_FAILURE; + query_rtnl_link(print_arg.ifindex, print_interfaces_rtnl_parse, + &print_arg); + + return EXIT_SUCCESS; }
int interface(char *mesh_iface, int argc, char **argv)
The command "create" can be used to create a batman-adv interface without any interface attached. This is helpful when the interfaces should be configured independently of the first attached interface.
The command "destroy" can be used to destroy a batman-adv interface without going through all attached interfaces and delete them manually.
Signed-off-by: Sven Eckelmann sven@narfation.org --- v2: - rename "new" command to "create" as requested by Linus Luessing and John Harrison
functions.c | 58 ++++++++++++++++++++++++ functions.h | 1 + man/batctl.8 | 3 ++ sys.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 200 insertions(+), 5 deletions(-)
diff --git a/functions.c b/functions.c index 327ef18..962efcf 100644 --- a/functions.c +++ b/functions.c @@ -953,3 +953,61 @@ err_free_sock:
return err; } + +static int ack_errno_handler(struct sockaddr_nl *nla __unused, + struct nlmsgerr *nlerr, + void *arg) +{ + int *err = arg; + + *err = nlerr->error; + + return NL_STOP; +} + +static int ack_wait_handler(struct nl_msg *msg __unused, void *arg __unused) +{ + return NL_STOP; +} + +int netlink_simple_request(struct nl_msg *msg) +{ + struct nl_sock *sock; + struct nl_cb *cb; + int err = 0; + int ret; + + sock = nl_socket_alloc(); + if (!sock) + return -ENOMEM; + + ret = nl_connect(sock, NETLINK_ROUTE); + if (ret < 0) { + err = -ENOMEM; + goto err_free_sock; + } + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) { + err = -ENOMEM; + goto err_free_sock; + } + + nl_cb_err(cb, NL_CB_CUSTOM, ack_errno_handler, &err); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL); + + ret = nl_send_auto_complete(sock, msg); + if (ret < 0) + goto err_free_cb; + + // ack_errno_handler sets err on errors + err = 0; + nl_recvmsgs(sock, cb); + +err_free_cb: + nl_cb_put(cb); +err_free_sock: + nl_socket_free(sock); + + return err; +} diff --git a/functions.h b/functions.h index a6090b6..7757731 100644 --- a/functions.h +++ b/functions.h @@ -47,6 +47,7 @@ struct ether_addr *translate_mac(const char *mesh_iface, 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 print_routing_algos(void); extern char *line_ptr; diff --git a/man/batctl.8 b/man/batctl.8 index 8bac727..a29d1fb 100644 --- a/man/batctl.8 +++ b/man/batctl.8 @@ -56,6 +56,9 @@ performances, is also included. If no parameter is given or the first parameter is neither "add" nor "del" the current interface settings are displayed. In order to add or delete interfaces specify "add" or "del" as first argument and append the interface names you wish to add or delete. Multiple interfaces can be specified. +.IP "\fBinterface\fP|\fBif\fP [\fBcreate\fP|\fBdestroy\fP]" +A batman-adv interface without attached interfaces can be created using "create". The parameter "destroy" can be used to +free all attached interfaces and remove batman-adv interface. .br .IP "\fBorig_interval\fP|\fBit\fP [\fBinterval\fP]" If no parameter is given the current originator interval setting is displayed otherwise the parameter is used to set the diff --git a/sys.c b/sys.c index 0140b28..c18c6b8 100644 --- a/sys.c +++ b/sys.c @@ -120,6 +120,7 @@ const struct settings_data batctl_settings[BATCTL_SETTINGS_NUM] = { static void interface_usage(void) { fprintf(stderr, "Usage: batctl [options] interface [parameters] [add|del iface(s)]\n"); + fprintf(stderr, " batctl [options] interface [parameters] [create|destroy]\n"); fprintf(stderr, "parameters:\n"); fprintf(stderr, " \t -h print this help\n"); } @@ -198,10 +199,95 @@ static int print_interfaces(char *mesh_iface) return EXIT_SUCCESS; }
+static int create_interface(const char *mesh_iface) +{ + struct ifinfomsg rt_hdr = { + .ifi_family = IFLA_UNSPEC, + }; + struct nlattr *linkinfo; + struct nl_msg *msg; + int err = 0; + int ret; + + msg = nlmsg_alloc_simple(RTM_NEWLINK, + NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK); + if (!msg) { + return -ENOMEM; + } + + ret = nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + ret = nla_put_string(msg, IFLA_IFNAME, mesh_iface); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + linkinfo = nla_nest_start(msg, IFLA_LINKINFO); + if (!linkinfo) { + err = -ENOMEM; + goto err_free_msg; + } + + ret = nla_put_string(msg, IFLA_INFO_KIND, "batadv"); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + nla_nest_end(msg, linkinfo); + + err = netlink_simple_request(msg); + +err_free_msg: + nlmsg_free(msg); + + return err; +} + +static int destroy_interface(const char *mesh_iface) +{ + struct ifinfomsg rt_hdr = { + .ifi_family = IFLA_UNSPEC, + }; + struct nl_msg *msg; + int err = 0; + int ret; + + msg = nlmsg_alloc_simple(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK); + if (!msg) { + return -ENOMEM; + } + + ret = nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + ret = nla_put_string(msg, IFLA_IFNAME, mesh_iface); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + err = netlink_simple_request(msg); + +err_free_msg: + nlmsg_free(msg); + + return err; +} + int interface(char *mesh_iface, int argc, char **argv) { char *path_buff; int i, res, optchar; + int ret;
while ((optchar = getopt(argc, argv, "h")) != -1) { switch (optchar) { @@ -218,16 +304,63 @@ int interface(char *mesh_iface, int argc, char **argv) return print_interfaces(mesh_iface);
if ((strcmp(argv[1], "add") != 0) && (strcmp(argv[1], "a") != 0) && - (strcmp(argv[1], "del") != 0) && (strcmp(argv[1], "d") != 0)) { + (strcmp(argv[1], "del") != 0) && (strcmp(argv[1], "d") != 0) && + (strcmp(argv[1], "create") != 0) && (strcmp(argv[1], "c") != 0) && + (strcmp(argv[1], "destroy") != 0) && (strcmp(argv[1], "D") != 0)) { fprintf(stderr, "Error - unknown argument specified: %s\n", argv[1]); interface_usage(); goto err; }
- if (argc == 2) { - fprintf(stderr, "Error - missing interface name(s) after '%s'\n", argv[1]); - interface_usage(); - goto err; + if (strcmp(argv[1], "destroy") == 0) + argv[1][0] = 'D'; + + switch (argv[1][0]) { + case 'a': + case 'd': + if (argc == 2) { + fprintf(stderr, + "Error - missing interface name(s) after '%s'\n", + argv[1]); + interface_usage(); + goto err; + } + break; + case 'c': + case 'D': + if (argc != 2) { + fprintf(stderr, + "Error - extra parameter after '%s'\n", + argv[1]); + interface_usage(); + goto err; + } + break; + default: + break; + } + + switch (argv[1][0]) { + case 'c': + ret = create_interface(mesh_iface); + if (ret < 0) { + fprintf(stderr, + "Error - failed to create batman-adv interface: %s\n", + strerror(-ret)); + goto err; + } + return EXIT_SUCCESS; + case 'D': + ret = destroy_interface(mesh_iface); + if (ret < 0) { + fprintf(stderr, + "Error - failed to destroy batman-adv interface: %s\n", + strerror(-ret)); + goto err; + } + return EXIT_SUCCESS; + default: + break; }
path_buff = malloc(PATH_BUFF_LEN);
The sysfs interface to add/remove interfaces to/from a batman-adv soft-interface was downgraded in batman-adv master to a second-class citizen. This was done because it has conceptional problems (for example locking of sysfs vs. locking of the network core code). The only direct way to modify network interfaces is rtnetlink. sysfs still exists but has to use workers which delay the actual add/del to a later point.
It is therefore prefered to use the modern rtnetlink. Only batman-adv versions older than v2013.2.0 (Linux 3.10) will not yet support the rtnl_link operations required for it to work.
Signed-off-by: Sven Eckelmann sven@narfation.org --- v2: - rename "new" command to "create" as requested by Linus Luessing and John Harrison
sys.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 145 insertions(+), 27 deletions(-)
diff --git a/sys.c b/sys.c index c18c6b8..cefd53c 100644 --- a/sys.c +++ b/sys.c @@ -199,6 +199,58 @@ static int print_interfaces(char *mesh_iface) return EXIT_SUCCESS; }
+struct count_interfaces_rtnl_arg { + int ifindex; + unsigned int count; +}; + +static int count_interfaces_rtnl_parse(struct nl_msg *msg, void *arg) +{ + struct count_interfaces_rtnl_arg *count_arg = arg; + struct nlattr *attrs[IFLA_MAX + 1]; + struct ifinfomsg *ifm; + int ret; + int master; + + ifm = nlmsg_data(nlmsg_hdr(msg)); + ret = nlmsg_parse(nlmsg_hdr(msg), sizeof(*ifm), attrs, IFLA_MAX, + link_policy); + if (ret < 0) + goto err; + + if (!attrs[IFLA_IFNAME]) + goto err; + + if (!attrs[IFLA_MASTER]) + goto err; + + master = nla_get_u32(attrs[IFLA_MASTER]); + + /* required on older kernels which don't prefilter the results */ + if (master != count_arg->ifindex) + goto err; + + count_arg->count++; + +err: + return NL_OK; +} + +static unsigned int count_interfaces(char *mesh_iface) +{ + struct count_interfaces_rtnl_arg count_arg; + + count_arg.count = 0; + count_arg.ifindex = if_nametoindex(mesh_iface); + if (!count_arg.ifindex) + return 0; + + query_rtnl_link(count_arg.ifindex, count_interfaces_rtnl_parse, + &count_arg); + + return count_arg.count; +} + static int create_interface(const char *mesh_iface) { struct ifinfomsg rt_hdr = { @@ -283,11 +335,54 @@ err_free_msg: return err; }
+static int set_master_interface(const char *iface, unsigned int ifmaster) +{ + struct ifinfomsg rt_hdr = { + .ifi_family = IFLA_UNSPEC, + }; + struct nl_msg *msg; + int err = 0; + int ret; + + msg = nlmsg_alloc_simple(RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK); + if (!msg) { + return -ENOMEM; + } + + ret = nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + ret = nla_put_string(msg, IFLA_IFNAME, iface); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + ret = nla_put_u32(msg, IFLA_MASTER, ifmaster); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + err = netlink_simple_request(msg); + +err_free_msg: + nlmsg_free(msg); + + return err; +} + int interface(char *mesh_iface, int argc, char **argv) { - char *path_buff; - int i, res, optchar; + int i, optchar; int ret; + unsigned int ifindex; + unsigned int ifmaster; + const char *long_op; + unsigned int cnt;
while ((optchar = getopt(argc, argv, "h")) != -1) { switch (optchar) { @@ -363,46 +458,69 @@ int interface(char *mesh_iface, int argc, char **argv) break; }
- path_buff = malloc(PATH_BUFF_LEN); - if (!path_buff) { - fprintf(stderr, "Error - could not allocate path buffer: out of memory ?\n"); - goto err; - } + /* get index of batman-adv interface - or try to create it */ + ifmaster = if_nametoindex(mesh_iface); + if (!ifmaster && argv[1][0] == 'a') { + ret = create_interface(mesh_iface); + if (ret < 0) { + fprintf(stderr, + "Error - failed to create batman-adv interface: %s\n", + strerror(-ret)); + goto err; + }
- for (i = 2; i < argc; i++) { - snprintf(path_buff, PATH_BUFF_LEN, SYS_MESH_IFACE_FMT, argv[i]); + ifmaster = if_nametoindex(mesh_iface); + }
- if (!file_exists(path_buff)) { - snprintf(path_buff, PATH_BUFF_LEN, SYS_IFACE_DIR, argv[i]); + if (!ifmaster) { + ret = -ENODEV; + fprintf(stderr, + "Error - failed to find batman-adv interface: %s\n", + strerror(-ret)); + goto err; + }
- if (!file_exists(path_buff)) { - fprintf(stderr, "Error - interface does not exist: %s\n", argv[i]); - continue; - } + /* make sure that batman-adv is loaded or was loaded by create_interface */ + if (!file_exists(module_ver_path)) { + fprintf(stderr, "Error - batman-adv module has not been loaded\n"); + goto err; + }
- if (!file_exists(module_ver_path)) { - fprintf(stderr, "Error - batman-adv module has not been loaded\n"); - goto err_buff; - } + for (i = 2; i < argc; i++) { + ifindex = if_nametoindex(argv[i]);
- fprintf(stderr, "Error - interface type not supported by batman-adv: %s\n", argv[i]); + if (!ifindex) { + fprintf(stderr, "Error - interface does not exist: %s\n", argv[i]); continue; }
if (argv[1][0] == 'a') - res = write_file("", path_buff, mesh_iface, NULL); + ifindex = ifmaster; else - res = write_file("", path_buff, "none", NULL); + ifindex = 0;
- if (res != EXIT_SUCCESS) - goto err_buff; + ret = set_master_interface(argv[i], ifindex); + if (ret < 0) { + if (argv[1][0] == 'a') + long_op = "add"; + else + long_op = "delete"; + + fprintf(stderr, "Error - failed to %s interface %s: %s\n", + long_op, argv[i], strerror(-ret)); + goto err; + } + } + + /* check if there is no interface left and then destroy mesh_iface */ + if (argv[1][0] == 'd') { + cnt = count_interfaces(mesh_iface); + if (cnt == 0) + destroy_interface(mesh_iface); }
- free(path_buff); return EXIT_SUCCESS;
-err_buff: - free(path_buff); err: return EXIT_FAILURE; }
Arguments may be added between "interface" and the subcommands "add" and "del". Thus is should not be hardcoded which positions of argv the subcommands start and instead the information from getopt should be used to calculate the correct position.
Signed-off-by: Sven Eckelmann sven@narfation.org --- v2: - rename "new" command to "create" as requested by Linus Luessing and John Harrison
sys.c | 51 ++++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-)
diff --git a/sys.c b/sys.c index cefd53c..190fd06 100644 --- a/sys.c +++ b/sys.c @@ -383,6 +383,8 @@ int interface(char *mesh_iface, int argc, char **argv) unsigned int ifmaster; const char *long_op; unsigned int cnt; + int rest_argc; + char **rest_argv;
while ((optchar = getopt(argc, argv, "h")) != -1) { switch (optchar) { @@ -395,38 +397,41 @@ int interface(char *mesh_iface, int argc, char **argv) } }
- if (argc == 1) + rest_argc = argc - optind; + rest_argv = &argv[optind]; + + if (rest_argc == 0) return print_interfaces(mesh_iface);
- if ((strcmp(argv[1], "add") != 0) && (strcmp(argv[1], "a") != 0) && - (strcmp(argv[1], "del") != 0) && (strcmp(argv[1], "d") != 0) && - (strcmp(argv[1], "create") != 0) && (strcmp(argv[1], "c") != 0) && - (strcmp(argv[1], "destroy") != 0) && (strcmp(argv[1], "D") != 0)) { - fprintf(stderr, "Error - unknown argument specified: %s\n", argv[1]); + if ((strcmp(rest_argv[0], "add") != 0) && (strcmp(rest_argv[0], "a") != 0) && + (strcmp(rest_argv[0], "del") != 0) && (strcmp(rest_argv[0], "d") != 0) && + (strcmp(rest_argv[0], "create") != 0) && (strcmp(rest_argv[0], "c") != 0) && + (strcmp(rest_argv[0], "destroy") != 0) && (strcmp(rest_argv[0], "D") != 0)) { + fprintf(stderr, "Error - unknown argument specified: %s\n", rest_argv[0]); interface_usage(); goto err; }
- if (strcmp(argv[1], "destroy") == 0) - argv[1][0] = 'D'; + if (strcmp(rest_argv[0], "destroy") == 0) + rest_argv[0][0] = 'D';
- switch (argv[1][0]) { + switch (rest_argv[0][0]) { case 'a': case 'd': - if (argc == 2) { + if (rest_argc == 1) { fprintf(stderr, "Error - missing interface name(s) after '%s'\n", - argv[1]); + rest_argv[0]); interface_usage(); goto err; } break; case 'c': case 'D': - if (argc != 2) { + if (rest_argc != 1) { fprintf(stderr, "Error - extra parameter after '%s'\n", - argv[1]); + rest_argv[0]); interface_usage(); goto err; } @@ -435,7 +440,7 @@ int interface(char *mesh_iface, int argc, char **argv) break; }
- switch (argv[1][0]) { + switch (rest_argv[0][0]) { case 'c': ret = create_interface(mesh_iface); if (ret < 0) { @@ -460,7 +465,7 @@ int interface(char *mesh_iface, int argc, char **argv)
/* get index of batman-adv interface - or try to create it */ ifmaster = if_nametoindex(mesh_iface); - if (!ifmaster && argv[1][0] == 'a') { + if (!ifmaster && rest_argv[0][0] == 'a') { ret = create_interface(mesh_iface); if (ret < 0) { fprintf(stderr, @@ -486,34 +491,34 @@ int interface(char *mesh_iface, int argc, char **argv) goto err; }
- for (i = 2; i < argc; i++) { - ifindex = if_nametoindex(argv[i]); + for (i = 1; i < rest_argc; i++) { + ifindex = if_nametoindex(rest_argv[i]);
if (!ifindex) { - fprintf(stderr, "Error - interface does not exist: %s\n", argv[i]); + fprintf(stderr, "Error - interface does not exist: %s\n", rest_argv[i]); continue; }
- if (argv[1][0] == 'a') + if (rest_argv[0][0] == 'a') ifindex = ifmaster; else ifindex = 0;
- ret = set_master_interface(argv[i], ifindex); + ret = set_master_interface(rest_argv[i], ifindex); if (ret < 0) { - if (argv[1][0] == 'a') + if (rest_argv[0][0] == 'a') long_op = "add"; else long_op = "delete";
fprintf(stderr, "Error - failed to %s interface %s: %s\n", - long_op, argv[i], strerror(-ret)); + long_op, rest_argv[i], strerror(-ret)); goto err; } }
/* check if there is no interface left and then destroy mesh_iface */ - if (argv[1][0] == 'd') { + if (rest_argv[0][0] == 'd') { cnt = count_interfaces(mesh_iface); if (cnt == 0) destroy_interface(mesh_iface);
Users may not want to lose their configured batman-adv soft-interface when they remove a single interface from it. The default configuration may not working well enough in the network setup of the user and thus it should be possible to avoid that it gets reset to it when a new interface is added after the last one was removed.
This can be done by avoiding automatic creation of an interface when the command "add" is used together with the option "-M". The add would fail when the soft-interface disappeared for some reason and thus the soft-interface would not be created again with the default configuration. But more importantly, the "del" command can be informed with the option "-M" to not try to remove the soft-interface in the first place.
Signed-off-by: Sven Eckelmann sven@narfation.org --- v2: - rename "new" command to "create" as requested by Linus Luessing and John Harrison
man/batctl.8 | 4 +++- sys.c | 12 +++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/man/batctl.8 b/man/batctl.8 index a29d1fb..ef7a16d 100644 --- a/man/batctl.8 +++ b/man/batctl.8 @@ -52,10 +52,12 @@ performances, is also included. .br .TP .I \fBcommands: -.IP "\fBinterface\fP|\fBif\fP [\fBadd\fP|\fBdel iface(s)\fP]" +.IP "\fBinterface\fP|\fBif\fP [\fB-M\fP] [\fBadd\fP|\fBdel iface(s)\fP]" If no parameter is given or the first parameter is neither "add" nor "del" the current interface settings are displayed. In order to add or delete interfaces specify "add" or "del" as first argument and append the interface names you wish to add or delete. Multiple interfaces can be specified. +The "-M" option tells batctl to not automatically create the batman-adv interface on "add" or to destroy it when "del" +removed all interfaces which belonged to it. .IP "\fBinterface\fP|\fBif\fP [\fBcreate\fP|\fBdestroy\fP]" A batman-adv interface without attached interfaces can be created using "create". The parameter "destroy" can be used to free all attached interfaces and remove batman-adv interface. diff --git a/sys.c b/sys.c index 190fd06..2cbccea 100644 --- a/sys.c +++ b/sys.c @@ -22,6 +22,7 @@
#include <unistd.h> #include <stdio.h> +#include <stdbool.h> #include <stdlib.h> #include <string.h> #include <errno.h> @@ -122,6 +123,7 @@ static void interface_usage(void) fprintf(stderr, "Usage: batctl [options] interface [parameters] [add|del iface(s)]\n"); fprintf(stderr, " batctl [options] interface [parameters] [create|destroy]\n"); fprintf(stderr, "parameters:\n"); + fprintf(stderr, " \t -M disable automatic creation/removal of batman-adv interface\n"); fprintf(stderr, " \t -h print this help\n"); }
@@ -385,12 +387,16 @@ int interface(char *mesh_iface, int argc, char **argv) unsigned int cnt; int rest_argc; char **rest_argv; + bool manual_mode = false;
- while ((optchar = getopt(argc, argv, "h")) != -1) { + while ((optchar = getopt(argc, argv, "hM")) != -1) { switch (optchar) { case 'h': interface_usage(); return EXIT_SUCCESS; + case 'M': + manual_mode = true; + break; default: interface_usage(); return EXIT_FAILURE; @@ -465,7 +471,7 @@ int interface(char *mesh_iface, int argc, char **argv)
/* get index of batman-adv interface - or try to create it */ ifmaster = if_nametoindex(mesh_iface); - if (!ifmaster && rest_argv[0][0] == 'a') { + if (!manual_mode && !ifmaster && rest_argv[0][0] == 'a') { ret = create_interface(mesh_iface); if (ret < 0) { fprintf(stderr, @@ -518,7 +524,7 @@ int interface(char *mesh_iface, int argc, char **argv) }
/* check if there is no interface left and then destroy mesh_iface */ - if (rest_argv[0][0] == 'd') { + if (!manual_mode && rest_argv[0][0] == 'd') { cnt = count_interfaces(mesh_iface); if (cnt == 0) destroy_interface(mesh_iface);
The interface command has nothing to do anymore more with all the other configuration in sysfs. Thus all the "interface" command functions should be placed in a separate file.
Signed-off-by: Sven Eckelmann sven@narfation.org --- v2: - rename "new" command to "create" as requested by Linus Luessing and John Harrison
Makefile | 1 + functions.h | 2 + interface.c | 457 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ interface.h | 29 ++++ main.c | 1 + sys.c | 420 ------------------------------------------------------- sys.h | 1 - 7 files changed, 490 insertions(+), 421 deletions(-) create mode 100644 interface.c create mode 100644 interface.h
diff --git a/Makefile b/Makefile index 0cec413..5dc8fe8 100755 --- a/Makefile +++ b/Makefile @@ -30,6 +30,7 @@ OBJ += debug.o OBJ += functions.o OBJ += genl.o OBJ += hash.o +OBJ += interface.o OBJ += ioctl.o OBJ += list-batman.o OBJ += main.o diff --git a/functions.h b/functions.h index 7757731..4c350f8 100644 --- a/functions.h +++ b/functions.h @@ -31,6 +31,8 @@ #define ETH_STR_LEN 17 #define BATMAN_ADV_TAG "batman-adv:"
+#define PATH_BUFF_LEN 200 + /* return time delta from start to end in milliseconds */ void start_timer(void); double end_timer(void); diff --git a/interface.c b/interface.c new file mode 100644 index 0000000..9d5590d --- /dev/null +++ b/interface.c @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2009-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner mareklindner@neomailbox.ch + * + * 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 + * + */ + +#include "interface.h" + +#include <unistd.h> +#include <stdio.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <dirent.h> +#include <net/if.h> +#include <linux/if_link.h> +#include <netlink/netlink.h> +#include <netlink/msg.h> +#include <netlink/attr.h> + +#include "main.h" +#include "sys.h" +#include "functions.h" + +static void interface_usage(void) +{ + fprintf(stderr, "Usage: batctl [options] interface [parameters] [add|del iface(s)]\n"); + fprintf(stderr, " batctl [options] interface [parameters] [create|destroy]\n"); + fprintf(stderr, "parameters:\n"); + fprintf(stderr, " \t -M disable automatic creation/removal of batman-adv interface\n"); + fprintf(stderr, " \t -h print this help\n"); +} + +static struct nla_policy link_policy[IFLA_MAX + 1] = { + [IFLA_IFNAME] = { .type = NLA_STRING, .maxlen = IFNAMSIZ }, + [IFLA_MASTER] = { .type = NLA_U32 }, +}; + +struct print_interfaces_rtnl_arg { + int ifindex; +}; + +static int print_interfaces_rtnl_parse(struct nl_msg *msg, void *arg) +{ + struct print_interfaces_rtnl_arg *print_arg = arg; + struct nlattr *attrs[IFLA_MAX + 1]; + char path_buff[PATH_BUFF_LEN]; + struct ifinfomsg *ifm; + char *ifname; + int ret; + const char *status; + int master; + + ifm = nlmsg_data(nlmsg_hdr(msg)); + ret = nlmsg_parse(nlmsg_hdr(msg), sizeof(*ifm), attrs, IFLA_MAX, + link_policy); + if (ret < 0) + goto err; + + if (!attrs[IFLA_IFNAME]) + goto err; + + if (!attrs[IFLA_MASTER]) + goto err; + + ifname = nla_get_string(attrs[IFLA_IFNAME]); + master = nla_get_u32(attrs[IFLA_MASTER]); + + /* required on older kernels which don't prefilter the results */ + if (master != print_arg->ifindex) + goto err; + + snprintf(path_buff, sizeof(path_buff), SYS_IFACE_STATUS_FMT, ifname); + ret = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0, 0); + if (ret != EXIT_SUCCESS) + status = "<error reading status>\n"; + else + status = line_ptr; + + printf("%s: %s", ifname, status); + + free(line_ptr); + line_ptr = NULL; + +err: + return NL_OK; +} + +static int print_interfaces(char *mesh_iface) +{ + struct print_interfaces_rtnl_arg print_arg; + + if (!file_exists(module_ver_path)) { + fprintf(stderr, "Error - batman-adv module has not been loaded\n"); + return EXIT_FAILURE; + } + + print_arg.ifindex = if_nametoindex(mesh_iface); + if (!print_arg.ifindex) + return EXIT_FAILURE; + + query_rtnl_link(print_arg.ifindex, print_interfaces_rtnl_parse, + &print_arg); + + return EXIT_SUCCESS; +} + +struct count_interfaces_rtnl_arg { + int ifindex; + unsigned int count; +}; + +static int count_interfaces_rtnl_parse(struct nl_msg *msg, void *arg) +{ + struct count_interfaces_rtnl_arg *count_arg = arg; + struct nlattr *attrs[IFLA_MAX + 1]; + struct ifinfomsg *ifm; + int ret; + int master; + + ifm = nlmsg_data(nlmsg_hdr(msg)); + ret = nlmsg_parse(nlmsg_hdr(msg), sizeof(*ifm), attrs, IFLA_MAX, + link_policy); + if (ret < 0) + goto err; + + if (!attrs[IFLA_IFNAME]) + goto err; + + if (!attrs[IFLA_MASTER]) + goto err; + + master = nla_get_u32(attrs[IFLA_MASTER]); + + /* required on older kernels which don't prefilter the results */ + if (master != count_arg->ifindex) + goto err; + + count_arg->count++; + +err: + return NL_OK; +} + +static unsigned int count_interfaces(char *mesh_iface) +{ + struct count_interfaces_rtnl_arg count_arg; + + count_arg.count = 0; + count_arg.ifindex = if_nametoindex(mesh_iface); + if (!count_arg.ifindex) + return 0; + + query_rtnl_link(count_arg.ifindex, count_interfaces_rtnl_parse, + &count_arg); + + return count_arg.count; +} + +static int create_interface(const char *mesh_iface) +{ + struct ifinfomsg rt_hdr = { + .ifi_family = IFLA_UNSPEC, + }; + struct nlattr *linkinfo; + struct nl_msg *msg; + int err = 0; + int ret; + + msg = nlmsg_alloc_simple(RTM_NEWLINK, + NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK); + if (!msg) { + return -ENOMEM; + } + + ret = nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + ret = nla_put_string(msg, IFLA_IFNAME, mesh_iface); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + linkinfo = nla_nest_start(msg, IFLA_LINKINFO); + if (!linkinfo) { + err = -ENOMEM; + goto err_free_msg; + } + + ret = nla_put_string(msg, IFLA_INFO_KIND, "batadv"); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + nla_nest_end(msg, linkinfo); + + err = netlink_simple_request(msg); + +err_free_msg: + nlmsg_free(msg); + + return err; +} + +static int destroy_interface(const char *mesh_iface) +{ + struct ifinfomsg rt_hdr = { + .ifi_family = IFLA_UNSPEC, + }; + struct nl_msg *msg; + int err = 0; + int ret; + + msg = nlmsg_alloc_simple(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK); + if (!msg) { + return -ENOMEM; + } + + ret = nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + ret = nla_put_string(msg, IFLA_IFNAME, mesh_iface); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + err = netlink_simple_request(msg); + +err_free_msg: + nlmsg_free(msg); + + return err; +} + +static int set_master_interface(const char *iface, unsigned int ifmaster) +{ + struct ifinfomsg rt_hdr = { + .ifi_family = IFLA_UNSPEC, + }; + struct nl_msg *msg; + int err = 0; + int ret; + + msg = nlmsg_alloc_simple(RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK); + if (!msg) { + return -ENOMEM; + } + + ret = nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + ret = nla_put_string(msg, IFLA_IFNAME, iface); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + ret = nla_put_u32(msg, IFLA_MASTER, ifmaster); + if (ret < 0) { + err = -ENOMEM; + goto err_free_msg; + } + + err = netlink_simple_request(msg); + +err_free_msg: + nlmsg_free(msg); + + return err; +} + +int interface(char *mesh_iface, int argc, char **argv) +{ + int i, optchar; + int ret; + unsigned int ifindex; + unsigned int ifmaster; + const char *long_op; + unsigned int cnt; + int rest_argc; + char **rest_argv; + bool manual_mode = false; + + while ((optchar = getopt(argc, argv, "hM")) != -1) { + switch (optchar) { + case 'h': + interface_usage(); + return EXIT_SUCCESS; + case 'M': + manual_mode = true; + break; + default: + interface_usage(); + return EXIT_FAILURE; + } + } + + rest_argc = argc - optind; + rest_argv = &argv[optind]; + + if (rest_argc == 0) + return print_interfaces(mesh_iface); + + if ((strcmp(rest_argv[0], "add") != 0) && (strcmp(rest_argv[0], "a") != 0) && + (strcmp(rest_argv[0], "del") != 0) && (strcmp(rest_argv[0], "d") != 0) && + (strcmp(rest_argv[0], "create") != 0) && (strcmp(rest_argv[0], "c") != 0) && + (strcmp(rest_argv[0], "destroy") != 0) && (strcmp(rest_argv[0], "D") != 0)) { + fprintf(stderr, "Error - unknown argument specified: %s\n", rest_argv[0]); + interface_usage(); + goto err; + } + + if (strcmp(rest_argv[0], "destroy") == 0) + rest_argv[0][0] = 'D'; + + switch (rest_argv[0][0]) { + case 'a': + case 'd': + if (rest_argc == 1) { + fprintf(stderr, + "Error - missing interface name(s) after '%s'\n", + rest_argv[0]); + interface_usage(); + goto err; + } + break; + case 'c': + case 'D': + if (rest_argc != 1) { + fprintf(stderr, + "Error - extra parameter after '%s'\n", + rest_argv[0]); + interface_usage(); + goto err; + } + break; + default: + break; + } + + switch (rest_argv[0][0]) { + case 'c': + ret = create_interface(mesh_iface); + if (ret < 0) { + fprintf(stderr, + "Error - failed to add create batman-adv interface: %s\n", + strerror(-ret)); + goto err; + } + return EXIT_SUCCESS; + case 'D': + ret = destroy_interface(mesh_iface); + if (ret < 0) { + fprintf(stderr, + "Error - failed to destroy batman-adv interface: %s\n", + strerror(-ret)); + goto err; + } + return EXIT_SUCCESS; + default: + break; + } + + /* get index of batman-adv interface - or try to create it */ + ifmaster = if_nametoindex(mesh_iface); + if (!manual_mode && !ifmaster && rest_argv[0][0] == 'a') { + ret = create_interface(mesh_iface); + if (ret < 0) { + fprintf(stderr, + "Error - failed to create batman-adv interface: %s\n", + strerror(-ret)); + goto err; + } + + ifmaster = if_nametoindex(mesh_iface); + } + + if (!ifmaster) { + ret = -ENODEV; + fprintf(stderr, + "Error - failed to find batman-adv interface: %s\n", + strerror(-ret)); + goto err; + } + + /* make sure that batman-adv is loaded or was loaded by create_interface */ + if (!file_exists(module_ver_path)) { + fprintf(stderr, "Error - batman-adv module has not been loaded\n"); + goto err; + } + + for (i = 1; i < rest_argc; i++) { + ifindex = if_nametoindex(rest_argv[i]); + + if (!ifindex) { + fprintf(stderr, "Error - interface does not exist: %s\n", rest_argv[i]); + continue; + } + + if (rest_argv[0][0] == 'a') + ifindex = ifmaster; + else + ifindex = 0; + + ret = set_master_interface(rest_argv[i], ifindex); + if (ret < 0) { + if (rest_argv[0][0] == 'a') + long_op = "add"; + else + long_op = "delete"; + + fprintf(stderr, "Error - failed to %s interface %s: %s\n", + long_op, rest_argv[i], strerror(-ret)); + goto err; + } + } + + /* check if there is no interface left and then destroy mesh_iface */ + if (!manual_mode && rest_argv[0][0] == 'd') { + cnt = count_interfaces(mesh_iface); + if (cnt == 0) + destroy_interface(mesh_iface); + } + + return EXIT_SUCCESS; + +err: + return EXIT_FAILURE; +} diff --git a/interface.h b/interface.h new file mode 100644 index 0000000..0ea7bd5 --- /dev/null +++ b/interface.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2009-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner mareklindner@neomailbox.ch + * + * 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 + * + */ + +#ifndef _BATCTL_INTERFACE_H +#define _BATCTL_INTERFACE_H + +#include "main.h" + +int interface(char *mesh_iface, int argc, char **argv); + +#endif diff --git a/main.c b/main.c index 5e1ecc7..e67fc40 100644 --- a/main.c +++ b/main.c @@ -29,6 +29,7 @@ #include "main.h" #include "sys.h" #include "debug.h" +#include "interface.h" #include "ping.h" #include "translate.h" #include "traceroute.h" diff --git a/sys.c b/sys.c index 2cbccea..59cbdae 100644 --- a/sys.c +++ b/sys.c @@ -38,8 +38,6 @@ #include "functions.h" #include "debug.h"
-#define PATH_BUFF_LEN 200 - const char *sysfs_param_enable[] = { "enable", "disable", @@ -118,424 +116,6 @@ const struct settings_data batctl_settings[BATCTL_SETTINGS_NUM] = { }, };
-static void interface_usage(void) -{ - fprintf(stderr, "Usage: batctl [options] interface [parameters] [add|del iface(s)]\n"); - fprintf(stderr, " batctl [options] interface [parameters] [create|destroy]\n"); - fprintf(stderr, "parameters:\n"); - fprintf(stderr, " \t -M disable automatic creation/removal of batman-adv interface\n"); - fprintf(stderr, " \t -h print this help\n"); -} - -static struct nla_policy link_policy[IFLA_MAX + 1] = { - [IFLA_IFNAME] = { .type = NLA_STRING, .maxlen = IFNAMSIZ }, - [IFLA_MASTER] = { .type = NLA_U32 }, -}; - -struct print_interfaces_rtnl_arg { - int ifindex; -}; - -static int print_interfaces_rtnl_parse(struct nl_msg *msg, void *arg) -{ - struct print_interfaces_rtnl_arg *print_arg = arg; - struct nlattr *attrs[IFLA_MAX + 1]; - char path_buff[PATH_BUFF_LEN]; - struct ifinfomsg *ifm; - char *ifname; - int ret; - const char *status; - int master; - - ifm = nlmsg_data(nlmsg_hdr(msg)); - ret = nlmsg_parse(nlmsg_hdr(msg), sizeof(*ifm), attrs, IFLA_MAX, - link_policy); - if (ret < 0) - goto err; - - if (!attrs[IFLA_IFNAME]) - goto err; - - if (!attrs[IFLA_MASTER]) - goto err; - - ifname = nla_get_string(attrs[IFLA_IFNAME]); - master = nla_get_u32(attrs[IFLA_MASTER]); - - /* required on older kernels which don't prefilter the results */ - if (master != print_arg->ifindex) - goto err; - - snprintf(path_buff, sizeof(path_buff), SYS_IFACE_STATUS_FMT, ifname); - ret = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0, 0); - if (ret != EXIT_SUCCESS) - status = "<error reading status>\n"; - else - status = line_ptr; - - printf("%s: %s", ifname, status); - - free(line_ptr); - line_ptr = NULL; - -err: - return NL_OK; -} - -static int print_interfaces(char *mesh_iface) -{ - struct print_interfaces_rtnl_arg print_arg; - - if (!file_exists(module_ver_path)) { - fprintf(stderr, "Error - batman-adv module has not been loaded\n"); - return EXIT_FAILURE; - } - - print_arg.ifindex = if_nametoindex(mesh_iface); - if (!print_arg.ifindex) - return EXIT_FAILURE; - - query_rtnl_link(print_arg.ifindex, print_interfaces_rtnl_parse, - &print_arg); - - return EXIT_SUCCESS; -} - -struct count_interfaces_rtnl_arg { - int ifindex; - unsigned int count; -}; - -static int count_interfaces_rtnl_parse(struct nl_msg *msg, void *arg) -{ - struct count_interfaces_rtnl_arg *count_arg = arg; - struct nlattr *attrs[IFLA_MAX + 1]; - struct ifinfomsg *ifm; - int ret; - int master; - - ifm = nlmsg_data(nlmsg_hdr(msg)); - ret = nlmsg_parse(nlmsg_hdr(msg), sizeof(*ifm), attrs, IFLA_MAX, - link_policy); - if (ret < 0) - goto err; - - if (!attrs[IFLA_IFNAME]) - goto err; - - if (!attrs[IFLA_MASTER]) - goto err; - - master = nla_get_u32(attrs[IFLA_MASTER]); - - /* required on older kernels which don't prefilter the results */ - if (master != count_arg->ifindex) - goto err; - - count_arg->count++; - -err: - return NL_OK; -} - -static unsigned int count_interfaces(char *mesh_iface) -{ - struct count_interfaces_rtnl_arg count_arg; - - count_arg.count = 0; - count_arg.ifindex = if_nametoindex(mesh_iface); - if (!count_arg.ifindex) - return 0; - - query_rtnl_link(count_arg.ifindex, count_interfaces_rtnl_parse, - &count_arg); - - return count_arg.count; -} - -static int create_interface(const char *mesh_iface) -{ - struct ifinfomsg rt_hdr = { - .ifi_family = IFLA_UNSPEC, - }; - struct nlattr *linkinfo; - struct nl_msg *msg; - int err = 0; - int ret; - - msg = nlmsg_alloc_simple(RTM_NEWLINK, - NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK); - if (!msg) { - return -ENOMEM; - } - - ret = nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO); - if (ret < 0) { - err = -ENOMEM; - goto err_free_msg; - } - - ret = nla_put_string(msg, IFLA_IFNAME, mesh_iface); - if (ret < 0) { - err = -ENOMEM; - goto err_free_msg; - } - - linkinfo = nla_nest_start(msg, IFLA_LINKINFO); - if (!linkinfo) { - err = -ENOMEM; - goto err_free_msg; - } - - ret = nla_put_string(msg, IFLA_INFO_KIND, "batadv"); - if (ret < 0) { - err = -ENOMEM; - goto err_free_msg; - } - - nla_nest_end(msg, linkinfo); - - err = netlink_simple_request(msg); - -err_free_msg: - nlmsg_free(msg); - - return err; -} - -static int destroy_interface(const char *mesh_iface) -{ - struct ifinfomsg rt_hdr = { - .ifi_family = IFLA_UNSPEC, - }; - struct nl_msg *msg; - int err = 0; - int ret; - - msg = nlmsg_alloc_simple(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK); - if (!msg) { - return -ENOMEM; - } - - ret = nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO); - if (ret < 0) { - err = -ENOMEM; - goto err_free_msg; - } - - ret = nla_put_string(msg, IFLA_IFNAME, mesh_iface); - if (ret < 0) { - err = -ENOMEM; - goto err_free_msg; - } - - err = netlink_simple_request(msg); - -err_free_msg: - nlmsg_free(msg); - - return err; -} - -static int set_master_interface(const char *iface, unsigned int ifmaster) -{ - struct ifinfomsg rt_hdr = { - .ifi_family = IFLA_UNSPEC, - }; - struct nl_msg *msg; - int err = 0; - int ret; - - msg = nlmsg_alloc_simple(RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK); - if (!msg) { - return -ENOMEM; - } - - ret = nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO); - if (ret < 0) { - err = -ENOMEM; - goto err_free_msg; - } - - ret = nla_put_string(msg, IFLA_IFNAME, iface); - if (ret < 0) { - err = -ENOMEM; - goto err_free_msg; - } - - ret = nla_put_u32(msg, IFLA_MASTER, ifmaster); - if (ret < 0) { - err = -ENOMEM; - goto err_free_msg; - } - - err = netlink_simple_request(msg); - -err_free_msg: - nlmsg_free(msg); - - return err; -} - -int interface(char *mesh_iface, int argc, char **argv) -{ - int i, optchar; - int ret; - unsigned int ifindex; - unsigned int ifmaster; - const char *long_op; - unsigned int cnt; - int rest_argc; - char **rest_argv; - bool manual_mode = false; - - while ((optchar = getopt(argc, argv, "hM")) != -1) { - switch (optchar) { - case 'h': - interface_usage(); - return EXIT_SUCCESS; - case 'M': - manual_mode = true; - break; - default: - interface_usage(); - return EXIT_FAILURE; - } - } - - rest_argc = argc - optind; - rest_argv = &argv[optind]; - - if (rest_argc == 0) - return print_interfaces(mesh_iface); - - if ((strcmp(rest_argv[0], "add") != 0) && (strcmp(rest_argv[0], "a") != 0) && - (strcmp(rest_argv[0], "del") != 0) && (strcmp(rest_argv[0], "d") != 0) && - (strcmp(rest_argv[0], "create") != 0) && (strcmp(rest_argv[0], "c") != 0) && - (strcmp(rest_argv[0], "destroy") != 0) && (strcmp(rest_argv[0], "D") != 0)) { - fprintf(stderr, "Error - unknown argument specified: %s\n", rest_argv[0]); - interface_usage(); - goto err; - } - - if (strcmp(rest_argv[0], "destroy") == 0) - rest_argv[0][0] = 'D'; - - switch (rest_argv[0][0]) { - case 'a': - case 'd': - if (rest_argc == 1) { - fprintf(stderr, - "Error - missing interface name(s) after '%s'\n", - rest_argv[0]); - interface_usage(); - goto err; - } - break; - case 'c': - case 'D': - if (rest_argc != 1) { - fprintf(stderr, - "Error - extra parameter after '%s'\n", - rest_argv[0]); - interface_usage(); - goto err; - } - break; - default: - break; - } - - switch (rest_argv[0][0]) { - case 'c': - ret = create_interface(mesh_iface); - if (ret < 0) { - fprintf(stderr, - "Error - failed to create batman-adv interface: %s\n", - strerror(-ret)); - goto err; - } - return EXIT_SUCCESS; - case 'D': - ret = destroy_interface(mesh_iface); - if (ret < 0) { - fprintf(stderr, - "Error - failed to destroy batman-adv interface: %s\n", - strerror(-ret)); - goto err; - } - return EXIT_SUCCESS; - default: - break; - } - - /* get index of batman-adv interface - or try to create it */ - ifmaster = if_nametoindex(mesh_iface); - if (!manual_mode && !ifmaster && rest_argv[0][0] == 'a') { - ret = create_interface(mesh_iface); - if (ret < 0) { - fprintf(stderr, - "Error - failed to create batman-adv interface: %s\n", - strerror(-ret)); - goto err; - } - - ifmaster = if_nametoindex(mesh_iface); - } - - if (!ifmaster) { - ret = -ENODEV; - fprintf(stderr, - "Error - failed to find batman-adv interface: %s\n", - strerror(-ret)); - goto err; - } - - /* make sure that batman-adv is loaded or was loaded by create_interface */ - if (!file_exists(module_ver_path)) { - fprintf(stderr, "Error - batman-adv module has not been loaded\n"); - goto err; - } - - for (i = 1; i < rest_argc; i++) { - ifindex = if_nametoindex(rest_argv[i]); - - if (!ifindex) { - fprintf(stderr, "Error - interface does not exist: %s\n", rest_argv[i]); - continue; - } - - if (rest_argv[0][0] == 'a') - ifindex = ifmaster; - else - ifindex = 0; - - ret = set_master_interface(rest_argv[i], ifindex); - if (ret < 0) { - if (rest_argv[0][0] == 'a') - long_op = "add"; - else - long_op = "delete"; - - fprintf(stderr, "Error - failed to %s interface %s: %s\n", - long_op, rest_argv[i], strerror(-ret)); - goto err; - } - } - - /* check if there is no interface left and then destroy mesh_iface */ - if (!manual_mode && rest_argv[0][0] == 'd') { - cnt = count_interfaces(mesh_iface); - if (cnt == 0) - destroy_interface(mesh_iface); - } - - return EXIT_SUCCESS; - -err: - return EXIT_FAILURE; -} - static void log_level_usage(void) { fprintf(stderr, "Usage: batctl [options] loglevel [parameters] [level[ level[ level]]...]\n"); diff --git a/sys.h b/sys.h index da2769d..be9480e 100644 --- a/sys.h +++ b/sys.h @@ -70,7 +70,6 @@ extern const char *sysfs_param_enable[]; extern const char *sysfs_param_server[]; extern const struct settings_data batctl_settings[BATCTL_SETTINGS_NUM];
-int interface(char *mesh_iface, int argc, char **argv); int handle_loglevel(char *mesh_iface, int argc, char **argv); int handle_sys_setting(char *mesh_iface, int setting, int argc, char **argv); int handle_gw_setting(char *mesh_iface, int argc, char **argv);
The check_mesh_iface* functions are not used to modify anything in sysfs. So they are better placed in the common/shared functions file than in sys.c.
Signed-off-by: Sven Eckelmann sven@narfation.org --- v2: - no change
functions.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ functions.h | 2 ++ sys.c | 56 -------------------------------------------------------- sys.h | 2 -- 4 files changed, 61 insertions(+), 58 deletions(-)
diff --git a/functions.c b/functions.c index 962efcf..f9feca4 100644 --- a/functions.c +++ b/functions.c @@ -32,6 +32,7 @@ #include <string.h> #include <errno.h> #include <fcntl.h> +#include <dirent.h> #include <sys/time.h> #include <netinet/in.h> #include <stdint.h> @@ -56,6 +57,8 @@ #include "debugfs.h" #include "netlink.h"
+#define PATH_BUFF_LEN 200 + static struct timeval start_time; static char *host_name; char *line_ptr = NULL; @@ -1011,3 +1014,59 @@ err_free_sock:
return err; } + +int check_mesh_iface(char *mesh_iface) +{ + char *base_dev = NULL; + char path_buff[PATH_BUFF_LEN]; + int ret = -1, vid; + 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); + else + snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, mesh_iface); + + /* try to open the mesh sys directory */ + dir = opendir(path_buff); + if (!dir) + goto out; + + closedir(dir); + + ret = 0; +out: + if (base_dev) + free(base_dev); + + return ret; +} + +int check_mesh_iface_ownership(char *mesh_iface, char *hard_iface) +{ + char path_buff[PATH_BUFF_LEN]; + int res; + + /* check if this device actually belongs to the mesh interface */ + snprintf(path_buff, sizeof(path_buff), SYS_MESH_IFACE_FMT, hard_iface); + res = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0, 0); + if (res != EXIT_SUCCESS) { + fprintf(stderr, "Error - the directory '%s' could not be read: %s\n", + path_buff, strerror(errno)); + fprintf(stderr, "Is the batman-adv module loaded and sysfs mounted ?\n"); + return EXIT_FAILURE; + } + + if (line_ptr[strlen(line_ptr) - 1] == '\n') + line_ptr[strlen(line_ptr) - 1] = '\0'; + + if (strcmp(line_ptr, mesh_iface) != 0) { + fprintf(stderr, "Error - interface %s is part of batman network %s, not %s\n", + hard_iface, line_ptr, mesh_iface); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/functions.h b/functions.h index 4c350f8..e413d6b 100644 --- a/functions.h +++ b/functions.h @@ -50,6 +50,8 @@ 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 check_mesh_iface_ownership(char *mesh_iface, char *hard_iface);
int print_routing_algos(void); extern char *line_ptr; diff --git a/sys.c b/sys.c index 59cbdae..b524340 100644 --- a/sys.c +++ b/sys.c @@ -511,59 +511,3 @@ free_buff: out: return res; } - -int check_mesh_iface(char *mesh_iface) -{ - char *base_dev = NULL; - char path_buff[PATH_BUFF_LEN]; - int ret = -1, vid; - 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); - else - snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, mesh_iface); - - /* try to open the mesh sys directory */ - dir = opendir(path_buff); - if (!dir) - goto out; - - closedir(dir); - - ret = 0; -out: - if (base_dev) - free(base_dev); - - return ret; -} - -int check_mesh_iface_ownership(char *mesh_iface, char *hard_iface) -{ - char path_buff[PATH_BUFF_LEN]; - int res; - - /* check if this device actually belongs to the mesh interface */ - snprintf(path_buff, sizeof(path_buff), SYS_MESH_IFACE_FMT, hard_iface); - res = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0, 0); - if (res != EXIT_SUCCESS) { - fprintf(stderr, "Error - the directory '%s' could not be read: %s\n", - path_buff, strerror(errno)); - fprintf(stderr, "Is the batman-adv module loaded and sysfs mounted ?\n"); - return EXIT_FAILURE; - } - - if (line_ptr[strlen(line_ptr) - 1] == '\n') - line_ptr[strlen(line_ptr) - 1] = '\0'; - - if (strcmp(line_ptr, mesh_iface) != 0) { - fprintf(stderr, "Error - interface %s is part of batman network %s, not %s\n", - hard_iface, line_ptr, mesh_iface); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} diff --git a/sys.h b/sys.h index be9480e..1365e76 100644 --- a/sys.h +++ b/sys.h @@ -74,7 +74,5 @@ int handle_loglevel(char *mesh_iface, int argc, char **argv); int handle_sys_setting(char *mesh_iface, int setting, int argc, char **argv); int handle_gw_setting(char *mesh_iface, int argc, char **argv); int handle_ra_setting(int argc, char **argv); -int check_mesh_iface(char *mesh_iface); -int check_mesh_iface_ownership(char *mesh_iface, char *hard_iface);
#endif
b.a.t.m.a.n@lists.open-mesh.org