All of lore.kernel.org
 help / color / mirror / Atom feed
* [B.A.T.M.A.N.] [PATCH 0/7] batctl: rtnetlink interface manipulation
@ 2016-07-13 15:29 Sven Eckelmann
  2016-07-13 15:30 ` [B.A.T.M.A.N.] [PATCH 1/7] batctl: Use rtnl to query list of softif devices Sven Eckelmann
  0 siblings, 1 reply; 13+ messages in thread
From: Sven Eckelmann @ 2016-07-13 15:29 UTC (permalink / raw)
  To: b.a.t.m.a.n

[-- Attachment #1: Type: text/plain, Size: 2723 bytes --]

Hi,

the sysfs file mesh_iface 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 
interfaces is rtnetlink which is used by different tools like iproute2 (ip 
link, ip addr, ...) or netifd. sysfs still exists but has to use workers which 
delay the actual add/del to a later point.

This patchset now moves batctl to rtnetlink instead of the sysfs-file 
mesh_iface. This should work fine since this is supported by batman-adv (in 
Linux) since Linux v3.10 (batman-adv v2013.2).

This patchset also introduces two new interface subcommands called "new" and 
"destroy". "new" 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.

It is now also possible to tell batctl to not automatically create a
batman-adv interface when an interface is attached. But more important is this 
option to disable the automatic removal of a batman-adv interface when all 
attached interfaces were removed. This is useful when a number of interfaces 
should be added/removed without accidentally loosing the current configuration 
of the interface. Of course, we should also accept the related patch for 
batman-adv [1].

I've also added two patches with some minor cleanup because it was dealing 
with code in the same file with similar context.

This patchset is build on top of the netlink patchset currently waiting to be 
applied.

Kind regards,
	Sven

[1] https://patchwork.open-mesh.org/patch/16499/


Sven Eckelmann (7):
  batctl: Use rtnl to query list of softif devices
  batctl: Add command to create/destroy batman-adv interface
  batctl: Use rtnl to add/remove interfaces
  batctl: Parse interface arguments relative to last parsed option
  batctl: Allow to disable automatic interface new/destroy
  batctl: Move interface command to extra file
  batctl: Move check_mesh_iface* to functions.c

 Makefile     |   1 +
 functions.c  | 181 +++++++++++++++++++++++
 functions.h  |  10 +-
 interface.c  | 457 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 interface.h  |  29 ++++
 main.c       |   1 +
 man/batctl.8 |   7 +-
 sys.c        | 215 +---------------------------
 sys.h        |   3 -
 9 files changed, 690 insertions(+), 214 deletions(-)
 create mode 100644 interface.c
 create mode 100644 interface.h

-- 
2.8.1


[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [B.A.T.M.A.N.] [PATCH 1/7] batctl: Use rtnl to query list of softif devices
  2016-07-13 15:29 [B.A.T.M.A.N.] [PATCH 0/7] batctl: rtnetlink interface manipulation Sven Eckelmann
@ 2016-07-13 15:30 ` Sven Eckelmann
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 2/7] batctl: Add command to create/destroy batman-adv interface Sven Eckelmann
                     ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Sven Eckelmann @ 2016-07-13 15:30 UTC (permalink / raw)
  To: b.a.t.m.a.n

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>
---
 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)
