[1/2] alfred: vis: Use rtnl to query list of hardifs of meshif

Message ID 20190619193810.16698-1-sven@narfation.org (mailing list archive)
State Accepted, archived
Commit a34f044de561ce90f67b5760059f818bfb35b449
Delegated to: Simon Wunderlich
Headers
Series [1/2] alfred: vis: Use rtnl to query list of hardifs of meshif |

Commit Message

Sven Eckelmann June 19, 2019, 7:38 p.m. UTC
  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 better to use the same way for both retrieving the list of
interfaces and modifying the list of interfaces.

Also the sysfs files are deprecated and cause warnings when access:

  batman_adv: [Deprecated]: batadv-vis (pid 832) Use of sysfs file "mesh_iface".
  Use batadv genl family instead

In worst case, the file doesn't even exist when batman-adv was compiled
without sysfs support.

Reported-by: Linus Lüssing <linus.luessing@c0d3.blue>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
 vis/vis.c | 170 +++++++++++++++++++++++++++++++++++++++---------------
 vis/vis.h |   1 -
 2 files changed, 123 insertions(+), 48 deletions(-)
  

Patch

diff --git a/vis/vis.c b/vis/vis.c
index beaeca1..37956b1 100644
--- a/vis/vis.c
+++ b/vis/vis.c
@@ -372,70 +372,146 @@  static void clear_lists(struct globals *globals)
 	}
 }
 
-static int register_interfaces(struct globals *globals)
+static int query_rtnl_link(int ifindex, nl_recvmsg_msg_cb_t func, void *arg)
 {
-	DIR *iface_base_dir;
-	struct dirent *iface_dir;
-	char *path_buff, *file_content;
-	char *content_newline;
+	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;
 
-	path_buff = malloc(PATH_BUFF_LEN);
-	if (!path_buff) {
-		perror("Error - could not allocate path buffer");
-		goto err;
+	sock = nl_socket_alloc();
+	if (!sock)
+		return -ENOMEM;
+
+	ret = nl_connect(sock, NETLINK_ROUTE);
+	if (ret < 0) {
+		err = -ENOMEM;
+		goto err_free_sock;
 	}
 
-	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;
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!cb) {
+		err = -ENOMEM;
+		goto err_free_sock;
 	}
 
-	while ((iface_dir = readdir(iface_base_dir)) != NULL) {
-		snprintf(path_buff, PATH_BUFF_LEN, SYS_MESH_IFACE_FMT, iface_dir->d_name);
-		file_content = read_file(path_buff);
-		if (!file_content)
-			continue;
+	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, func, arg);
 
-		if (file_content[strlen(file_content) - 1] == '\n')
-			file_content[strlen(file_content) - 1] = '\0';
+	msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP);
+	if (!msg) {
+		err = -ENOMEM;
+		goto err_free_cb;
+	}
 
-		if (strcmp(file_content, "none") == 0)
-			goto free_line;
+	ret = nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO);
+	if (ret < 0) {
+		err = -ENOMEM;
+		goto err_free_msg;
+	}
 
-		if (strcmp(file_content, globals->interface) != 0)
-			goto free_line;
+	ret = nla_put_u32(msg, IFLA_MASTER, ifindex);
+	if (ret < 0) {
+		err = -ENOMEM;
+		goto err_free_msg;
+	}
 
-		free(file_content);
-		file_content = NULL;
+	ret = nl_send_auto_complete(sock, msg);
+	if (ret < 0)
+		goto err_free_msg;
 
-		snprintf(path_buff, PATH_BUFF_LEN, SYS_IFACE_STATUS_FMT, iface_dir->d_name);
-		file_content = read_file(path_buff);
-		if (!file_content)
-			continue;
+	nl_recvmsgs(sock, cb);
 
-		content_newline = strstr(file_content, "\n");
-		if (content_newline)
-			*content_newline = '\0';
+err_free_msg:
+	nlmsg_free(msg);
+err_free_cb:
+	nl_cb_put(cb);
+err_free_sock:
+	nl_socket_free(sock);
 
-		if (strcmp(file_content, "active") == 0)
-			get_if_index_byname(globals, iface_dir->d_name);
+	return err;
+}
 
-free_line:
-		free(file_content);
-		file_content = NULL;
-	}
+struct register_interfaces_rtnl_arg {
+	struct globals *globals;
+	int ifindex;
+};
 
-	free(path_buff);
-	closedir(iface_base_dir);
-	return EXIT_SUCCESS;
+static struct nla_policy link_policy[IFLA_MAX + 1] = {
+	[IFLA_IFNAME] = { .type = NLA_STRING, .maxlen = IFNAMSIZ },
+	[IFLA_MASTER] = { .type = NLA_U32 },
+};
+
+static int register_interfaces_rtnl_parse(struct nl_msg *msg, void *arg)
+{
+	struct register_interfaces_rtnl_arg *register_arg = arg;
+	struct nlattr *attrs[IFLA_MAX + 1];
+	char path_buff[PATH_BUFF_LEN];
+	struct ifinfomsg *ifm;
+	char *content_newline;
+	char *file_content;
+	char *ifname;
+	int master;
+	int ret;
+
+	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 != register_arg->ifindex)
+		goto err;
+
+	snprintf(path_buff, PATH_BUFF_LEN, SYS_IFACE_STATUS_FMT, ifname);
+	file_content = read_file(path_buff);
+	if (!file_content)
+		goto free_file;
+
+	content_newline = strstr(file_content, "\n");
+	if (content_newline)
+		*content_newline = '\0';
+
+	if (strcmp(file_content, "active") != 0)
+		goto err;
+
+	get_if_index_byname(register_arg->globals, ifname);
 
-err_buff:
-	free(path_buff);
+free_file:
+	free(file_content);
+	file_content = NULL;
 err:
-	return EXIT_FAILURE;
+	return NL_OK;
+}
+
+static int register_interfaces(struct globals *globals)
+{
+	struct register_interfaces_rtnl_arg register_arg = {
+		.globals = globals,
+	};
+
+	register_arg.ifindex = if_nametoindex(globals->interface);
+	if (!globals->interface)
+		return EXIT_FAILURE;
+
+
+	query_rtnl_link(register_arg.ifindex, register_interfaces_rtnl_parse,
+			&register_arg);
+
+	return EXIT_SUCCESS;
 }
 
 static const int parse_orig_list_mandatory[] = {
diff --git a/vis/vis.h b/vis/vis.h
index 178406c..36bdecc 100644
--- a/vis/vis.h
+++ b/vis/vis.h
@@ -25,7 +25,6 @@ 
 
 #define SYS_IFACE_PATH				"/sys/class/net"
 #define DEBUG_BATIF_PATH_FMT			"%s/batman_adv/%s"
-#define SYS_MESH_IFACE_FMT			SYS_IFACE_PATH"/%s/batman_adv/mesh_iface"
 #define SYS_IFACE_STATUS_FMT			SYS_IFACE_PATH"/%s/batman_adv/iface_status"