-- 
2.8.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [B.A.T.M.A.N.] [PATCH 2/7] batctl: Add command to create/destroy batman-adv interface
  2016-07-13 15:30 ` [B.A.T.M.A.N.] [PATCH 1/7] batctl: Use rtnl to query list of softif devices Sven Eckelmann
@ 2016-07-13 15:30   ` Sven Eckelmann
  2016-09-20 14:24     ` Linus Lüssing
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 3/7] batctl: Use rtnl to add/remove interfaces Sven Eckelmann
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Sven Eckelmann @ 2016-07-13 15:30 UTC (permalink / raw)
  To: b.a.t.m.a.n

The command "new" 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>
---
 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..8dcf18a 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 [\fBnew\fP|\fBdestroy\fP]"
+A batman-adv interface without attached interfaces can be created using "new". 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..252864b 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] [new|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 new_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], "new") != 0) && (strcmp(argv[1], "n") != 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 'n':
+	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 'n':
+		ret = new_interface(mesh_iface);
+		if (ret < 0) {
+			fprintf(stderr,
+				"Error - failed to add new 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);
-- 
2.8.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [B.A.T.M.A.N.] [PATCH 3/7] batctl: Use rtnl to add/remove interfaces
  2016-07-13 15:30 ` [B.A.T.M.A.N.] [PATCH 1/7] batctl: Use rtnl to query list of softif devices Sven Eckelmann
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 2/7] batctl: Add command to create/destroy batman-adv interface Sven Eckelmann
@ 2016-07-13 15:30   ` Sven Eckelmann
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 4/7] batctl: Parse interface arguments relative to last parsed option Sven Eckelmann
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Sven Eckelmann @ 2016-07-13 15:30 UTC (permalink / raw)
  To: b.a.t.m.a.n

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>
---
 sys.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 145 insertions(+), 27 deletions(-)

diff --git a/sys.c b/sys.c
index 252864b..ac78d37 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 new_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 = new_interface(mesh_iface);
+		if (ret < 0) {
+			fprintf(stderr,
+				"Error - failed to add new 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 new_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;
 }
-- 
2.8.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [B.A.T.M.A.N.] [PATCH 4/7] batctl: Parse interface arguments relative to last parsed option
  2016-07-13 15:30 ` [B.A.T.M.A.N.] [PATCH 1/7] batctl: Use rtnl to query list of softif devices Sven Eckelmann
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 2/7] batctl: Add command to create/destroy batman-adv interface Sven Eckelmann
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 3/7] batctl: Use rtnl to add/remove interfaces Sven Eckelmann
@ 2016-07-13 15:30   ` Sven Eckelmann
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 5/7] batctl: Allow to disable automatic interface new/destroy Sven Eckelmann
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Sven Eckelmann @ 2016-07-13 15:30 UTC (permalink / raw)
  To: b.a.t.m.a.n

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>
---
 sys.c | 51 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 28 insertions(+), 23 deletions(-)

diff --git a/sys.c b/sys.c
index ac78d37..7cd2690 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], "new") != 0) && (strcmp(argv[1], "n") != 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], "new") != 0) && (strcmp(rest_argv[0], "n") != 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 'n':
 	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 'n':
 		ret = new_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 = new_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);
-- 
2.8.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [B.A.T.M.A.N.] [PATCH 5/7] batctl: Allow to disable automatic interface new/destroy
  2016-07-13 15:30 ` [B.A.T.M.A.N.] [PATCH 1/7] batctl: Use rtnl to query list of softif devices Sven Eckelmann
                     ` (2 preceding siblings ...)
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 4/7] batctl: Parse interface arguments relative to last parsed option Sven Eckelmann
@ 2016-07-13 15:30   ` Sven Eckelmann
  2016-09-20 14:29     ` Linus Lüssing
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 6/7] batctl: Move interface command to extra file Sven Eckelmann
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 7/7] batctl: Move check_mesh_iface* to functions.c Sven Eckelmann
  5 siblings, 1 reply; 13+ messages in thread
From: Sven Eckelmann @ 2016-07-13 15:30 UTC (permalink / raw)
  To: b.a.t.m.a.n

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>
---
 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 8dcf18a..0d77546 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 [\fBnew\fP|\fBdestroy\fP]"
 A batman-adv interface without attached interfaces can be created using "new". 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 7cd2690..88dd39f 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] [new|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 = new_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);
-- 
2.8.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [B.A.T.M.A.N.] [PATCH 6/7] batctl: Move interface command to extra file
  2016-07-13 15:30 ` [B.A.T.M.A.N.] [PATCH 1/7] batctl: Use rtnl to query list of softif devices Sven Eckelmann
                     ` (3 preceding siblings ...)
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 5/7] batctl: Allow to disable automatic interface new/destroy Sven Eckelmann
@ 2016-07-13 15:30   ` Sven Eckelmann
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 7/7] batctl: Move check_mesh_iface* to functions.c Sven Eckelmann
  5 siblings, 0 replies; 13+ messages in thread
From: Sven Eckelmann @ 2016-07-13 15:30 UTC (permalink / raw)
  To: b.a.t.m.a.n

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>
---
 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..7abc80e
--- /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] [new|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 new_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], "new") != 0) && (strcmp(rest_argv[0], "n") != 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 'n':
+	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 'n':
+		ret = new_interface(mesh_iface);
+		if (ret < 0) {
+			fprintf(stderr,
+				"Error - failed to add new 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 = new_interface(mesh_iface);
+		if (ret < 0) {
+			fprintf(stderr,
+				"Error - failed to add new 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 new_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 88dd39f..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] [new|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 new_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], "new") != 0) && (strcmp(rest_argv[0], "n") != 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 'n':
-	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 'n':
-		ret = new_interface(mesh_iface);
-		if (ret < 0) {
-			fprintf(stderr,
-				"Error - failed to add new 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 = new_interface(mesh_iface);
-		if (ret < 0) {
-			fprintf(stderr,
-				"Error - failed to add new 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 new_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);
-- 
2.8.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [B.A.T.M.A.N.] [PATCH 7/7] batctl: Move check_mesh_iface* to functions.c
  2016-07-13 15:30 ` [B.A.T.M.A.N.] [PATCH 1/7] batctl: Use rtnl to query list of softif devices Sven Eckelmann
                     ` (4 preceding siblings ...)
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 6/7] batctl: Move interface command to extra file Sven Eckelmann
@ 2016-07-13 15:30   ` Sven Eckelmann
  5 siblings, 0 replies; 13+ messages in thread
From: Sven Eckelmann @ 2016-07-13 15:30 UTC (permalink / raw)
  To: b.a.t.m.a.n

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>
---
 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
-- 
2.8.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [B.A.T.M.A.N.] [PATCH 2/7] batctl: Add command to create/destroy batman-adv interface
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 2/7] batctl: Add command to create/destroy batman-adv interface Sven Eckelmann
@ 2016-09-20 14:24     ` Linus Lüssing
  2016-09-20 15:43       ` Sven Eckelmann
  0 siblings, 1 reply; 13+ messages in thread
From: Linus Lüssing @ 2016-09-20 14:24 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Wed, Jul 13, 2016 at 05:30:17PM +0200, Sven Eckelmann wrote:
> The command "new" 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.

Like in the title of this mail, maybe naming the commands
"create" and "destroy" instead of "new"/"destroy"?

The former sounds slightly more antonymic to me.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [B.A.T.M.A.N.] [PATCH 5/7] batctl: Allow to disable automatic interface new/destroy
  2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 5/7] batctl: Allow to disable automatic interface new/destroy Sven Eckelmann
@ 2016-09-20 14:29     ` Linus Lüssing
  2016-09-20 15:36       ` Sven Eckelmann
  0 siblings, 1 reply; 13+ messages in thread
From: Linus Lüssing @ 2016-09-20 14:29 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Wed, Jul 13, 2016 at 05:30:20PM +0200, Sven Eckelmann wrote:
> 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.

Currently wondering... have you thought about maybe
memorizing when a batman-adv interface was created via the new
"new" command? And in that case then transparently avoiding the automatic
destruction.

Would be one less parameter to memorize for the user then.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [B.A.T.M.A.N.] [PATCH 5/7] batctl: Allow to disable automatic interface new/destroy
  2016-09-20 14:29     ` Linus Lüssing
@ 2016-09-20 15:36       ` Sven Eckelmann
  0 siblings, 0 replies; 13+ messages in thread
From: Sven Eckelmann @ 2016-09-20 15:36 UTC (permalink / raw)
  To: b.a.t.m.a.n

[-- Attachment #1: Type: text/plain, Size: 1217 bytes --]

On Dienstag, 20. September 2016 16:29:02 CEST Linus Lüssing wrote:
[...]
> > 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.
> 
> Currently wondering... have you thought about maybe
> memorizing when a batman-adv interface was created via the new
> "new" command? And in that case then transparently avoiding the automatic
> destruction.
> 
> Would be one less parameter to memorize for the user then.

batctl would have to remember this to work and batctl is no program which is 
running all the time. So it has to use temporary files... no.

One point here is to get rid of the batman-adv only files for creation/
destruction of itnerfaces and use the standard rtnl netlink. So I don't want 
to create a new interface which does this in the kernel which supports your 
idea.

Kind regards,
	Sven

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [B.A.T.M.A.N.] [PATCH 2/7] batctl: Add command to create/destroy batman-adv interface
  2016-09-20 14:24     ` Linus Lüssing
@ 2016-09-20 15:43       ` Sven Eckelmann
  2016-09-21  5:59         ` jmh8
  0 siblings, 1 reply; 13+ messages in thread
From: Sven Eckelmann @ 2016-09-20 15:43 UTC (permalink / raw)
  To: b.a.t.m.a.n

[-- Attachment #1: Type: text/plain, Size: 649 bytes --]

On Dienstag, 20. September 2016 16:24:18 CEST Linus Lüssing wrote:
> On Wed, Jul 13, 2016 at 05:30:17PM +0200, Sven Eckelmann wrote:
> > The command "new" 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.
> 
> Like in the title of this mail, maybe naming the commands
> "create" and "destroy" instead of "new"/"destroy"?
> 
> The former sounds slightly more antonymic to me.

Has anyone else an opinion about that? I personally would be fine with 
"create" instead of "new".

Kind regards,
	Sven

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [B.A.T.M.A.N.] [PATCH 2/7] batctl: Add command to create/destroy batman-adv interface
  2016-09-20 15:43       ` Sven Eckelmann
@ 2016-09-21  5:59         ` jmh8
  0 siblings, 0 replies; 13+ messages in thread
From: jmh8 @ 2016-09-21  5:59 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking


Hi All,

    I too like create/destroy.

    John

On Tue, 20 Sep 2016, Sven Eckelmann wrote:

> On Dienstag, 20. September 2016 16:24:18 CEST Linus L?ssing wrote:
>> On Wed, Jul 13, 2016 at 05:30:17PM +0200, Sven Eckelmann wrote:
>>> The command "new" 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.
>>
>> Like in the title of this mail, maybe naming the commands
>> "create" and "destroy" instead of "new"/"destroy"?
>>
>> The former sounds slightly more antonymic to me.
>
> Has anyone else an opinion about that? I personally would be fine with
> "create" instead of "new".
>
> Kind regards,
> 	Sven

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2016-09-21  5:59 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-13 15:29 [B.A.T.M.A.N.] [PATCH 0/7] batctl: rtnetlink interface manipulation Sven Eckelmann
2016-07-13 15:30 ` [B.A.T.M.A.N.] [PATCH 1/7] batctl: Use rtnl to query list of softif devices Sven Eckelmann
2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 2/7] batctl: Add command to create/destroy batman-adv interface Sven Eckelmann
2016-09-20 14:24     ` Linus Lüssing
2016-09-20 15:43       ` Sven Eckelmann
2016-09-21  5:59         ` jmh8
2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 3/7] batctl: Use rtnl to add/remove interfaces Sven Eckelmann
2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 4/7] batctl: Parse interface arguments relative to last parsed option Sven Eckelmann
2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 5/7] batctl: Allow to disable automatic interface new/destroy Sven Eckelmann
2016-09-20 14:29     ` Linus Lüssing
2016-09-20 15:36       ` Sven Eckelmann
2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 6/7] batctl: Move interface command to extra file Sven Eckelmann
2016-07-13 15:30   ` [B.A.T.M.A.N.] [PATCH 7/7] batctl: Move check_mesh_iface* to functions.c Sven Eckelmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.