The content of batman_adv/iface_status ends with a newline. Thus register_interfaces has to make sure that it only compares the first line without the \n when comparing with the status string.
Signed-off-by: Sven Eckelmann sven@narfation.org --- vis/vis.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/vis/vis.c b/vis/vis.c index 4d494bc..7eab781 100644 --- a/vis/vis.c +++ b/vis/vis.c @@ -257,6 +257,7 @@ static int register_interfaces(struct globals *globals) DIR *iface_base_dir; struct dirent *iface_dir; char *path_buff, *file_content; + char *content_newline;
path_buff = malloc(PATH_BUFF_LEN); if (!path_buff) { @@ -295,6 +296,10 @@ static int register_interfaces(struct globals *globals) if (!file_content) continue;
+ content_newline = strstr(file_content, "\n"); + if (content_newline) + *content_newline = '\0'; + if (strcmp(file_content, "active") == 0) get_if_index(globals, iface_dir->d_name);
From: Sven Eckelmann sven.eckelmann@open-mesh.com
The line of objects which are required to compile alfred gets longer and becomes harder to read. Instead save each object on its own line to make it easier to edit and easier to solve conflicts when multiple patches modify the list of objects.
Signed-off-by: Sven Eckelmann sven.eckelmann@open-mesh.com --- Makefile | 12 +++++++++++- gpsd/Makefile | 2 +- vis/Makefile | 3 ++- 3 files changed, 14 insertions(+), 3 deletions(-) mode change 100644 => 100755 Makefile mode change 100644 => 100755 gpsd/Makefile mode change 100644 => 100755 vis/Makefile
diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 index 939e9f8..1c364f7 --- a/Makefile +++ b/Makefile @@ -20,7 +20,17 @@
# alfred build BINARY_NAME = alfred -OBJ = main.o server.o client.o netsock.o send.o recv.o hash.o unix_sock.o util.o debugfs.o batadv_query.o +OBJ += batadv_query.o +OBJ += client.o +OBJ += debugfs.o +OBJ += hash.o +OBJ += main.o +OBJ += netsock.o +OBJ += recv.o +OBJ += send.o +OBJ += server.o +OBJ += unix_sock.o +OBJ += util.o MANPAGE = man/alfred.8
# alfred flags and options diff --git a/gpsd/Makefile b/gpsd/Makefile old mode 100644 new mode 100755 index 72e4445..bae5660 --- a/gpsd/Makefile +++ b/gpsd/Makefile @@ -20,7 +20,7 @@
# alfred-gpsd build BINARY_NAME = alfred-gpsd -OBJ = alfred-gpsd.o +OBJ += alfred-gpsd.o MANPAGE = man/alfred-gpsd.8
# alfred flags and options diff --git a/vis/Makefile b/vis/Makefile old mode 100644 new mode 100755 index accd1fa..52ca981 --- a/vis/Makefile +++ b/vis/Makefile @@ -20,7 +20,8 @@
# batadv-vis build BINARY_NAME = batadv-vis -OBJ = vis.o debugfs.o +OBJ += debugfs.o +OBJ += vis.o MANPAGE = man/batadv-vis.8
# batadv-vis flags and options
Signed-off-by: Sven Eckelmann sven@narfation.org --- Makefile | 35 ++++++++-- README | 2 + batman_adv.h | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ netlink.c | 84 ++++++++++++++++++++++ netlink.h | 30 ++++++++ vis/Makefile | 30 ++++++++ vis/batman_adv.h | 1 + vis/netlink.c | 1 + vis/netlink.h | 1 + 9 files changed, 386 insertions(+), 6 deletions(-) create mode 100644 batman_adv.h create mode 100644 netlink.c create mode 100644 netlink.h create mode 120000 vis/batman_adv.h create mode 120000 vis/netlink.c create mode 120000 vis/netlink.h
diff --git a/Makefile b/Makefile index 1c364f7..6daa904 100755 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ OBJ += client.o OBJ += debugfs.o OBJ += hash.o OBJ += main.o +OBJ += netlink.o OBJ += netsock.o OBJ += recv.o OBJ += send.o @@ -83,14 +84,36 @@ ifneq ($(CONFIG_ALFRED_GPSD),n) GPSD_INSTALL=gpsd-install endif
-ifneq ($(CONFIG_ALFRED_CAPABILITIES),n) - ifeq ($(origin PKG_CONFIG), undefined) - PKG_CONFIG = pkg-config - ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null),) - $(error $(PKG_CONFIG) not found) - endif +ifeq ($(origin PKG_CONFIG), undefined) + PKG_CONFIG = pkg-config + ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null),) + $(error $(PKG_CONFIG) not found) + endif +endif + +ifeq ($(origin LIBNL_CFLAGS) $(origin LIBNL_LDLIBS), undefined undefined) + LIBNL_NAME ?= libnl-3.0 + ifeq ($(shell $(PKG_CONFIG) --modversion $(LIBNL_NAME) 2>/dev/null),) + $(error No $(LIBNL_NAME) development libraries found!) endif + LIBNL_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBNL_NAME)) + LIBNL_LDLIBS += $(shell $(PKG_CONFIG) --libs $(LIBNL_NAME)) +endif +CFLAGS += $(LIBNL_CFLAGS) +LDLIBS += $(LIBNL_LDLIBS)
+ifeq ($(origin LIBNL_GENL_CFLAGS) $(origin LIBNL_GENL_LDLIBS), undefined undefined) + LIBNL_GENL_NAME ?= libnl-genl-3.0 + ifeq ($(shell $(PKG_CONFIG) --modversion $(LIBNL_GENL_NAME) 2>/dev/null),) + $(error No $(LIBNL_GENL_NAME) development libraries found!) + endif + LIBNL_GENL_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBNL_GENL_NAME)) + LIBNL_GENL_LDLIBS += $(shell $(PKG_CONFIG) --libs $(LIBNL_GENL_NAME)) +endif +CFLAGS += $(LIBNL_GENL_CFLAGS) +LDLIBS += $(LIBNL_GENL_LDLIBS) + +ifneq ($(CONFIG_ALFRED_CAPABILITIES),n) ifeq ($(origin LIBCAP_CFLAGS) $(origin LIBCAP_LDLIBS), undefined undefined) LIBCAP_NAME ?= libcap ifeq ($(shell $(PKG_CONFIG) --modversion $(LIBCAP_NAME) 2>/dev/null),) diff --git a/README b/README index fbca7d1..2a015b8 100644 --- a/README +++ b/README @@ -28,6 +28,8 @@ Compilation alfred depends on: * librt (usually part of libc) * IPv6 support in the kernel/host system + * libnl-3 - support for netlink sockets + * libnl-3-genl - support for generic netlink messages
and optionally: * libgps - if you want to distribute GPS information diff --git a/batman_adv.h b/batman_adv.h new file mode 100644 index 0000000..37157d0 --- /dev/null +++ b/batman_adv.h @@ -0,0 +1,208 @@ +/* Copyright (C) 2016 B.A.T.M.A.N. contributors: + * + * Matthias Schiffer + * + * 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, see http://www.gnu.org/licenses/. + */ + +#ifndef _UAPI_LINUX_BATMAN_ADV_H_ +#define _UAPI_LINUX_BATMAN_ADV_H_ + +#define BATADV_NL_NAME "batadv" + +#define BATADV_NL_MCAST_GROUP_TPMETER "tpmeter" + +/** + * enum batadv_tt_client_flags - TT client specific flags + * @BATADV_TT_CLIENT_DEL: the client has to be deleted from the table + * @BATADV_TT_CLIENT_ROAM: the client roamed to/from another node and the new + * update telling its new real location has not been received/sent yet + * @BATADV_TT_CLIENT_WIFI: this client is connected through a wifi interface. + * This information is used by the "AP Isolation" feature + * @BATADV_TT_CLIENT_ISOLA: this client is considered "isolated". This + * information is used by the Extended Isolation feature + * @BATADV_TT_CLIENT_NOPURGE: this client should never be removed from the table + * @BATADV_TT_CLIENT_NEW: this client has been added to the local table but has + * not been announced yet + * @BATADV_TT_CLIENT_PENDING: this client is marked for removal but it is kept + * in the table for one more originator interval for consistency purposes + * @BATADV_TT_CLIENT_TEMP: this global client has been detected to be part of + * the network but no nnode has already announced it + * + * Bits from 0 to 7 are called _remote flags_ because they are sent on the wire. + * Bits from 8 to 15 are called _local flags_ because they are used for local + * computations only. + * + * Bits from 4 to 7 - a subset of remote flags - are ensured to be in sync with + * the other nodes in the network. To achieve this goal these flags are included + * in the TT CRC computation. + */ +enum batadv_tt_client_flags { + BATADV_TT_CLIENT_DEL = (1 << 0), + BATADV_TT_CLIENT_ROAM = (1 << 1), + BATADV_TT_CLIENT_WIFI = (1 << 4), + BATADV_TT_CLIENT_ISOLA = (1 << 5), + BATADV_TT_CLIENT_NOPURGE = (1 << 8), + BATADV_TT_CLIENT_NEW = (1 << 9), + BATADV_TT_CLIENT_PENDING = (1 << 10), + BATADV_TT_CLIENT_TEMP = (1 << 11), +}; + +/** + * enum batadv_nl_attrs - batman-adv netlink attributes + * + * @BATADV_ATTR_UNSPEC: unspecified attribute to catch errors + * @BATADV_ATTR_VERSION: batman-adv version string + * @BATADV_ATTR_ALGO_NAME: name of routing algorithm + * @BATADV_ATTR_MESH_IFINDEX: index of the batman-adv interface + * @BATADV_ATTR_MESH_IFNAME: name of the batman-adv interface + * @BATADV_ATTR_MESH_ADDRESS: mac address of the batman-adv interface + * @BATADV_ATTR_HARD_IFINDEX: index of the non-batman-adv interface + * @BATADV_ATTR_HARD_IFNAME: name of the non-batman-adv interface + * @BATADV_ATTR_HARD_ADDRESS: mac address of the non-batman-adv interface + * @BATADV_ATTR_ORIG_ADDRESS: originator mac address + * @BATADV_ATTR_TPMETER_RESULT: result of run (see batadv_tp_meter_status) + * @BATADV_ATTR_TPMETER_TEST_TIME: time (msec) the run took + * @BATADV_ATTR_TPMETER_BYTES: amount of acked bytes during run + * @BATADV_ATTR_TPMETER_COOKIE: session cookie to match tp_meter session + * @BATADV_ATTR_PAD: attribute used for padding for 64-bit alignment + * @BATADV_ATTR_ACTIVE: Flag indicating if the hard interface is active + * @BATADV_ATTR_TT_ADDRESS: Client MAC address + * @BATADV_ATTR_TT_TTVN: Translation table version + * @BATADV_ATTR_TT_LAST_TTVN: Previous translation table version + * @BATADV_ATTR_TT_CRC32: CRC32 over translation table + * @BATADV_ATTR_TT_VID: VLAN ID + * @BATADV_ATTR_TT_FLAGS: Translation table client flags + * @BATADV_ATTR_FLAG_BEST: Flags indicating entry is the best + * @BATADV_ATTR_LAST_SEEN_MSECS: Time in milliseconds since last seen + * @BATADV_ATTR_NEIGH_ADDRESS: Neighbour MAC address + * @BATADV_ATTR_TQ: TQ to neighbour + * @BATADV_ATTR_THROUGHPUT: Estimated throughput to Neighbour + * @BATADV_ATTR_BANDWIDTH_UP: Reported uplink bandwidth + * @BATADV_ATTR_BANDWIDTH_DOWN: Reported downlink bandwidth + * @BATADV_ATTR_ROUTER: Gateway router MAC address + * @BATADV_ATTR_BLA_OWN: Flag indicating own originator + * @BATADV_ATTR_BLA_ADDRESS: Bridge loop avoidance claim MAC address + * @BATADV_ATTR_BLA_VID: BLA VLAN ID + * @BATADV_ATTR_BLA_BACKBONE: BLA gateway originator MAC address + * @BATADV_ATTR_BLA_CRC: BLA CRC + * @__BATADV_ATTR_AFTER_LAST: internal use + * @NUM_BATADV_ATTR: total number of batadv_nl_attrs available + * @BATADV_ATTR_MAX: highest attribute number currently defined + */ +enum batadv_nl_attrs { + BATADV_ATTR_UNSPEC, + BATADV_ATTR_VERSION, + BATADV_ATTR_ALGO_NAME, + BATADV_ATTR_MESH_IFINDEX, + BATADV_ATTR_MESH_IFNAME, + BATADV_ATTR_MESH_ADDRESS, + BATADV_ATTR_HARD_IFINDEX, + BATADV_ATTR_HARD_IFNAME, + BATADV_ATTR_HARD_ADDRESS, + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_TPMETER_RESULT, + BATADV_ATTR_TPMETER_TEST_TIME, + BATADV_ATTR_TPMETER_BYTES, + BATADV_ATTR_TPMETER_COOKIE, + BATADV_ATTR_PAD, + BATADV_ATTR_ACTIVE, + BATADV_ATTR_TT_ADDRESS, + BATADV_ATTR_TT_TTVN, + BATADV_ATTR_TT_LAST_TTVN, + BATADV_ATTR_TT_CRC32, + BATADV_ATTR_TT_VID, + BATADV_ATTR_TT_FLAGS, + BATADV_ATTR_FLAG_BEST, + BATADV_ATTR_LAST_SEEN_MSECS, + BATADV_ATTR_NEIGH_ADDRESS, + BATADV_ATTR_TQ, + BATADV_ATTR_THROUGHPUT, + BATADV_ATTR_BANDWIDTH_UP, + BATADV_ATTR_BANDWIDTH_DOWN, + BATADV_ATTR_ROUTER, + BATADV_ATTR_BLA_OWN, + BATADV_ATTR_BLA_ADDRESS, + BATADV_ATTR_BLA_VID, + BATADV_ATTR_BLA_BACKBONE, + BATADV_ATTR_BLA_CRC, + /* add attributes above here, update the policy in netlink.c */ + __BATADV_ATTR_AFTER_LAST, + NUM_BATADV_ATTR = __BATADV_ATTR_AFTER_LAST, + BATADV_ATTR_MAX = __BATADV_ATTR_AFTER_LAST - 1 +}; + +/** + * enum batadv_nl_commands - supported batman-adv netlink commands + * + * @BATADV_CMD_UNSPEC: unspecified command to catch errors + * @BATADV_CMD_GET_MESH_INFO: Query basic information about batman-adv device + * @BATADV_CMD_TP_METER: Start a tp meter session + * @BATADV_CMD_TP_METER_CANCEL: Cancel a tp meter session + * @BATADV_CMD_GET_ROUTING_ALGOS: Query the list of routing algorithms. + * @BATADV_CMD_GET_HARDIFS: Query list of hard interfaces + * @BATADV_CMD_GET_TRANSTABLE_LOCAL: Query list of local translations + * @BATADV_CMD_GET_TRANSTABLE_GLOBAL Query list of global translations + * @BATADV_CMD_GET_ORIGINATORS: Query list of originators + * @BATADV_CMD_GET_NEIGHBORS: Query list of neighbours + * @BATADV_CMD_GET_GATEWAYS: Query list of gateways + * @BATADV_CMD_GET_BLA_CLAIM: Query list of bridge loop avoidance claims + * @BATADV_CMD_GET_BLA_BACKBONE: Query list of bridge loop avoidance backbones + * @__BATADV_CMD_AFTER_LAST: internal use + * @BATADV_CMD_MAX: highest used command number + */ +enum batadv_nl_commands { + BATADV_CMD_UNSPEC, + BATADV_CMD_GET_MESH_INFO, + BATADV_CMD_TP_METER, + BATADV_CMD_TP_METER_CANCEL, + BATADV_CMD_GET_ROUTING_ALGOS, + BATADV_CMD_GET_HARDIFS, + BATADV_CMD_GET_TRANSTABLE_LOCAL, + BATADV_CMD_GET_TRANSTABLE_GLOBAL, + BATADV_CMD_GET_ORIGINATORS, + BATADV_CMD_GET_NEIGHBORS, + BATADV_CMD_GET_GATEWAYS, + BATADV_CMD_GET_BLA_CLAIM, + BATADV_CMD_GET_BLA_BACKBONE, + /* add new commands above here */ + __BATADV_CMD_AFTER_LAST, + BATADV_CMD_MAX = __BATADV_CMD_AFTER_LAST - 1 +}; + +/** + * enum batadv_tp_meter_reason - reason of a tp meter test run stop + * @BATADV_TP_REASON_COMPLETE: sender finished tp run + * @BATADV_TP_REASON_CANCEL: sender was stopped during run + * @BATADV_TP_REASON_DST_UNREACHABLE: receiver could not be reached or didn't + * answer + * @BATADV_TP_REASON_RESEND_LIMIT: (unused) sender retry reached limit + * @BATADV_TP_REASON_ALREADY_ONGOING: test to or from the same node already + * ongoing + * @BATADV_TP_REASON_MEMORY_ERROR: test was stopped due to low memory + * @BATADV_TP_REASON_CANT_SEND: failed to send via outgoing interface + * @BATADV_TP_REASON_TOO_MANY: too many ongoing sessions + */ +enum batadv_tp_meter_reason { + BATADV_TP_REASON_COMPLETE = 3, + BATADV_TP_REASON_CANCEL = 4, + /* error status >= 128 */ + BATADV_TP_REASON_DST_UNREACHABLE = 128, + BATADV_TP_REASON_RESEND_LIMIT = 129, + BATADV_TP_REASON_ALREADY_ONGOING = 130, + BATADV_TP_REASON_MEMORY_ERROR = 131, + BATADV_TP_REASON_CANT_SEND = 132, + BATADV_TP_REASON_TOO_MANY = 133, +}; + +#endif /* _UAPI_LINUX_BATMAN_ADV_H_ */ diff --git a/netlink.c b/netlink.c new file mode 100644 index 0000000..d9c1f55 --- /dev/null +++ b/netlink.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2009-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner mareklindner@neomailbox.ch, Andrew Lunn andrew@lunn.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 "netlink.h" + +#include <netlink/netlink.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/ctrl.h> +#include <net/ethernet.h> + +#include "batman_adv.h" + +struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { + [BATADV_ATTR_VERSION] = { .type = NLA_STRING }, + [BATADV_ATTR_ALGO_NAME] = { .type = NLA_STRING }, + [BATADV_ATTR_MESH_IFINDEX] = { .type = NLA_U32 }, + [BATADV_ATTR_MESH_IFNAME] = { .type = NLA_STRING, + .maxlen = IFNAMSIZ }, + [BATADV_ATTR_MESH_ADDRESS] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_HARD_IFINDEX] = { .type = NLA_U32 }, + [BATADV_ATTR_HARD_IFNAME] = { .type = NLA_STRING, + .maxlen = IFNAMSIZ }, + [BATADV_ATTR_HARD_ADDRESS] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_ORIG_ADDRESS] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_TPMETER_RESULT] = { .type = NLA_U8 }, + [BATADV_ATTR_TPMETER_TEST_TIME] = { .type = NLA_U32 }, + [BATADV_ATTR_TPMETER_BYTES] = { .type = NLA_U64 }, + [BATADV_ATTR_TPMETER_COOKIE] = { .type = NLA_U32 }, + [BATADV_ATTR_PAD] = { .type = NLA_UNSPEC }, + [BATADV_ATTR_ACTIVE] = { .type = NLA_FLAG }, + [BATADV_ATTR_TT_ADDRESS] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_TT_TTVN] = { .type = NLA_U8 }, + [BATADV_ATTR_TT_LAST_TTVN] = { .type = NLA_U8 }, + [BATADV_ATTR_TT_CRC32] = { .type = NLA_U32 }, + [BATADV_ATTR_TT_VID] = { .type = NLA_U16 }, + [BATADV_ATTR_TT_FLAGS] = { .type = NLA_U32 }, + [BATADV_ATTR_FLAG_BEST] = { .type = NLA_FLAG }, + [BATADV_ATTR_LAST_SEEN_MSECS] = { .type = NLA_U32 }, + [BATADV_ATTR_NEIGH_ADDRESS] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_TQ] = { .type = NLA_U8 }, + [BATADV_ATTR_THROUGHPUT] = { .type = NLA_U32 }, + [BATADV_ATTR_BANDWIDTH_UP] = { .type = NLA_U32 }, + [BATADV_ATTR_BANDWIDTH_DOWN] = { .type = NLA_U32 }, + [BATADV_ATTR_ROUTER] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_BLA_OWN] = { .type = NLA_FLAG }, + [BATADV_ATTR_BLA_ADDRESS] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_BLA_VID] = { .type = NLA_U16 }, + [BATADV_ATTR_BLA_BACKBONE] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_BLA_CRC] = { .type = NLA_U16 }, +}; diff --git a/netlink.h b/netlink.h new file mode 100644 index 0000000..f903563 --- /dev/null +++ b/netlink.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2009-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner mareklindner@neomailbox.ch, Andrew Lunn andrew@lunn.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 _ALFRED_NETLINK_H +#define _ALFRED_NETLINK_H + +#include <netlink/genl/genl.h> +#include <netlink/genl/ctrl.h> + +extern struct nla_policy batadv_netlink_policy[]; + +#endif /* _ALFRED_NETLINK_H */ diff --git a/vis/Makefile b/vis/Makefile index 52ca981..fd99f49 100755 --- a/vis/Makefile +++ b/vis/Makefile @@ -21,6 +21,7 @@ # batadv-vis build BINARY_NAME = batadv-vis OBJ += debugfs.o +OBJ += netlink.o OBJ += vis.o MANPAGE = man/batadv-vis.8
@@ -59,6 +60,35 @@ ifneq ($(REVISION),) CPPFLAGS += -DSOURCE_VERSION="$(REVISION)" endif
+ifeq ($(origin PKG_CONFIG), undefined) + PKG_CONFIG = pkg-config + ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null),) + $(error $(PKG_CONFIG) not found) + endif +endif + +ifeq ($(origin LIBNL_CFLAGS) $(origin LIBNL_LDLIBS), undefined undefined) + LIBNL_NAME ?= libnl-3.0 + ifeq ($(shell $(PKG_CONFIG) --modversion $(LIBNL_NAME) 2>/dev/null),) + $(error No $(LIBNL_NAME) development libraries found!) + endif + LIBNL_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBNL_NAME)) + LIBNL_LDLIBS += $(shell $(PKG_CONFIG) --libs $(LIBNL_NAME)) +endif +CFLAGS += $(LIBNL_CFLAGS) +LDLIBS += $(LIBNL_LDLIBS) + +ifeq ($(origin LIBNL_GENL_CFLAGS) $(origin LIBNL_GENL_LDLIBS), undefined undefined) + LIBNL_GENL_NAME ?= libnl-genl-3.0 + ifeq ($(shell $(PKG_CONFIG) --modversion $(LIBNL_GENL_NAME) 2>/dev/null),) + $(error No $(LIBNL_GENL_NAME) development libraries found!) + endif + LIBNL_GENL_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBNL_GENL_NAME)) + LIBNL_GENL_LDLIBS += $(shell $(PKG_CONFIG) --libs $(LIBNL_GENL_NAME)) +endif +CFLAGS += $(LIBNL_GENL_CFLAGS) +LDLIBS += $(LIBNL_GENL_LDLIBS) + # default target all: $(BINARY_NAME)
diff --git a/vis/batman_adv.h b/vis/batman_adv.h new file mode 120000 index 0000000..72222e9 --- /dev/null +++ b/vis/batman_adv.h @@ -0,0 +1 @@ +../batman_adv.h \ No newline at end of file diff --git a/vis/netlink.c b/vis/netlink.c new file mode 120000 index 0000000..06d13cc --- /dev/null +++ b/vis/netlink.c @@ -0,0 +1 @@ +../netlink.c \ No newline at end of file diff --git a/vis/netlink.h b/vis/netlink.h new file mode 120000 index 0000000..c7a63b5 --- /dev/null +++ b/vis/netlink.h @@ -0,0 +1 @@ +../netlink.h \ No newline at end of file
diff --git a/vis/batman_adv.h b/vis/batman_adv.h new file mode 120000 index 0000000..72222e9 --- /dev/null +++ b/vis/batman_adv.h @@ -0,0 +1 @@ +../batman_adv.h \ No newline at end of file diff --git a/vis/netlink.c b/vis/netlink.c new file mode 120000 index 0000000..06d13cc --- /dev/null +++ b/vis/netlink.c @@ -0,0 +1 @@ +../netlink.c \ No newline at end of file diff --git a/vis/netlink.h b/vis/netlink.h new file mode 120000 index 0000000..c7a63b5 --- /dev/null +++ b/vis/netlink.h @@ -0,0 +1 @@ +../netlink.h \ No newline at end of file
I was wondering why you use symlinks here, while we pull in the other headers from their original paths (../packet.h, ../list.h).
We should probably keep the header handling consistent. What would be your opinion whether we should use relative paths or symlinks?
Thanks, Simon
On Donnerstag, 21. Juli 2016 17:58:07 CEST Simon Wunderlich wrote:
diff --git a/vis/batman_adv.h b/vis/batman_adv.h new file mode 120000 index 0000000..72222e9 --- /dev/null +++ b/vis/batman_adv.h @@ -0,0 +1 @@ +../batman_adv.h \ No newline at end of file diff --git a/vis/netlink.c b/vis/netlink.c new file mode 120000 index 0000000..06d13cc --- /dev/null +++ b/vis/netlink.c @@ -0,0 +1 @@ +../netlink.c \ No newline at end of file diff --git a/vis/netlink.h b/vis/netlink.h new file mode 120000 index 0000000..c7a63b5 --- /dev/null +++ b/vis/netlink.h @@ -0,0 +1 @@ +../netlink.h \ No newline at end of file
I was wondering why you use symlinks here, while we pull in the other headers from their original paths (../packet.h, ../list.h).
We should probably keep the header handling consistent. What would be your opinion whether we should use relative paths or symlinks?
This doesn't work for netlink.c because it would break during parallel builds. And netlink.c requires batman_adv.h which must be in the search path for it.
Possible would be to symlink netlink.c and netlink.h and Add "-I.." to CPPFLAGS of batadv-vis.
Kind regards, Sven
The batman_adv netlink family requires CAP_NET_ADMIN capabilities to query the debugging tables.
Signed-off-by: Sven Eckelmann sven@narfation.org --- README | 8 ++++---- batadv_query.c | 3 +++ main.c | 12 ++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/README b/README index 2a015b8..bc1c3bc 100644 --- a/README +++ b/README @@ -277,11 +277,11 @@ Operations requiring special capabilities: * accessing the debugfs filesystem
The first operation can still be executed when the admin grants the special -capability CAP_NET_RAW to anyone executing the alfred binary. The unix socket -can also be moved using the parameter '-u' to a different directory which can -be accessed by the user. +capability CAP_NET_RAW+CAP_NET_ADMIN to anyone executing the alfred binary. +The unix socket can also be moved using the parameter '-u' to a different +directory which can be accessed by the user.
- $ sudo setcap cap_net_raw+ep alfred + $ sudo setcap cap_net_admin,cap_net_raw+ep alfred $ ./alfred -u alfred.sock -i eth0
The user running alfred must still be in a group which is allowed to access diff --git a/batadv_query.c b/batadv_query.c index a5fa565..d917242 100644 --- a/batadv_query.c +++ b/batadv_query.c @@ -29,6 +29,9 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#ifdef CONFIG_ALFRED_CAPABILITIES +#include <sys/capability.h> +#endif #include <sys/types.h> #include "debugfs.h"
diff --git a/main.c b/main.c index 52dca97..9cab705 100644 --- a/main.c +++ b/main.c @@ -77,6 +77,7 @@ static int reduce_capabilities(void) cap_t cap_new; cap_flag_value_t cap_flag; cap_value_t cap_net_raw = CAP_NET_RAW; + cap_value_t cap_net_admin = CAP_NET_ADMIN;
/* get current process capabilities */ cap_cur = cap_get_proc(); @@ -105,6 +106,17 @@ static int reduce_capabilities(void) } }
+ cap_flag = CAP_CLEAR; + cap_get_flag(cap_cur, CAP_NET_ADMIN, CAP_PERMITTED, &cap_flag); + if (cap_flag != CAP_CLEAR) { + ret = cap_set_flag(cap_new, CAP_PERMITTED, 1, &cap_net_admin, + CAP_SET); + if (ret < 0) { + perror("cap_set_flag"); + goto out; + } + } + /* set minimal capabilities field */ ret = cap_set_proc(cap_new); if (ret < 0) {
The debugfs tables cannot be used by the alfred in network namespaces. These have to use netlink. Thus the translate_mac should be less tightly linked to the debugfs tables to implement optional netlink support.
Signed-off-by: Sven Eckelmann sven@narfation.org --- batadv_query.c | 45 ++++++++++++++++++++++++++++++++++----------- batadv_query.h | 2 +- 2 files changed, 35 insertions(+), 12 deletions(-)
diff --git a/batadv_query.c b/batadv_query.c index d917242..b0679fc 100644 --- a/batadv_query.c +++ b/batadv_query.c @@ -125,7 +125,9 @@ int batadv_interface_check(const char *mesh_iface) return 0; }
-struct ether_addr *translate_mac(const char *mesh_iface, struct ether_addr *mac) +static int translate_mac_debugfs(const char *mesh_iface, + const struct ether_addr *mac, + struct ether_addr *mac_out) { enum { tg_start, @@ -133,24 +135,21 @@ struct ether_addr *translate_mac(const char *mesh_iface, struct ether_addr *mac) tg_via, tg_originator, } pos; - char full_path[MAX_PATH + 1]; - static struct ether_addr in_mac; - struct ether_addr *mac_result, *mac_tmp; + char full_path[MAX_PATH+1]; + struct ether_addr *mac_tmp; FILE *f = NULL; size_t len = 0; char *line = NULL; char *input, *saveptr, *token; int line_invalid; - - memcpy(&in_mac, mac, sizeof(in_mac)); - mac_result = &in_mac; + bool found = false;
debugfs_make_path(DEBUG_BATIF_PATH_FMT "/" DEBUG_TRANSTABLE_GLOBAL, mesh_iface, full_path, sizeof(full_path));
f = fopen(full_path, "r"); if (!f) - goto out; + return -EOPNOTSUPP;
while (getline(&line, &len, f) != -1) { line_invalid = 0; @@ -169,8 +168,8 @@ struct ether_addr *translate_mac(const char *mesh_iface, struct ether_addr *mac) break; case tg_mac: mac_tmp = ether_aton(token); - if (!mac_tmp || memcmp(mac_tmp, &in_mac, - sizeof(in_mac)) != 0) + if (!mac_tmp || memcmp(mac_tmp, mac, + ETH_ALEN) != 0) line_invalid = 1; else pos = tg_via; @@ -184,7 +183,8 @@ struct ether_addr *translate_mac(const char *mesh_iface, struct ether_addr *mac) if (!mac_tmp) { line_invalid = 1; } else { - mac_result = mac_tmp; + memcpy(mac_out, mac_tmp, ETH_ALEN); + found = true; goto out; } break; @@ -199,6 +199,29 @@ out: if (f) fclose(f); free(line); + + if (found) + return 0; + else + return -ENOENT; +} + +struct ether_addr *translate_mac(const char *mesh_iface, + const struct ether_addr *mac) +{ + struct ether_addr in_mac; + static struct ether_addr out_mac; + struct ether_addr *mac_result; + + /* input mac has to be copied because it could be in the shared + * ether_aton buffer + */ + memcpy(&in_mac, mac, sizeof(in_mac)); + memcpy(&out_mac, mac, sizeof(out_mac)); + mac_result = &out_mac; + + translate_mac_debugfs(mesh_iface, &in_mac, mac_result); + return mac_result; }
diff --git a/batadv_query.h b/batadv_query.h index d9660bc..320203b 100644 --- a/batadv_query.h +++ b/batadv_query.h @@ -25,7 +25,7 @@ #include <netinet/in.h>
struct ether_addr *translate_mac(const char *mesh_iface, - struct ether_addr *mac); + const struct ether_addr *mac); uint8_t get_tq(const char *mesh_iface, struct ether_addr *mac); int batadv_interface_check(const char *mesh_iface); int mac_to_ipv6(const struct ether_addr *mac, struct in6_addr *addr);
The debugfs entries are only available on the main network namespace. All other network namespaces have to fall back to netlink to read the global translation table.
alfred has therefore try to access the translation table via netlink and try to fall back to the debugfs table in case the batman-adv module doesn't support BATADV_CMD_GET_TRANSTABLE_GLOBAL.
Signed-off-by: Sven Eckelmann sven@narfation.org --- batadv_query.c | 49 +++++++++++++- netlink.c | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netlink.h | 23 +++++++ 3 files changed, 269 insertions(+), 1 deletion(-)
diff --git a/batadv_query.c b/batadv_query.c index b0679fc..9082576 100644 --- a/batadv_query.c +++ b/batadv_query.c @@ -33,12 +33,53 @@ #include <sys/capability.h> #endif #include <sys/types.h> + +#include "netlink.h" #include "debugfs.h"
#define DEBUG_BATIF_PATH_FMT "%s/batman_adv/%s" #define DEBUG_TRANSTABLE_GLOBAL "transtable_global" #define DEBUG_ORIGINATORS "originators"
+static int enable_net_admin_capability(int enable) +{ + int ret = 0; + +#ifdef CONFIG_ALFRED_CAPABILITIES + cap_t cap_cur; + cap_flag_value_t cap_flag; + cap_value_t cap_net_admin = CAP_NET_ADMIN; + + if (enable) + cap_flag = CAP_SET; + else + cap_flag = CAP_CLEAR; + + cap_cur = cap_get_proc(); + if (!cap_cur) { + perror("cap_get_proc"); + return -1; + } + + ret = cap_set_flag(cap_cur, CAP_EFFECTIVE, 1, &cap_net_admin, cap_flag); + if (ret < 0) { + perror("cap_set_flag"); + goto out; + } + + ret = cap_set_proc(cap_cur); + if (ret < 0) { + perror("cap_set_proc"); + goto out; + } + +out: + cap_free(cap_cur); +#endif + + return ret; +} + int mac_to_ipv6(const struct ether_addr *mac, struct in6_addr *addr) { memset(addr, 0, sizeof(*addr)); @@ -212,6 +253,7 @@ struct ether_addr *translate_mac(const char *mesh_iface, struct ether_addr in_mac; static struct ether_addr out_mac; struct ether_addr *mac_result; + int ret;
/* input mac has to be copied because it could be in the shared * ether_aton buffer @@ -220,7 +262,12 @@ struct ether_addr *translate_mac(const char *mesh_iface, memcpy(&out_mac, mac, sizeof(out_mac)); mac_result = &out_mac;
- translate_mac_debugfs(mesh_iface, &in_mac, mac_result); + enable_net_admin_capability(1); + ret = translate_mac_netlink(mesh_iface, &in_mac, mac_result); + enable_net_admin_capability(0); + + if (ret == -EOPNOTSUPP) + translate_mac_debugfs(mesh_iface, &in_mac, mac_result);
return mac_result; } diff --git a/netlink.c b/netlink.c index d9c1f55..e1ebc07 100644 --- a/netlink.c +++ b/netlink.c @@ -21,6 +21,14 @@
#include "netlink.h"
+#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <net/ethernet.h> +#include <net/if.h> #include <netlink/netlink.h> #include <netlink/genl/genl.h> #include <netlink/genl/ctrl.h> @@ -28,6 +36,10 @@
#include "batman_adv.h"
+#ifndef __unused +#define __unused __attribute__((unused)) +#endif + struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_VERSION] = { .type = NLA_STRING }, [BATADV_ATTR_ALGO_NAME] = { .type = NLA_STRING }, @@ -82,3 +94,189 @@ struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { .maxlen = ETH_ALEN }, [BATADV_ATTR_BLA_CRC] = { .type = NLA_U16 }, }; + +int missing_mandatory_attrs(struct nlattr *attrs[], const int mandatory[], + size_t num) +{ + size_t i; + + for (i = 0; i < num; i++) + if (!attrs[mandatory[i]]) + return -EINVAL; + + return 0; +} + +static int nlquery_error_cb(struct sockaddr_nl *nla __unused, + struct nlmsgerr *nlerr, void *arg) +{ + struct nlquery_opts *query_opts = arg; + + query_opts->err = nlerr->error; + + return NL_STOP; +} + +static int nlquery_stop_cb(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlquery_opts *query_opts = arg; + int *error = nlmsg_data(nlh); + + if (*error) + query_opts->err = *error; + + return NL_STOP; +} + +int netlink_query_common(const char *mesh_iface, uint8_t nl_cmd, + nl_recvmsg_msg_cb_t callback, + struct nlquery_opts *query_opts) +{ + struct nl_sock *sock; + struct nl_msg *msg; + struct nl_cb *cb; + int ifindex; + int family; + int ret; + + query_opts->err = 0; + + sock = nl_socket_alloc(); + if (!sock) + return -ENOMEM; + + ret = genl_connect(sock); + if (ret < 0) { + query_opts->err = ret; + goto err_free_sock; + } + + family = genl_ctrl_resolve(sock, BATADV_NL_NAME); + if (family < 0) { + query_opts->err = -EOPNOTSUPP; + goto err_free_sock; + } + + ifindex = if_nametoindex(mesh_iface); + if (!ifindex) { + query_opts->err = -ENODEV; + goto err_free_sock; + } + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) { + query_opts->err = -ENOMEM; + goto err_free_sock; + } + + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, callback, query_opts); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nlquery_stop_cb, query_opts); + nl_cb_err(cb, NL_CB_CUSTOM, nlquery_error_cb, query_opts); + + msg = nlmsg_alloc(); + if (!msg) { + query_opts->err = -ENOMEM; + goto err_free_cb; + } + + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_DUMP, + nl_cmd, 1); + + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex); + nl_send_auto_complete(sock, msg); + nlmsg_free(msg); + + nl_recvmsgs(sock, cb); + +err_free_cb: + nl_cb_put(cb); +err_free_sock: + nl_socket_free(sock); + + return query_opts->err; +} + +static const int translate_mac_netlink_mandatory[] = { + BATADV_ATTR_TT_ADDRESS, + BATADV_ATTR_ORIG_ADDRESS, +}; + +struct translate_mac_netlink_opts { + struct ether_addr mac; + bool found; + struct nlquery_opts query_opts; +}; + +static int translate_mac_netlink_cb(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlquery_opts *query_opts = arg; + struct translate_mac_netlink_opts *opts; + struct genlmsghdr *ghdr; + uint8_t *addr; + uint8_t *orig; + + opts = container_of(query_opts, struct translate_mac_netlink_opts, + query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_TRANSTABLE_GLOBAL) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + return NL_OK; + } + + if (missing_mandatory_attrs(attrs, translate_mac_netlink_mandatory, + ARRAY_SIZE(translate_mac_netlink_mandatory))) + return NL_OK; + + addr = nla_data(attrs[BATADV_ATTR_TT_ADDRESS]); + orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); + + if (!attrs[BATADV_ATTR_FLAG_BEST]) + return NL_OK; + + if (memcmp(&opts->mac, addr, ETH_ALEN) != 0) + return NL_OK; + + memcpy(&opts->mac, orig, ETH_ALEN); + opts->found = true; + opts->query_opts.err = 0; + + return NL_STOP; +} + +int translate_mac_netlink(const char *mesh_iface, const struct ether_addr *mac, + struct ether_addr *mac_out) +{ + struct translate_mac_netlink_opts opts = { + .found = false, + .query_opts = { + .err = 0, + }, + }; + int ret; + + memcpy(&opts.mac, mac, ETH_ALEN); + + ret = netlink_query_common(mesh_iface, + BATADV_CMD_GET_TRANSTABLE_GLOBAL, + translate_mac_netlink_cb, &opts.query_opts); + if (ret < 0) + return ret; + + if (!opts.found) + return -ENOENT; + + memcpy(mac_out, &opts.mac, ETH_ALEN); + + return 0; +} diff --git a/netlink.h b/netlink.h index f903563..8e54235 100644 --- a/netlink.h +++ b/netlink.h @@ -24,6 +24,29 @@
#include <netlink/genl/genl.h> #include <netlink/genl/ctrl.h> +#include <stddef.h> + +struct ether_addr; + +struct nlquery_opts { + int err; +}; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) + +#ifndef container_of +#define container_of(ptr, type, member) __extension__ ({ \ + const __typeof__(((type *)0)->member) *__pmember = (ptr); \ + (type *)((char *)__pmember - offsetof(type, member)); }) +#endif + +int netlink_query_common(const char *mesh_iface, uint8_t nl_cmd, + nl_recvmsg_msg_cb_t callback, + struct nlquery_opts *query_opts); +int missing_mandatory_attrs(struct nlattr *attrs[], const int mandatory[], + size_t num); +int translate_mac_netlink(const char *mesh_iface, const struct ether_addr *mac, + struct ether_addr *mac_out);
extern struct nla_policy batadv_netlink_policy[];
The debugfs tables cannot be used by the alfred in network namespaces. These have to use netlink. Thus the get_tq should be less tightly linked to the debugfs tables to implement optional netlink support.
Signed-off-by: Sven Eckelmann sven@narfation.org --- batadv_query.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-)
diff --git a/batadv_query.c b/batadv_query.c index 9082576..a893995 100644 --- a/batadv_query.c +++ b/batadv_query.c @@ -272,7 +272,8 @@ struct ether_addr *translate_mac(const char *mesh_iface, return mac_result; }
-uint8_t get_tq(const char *mesh_iface, struct ether_addr *mac) +static int get_tq_debugfs(const char *mesh_iface, struct ether_addr *mac, + uint8_t *tq) { enum { orig_mac, @@ -288,7 +289,7 @@ uint8_t get_tq(const char *mesh_iface, struct ether_addr *mac) char *line = NULL; char *input, *saveptr, *token; int line_invalid; - uint8_t tq = 0; + bool found = false;
memcpy(&in_mac, mac, sizeof(in_mac));
@@ -297,7 +298,7 @@ uint8_t get_tq(const char *mesh_iface, struct ether_addr *mac)
f = fopen(full_path, "r"); if (!f) - goto out; + return -EOPNOTSUPP;
while (getline(&line, &len, f) != -1) { line_invalid = 0; @@ -338,7 +339,8 @@ uint8_t get_tq(const char *mesh_iface, struct ether_addr *mac) line_invalid = 1; } else { token[strlen(token) - 1] = '\0'; - tq = strtol(token, NULL, 10); + *tq = strtol(token, NULL, 10); + found = true; goto out; } break; @@ -353,5 +355,24 @@ out: if (f) fclose(f); free(line); + + if (found) + return 0; + else + return -ENOENT; +} + +uint8_t get_tq(const char *mesh_iface, struct ether_addr *mac) +{ + struct ether_addr in_mac; + uint8_t tq = 0; + + /* input mac has to be copied because it could be in the shared + * ether_aton buffer + */ + memcpy(&in_mac, mac, sizeof(in_mac)); + + get_tq_debugfs(mesh_iface, &in_mac, &tq); + return tq; }
The debugfs entries are only available on the main network namespace. All other network namespaces have to fall back to netlink to read the originator table.
alfred has therefore try to access the originator via netlink and try to fall back to the debugfs table in case the batman-adv module doesn't support BATADV_CMD_GET_ORIGINATORS.
Signed-off-by: Sven Eckelmann sven@narfation.org --- batadv_query.c | 8 +++++- netlink.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netlink.h | 2 ++ 3 files changed, 94 insertions(+), 1 deletion(-)
diff --git a/batadv_query.c b/batadv_query.c index a893995..a671b79 100644 --- a/batadv_query.c +++ b/batadv_query.c @@ -366,13 +366,19 @@ uint8_t get_tq(const char *mesh_iface, struct ether_addr *mac) { struct ether_addr in_mac; uint8_t tq = 0; + int ret;
/* input mac has to be copied because it could be in the shared * ether_aton buffer */ memcpy(&in_mac, mac, sizeof(in_mac));
- get_tq_debugfs(mesh_iface, &in_mac, &tq); + enable_net_admin_capability(1); + ret = get_tq_netlink(mesh_iface, &in_mac, &tq); + enable_net_admin_capability(0); + + if (ret == -EOPNOTSUPP) + get_tq_debugfs(mesh_iface, &in_mac, &tq);
return tq; } diff --git a/netlink.c b/netlink.c index e1ebc07..1b5695c 100644 --- a/netlink.c +++ b/netlink.c @@ -280,3 +280,88 @@ int translate_mac_netlink(const char *mesh_iface, const struct ether_addr *mac,
return 0; } + +static const int get_tq_netlink_mandatory[] = { + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_TQ, +}; + +struct get_tq_netlink_opts { + struct ether_addr mac; + uint8_t tq; + bool found; + struct nlquery_opts query_opts; +}; + +static int get_tq_netlink_cb(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlquery_opts *query_opts = arg; + struct get_tq_netlink_opts *opts; + struct genlmsghdr *ghdr; + uint8_t *orig; + uint8_t tq; + + opts = container_of(query_opts, struct get_tq_netlink_opts, + query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + return NL_OK; + } + + if (missing_mandatory_attrs(attrs, get_tq_netlink_mandatory, + ARRAY_SIZE(get_tq_netlink_mandatory))) + return NL_OK; + + orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); + tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); + + if (!attrs[BATADV_ATTR_FLAG_BEST]) + return NL_OK; + + if (memcmp(&opts->mac, orig, ETH_ALEN) != 0) + return NL_OK; + + opts->tq = tq; + opts->found = true; + opts->query_opts.err = 0; + + return NL_STOP; +} + +int get_tq_netlink(const char *mesh_iface, const struct ether_addr *mac, + uint8_t *tq) +{ + struct get_tq_netlink_opts opts = { + .tq = 0, + .found = false, + .query_opts = { + .err = 0, + }, + }; + int ret; + + memcpy(&opts.mac, mac, ETH_ALEN); + + ret = netlink_query_common(mesh_iface, BATADV_CMD_GET_ORIGINATORS, + get_tq_netlink_cb, &opts.query_opts); + if (ret < 0) + return ret; + + if (!opts.found) + return -ENOENT; + + *tq = opts.tq; + + return 0; +} diff --git a/netlink.h b/netlink.h index 8e54235..b08e872 100644 --- a/netlink.h +++ b/netlink.h @@ -47,6 +47,8 @@ int missing_mandatory_attrs(struct nlattr *attrs[], const int mandatory[], size_t num); int translate_mac_netlink(const char *mesh_iface, const struct ether_addr *mac, struct ether_addr *mac_out); +int get_tq_netlink(const char *mesh_iface, const struct ether_addr *mac, + uint8_t *tq);
extern struct nla_policy batadv_netlink_policy[];
The netlink messages don't contain the complete names. Instead the device indexes are used. To avoid extra overhead of retrieving the device name for each index, the interface list can just be used again as cache by making it queryable via the ifindex.
Signed-off-by: Sven Eckelmann sven@narfation.org --- vis/vis.c | 13 ++++++++++--- vis/vis.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/vis/vis.c b/vis/vis.c index 7eab781..bac451b 100644 --- a/vis/vis.c +++ b/vis/vis.c @@ -125,9 +125,10 @@ static int get_if_mac(char *ifname, uint8_t *mac) return 0; }
-static int get_if_index(struct globals *globals, char *ifname) +static int get_if_index_byname(struct globals *globals, char *ifname) { struct iface_list_entry *i_entry; + int devindex; int i;
if (!ifname) @@ -139,6 +140,11 @@ static int get_if_index(struct globals *globals, char *ifname) return i; i++; } + + devindex = if_nametoindex(ifname); + if (!devindex) + return -1; + i_entry = malloc(sizeof(*i_entry)); if (!i_entry) return -1; @@ -148,6 +154,7 @@ static int get_if_index(struct globals *globals, char *ifname) return -1; }
+ i_entry->devindex = devindex; strncpy(i_entry->name, ifname, sizeof(i_entry->name)); /* just to be safe ... */ i_entry->name[sizeof(i_entry->name) - 1] = 0; @@ -301,7 +308,7 @@ static int register_interfaces(struct globals *globals) *content_newline = '\0';
if (strcmp(file_content, "active") == 0) - get_if_index(globals, iface_dir->d_name); + get_if_index_byname(globals, iface_dir->d_name);
free_line: free(file_content); @@ -364,7 +371,7 @@ static int parse_orig_list(struct globals *globals) if (!mac) continue;
- ifindex = get_if_index(globals, iface); + ifindex = get_if_index_byname(globals, iface); if (ifindex < 0) continue;
diff --git a/vis/vis.h b/vis/vis.h index 4c98064..c25a75b 100644 --- a/vis/vis.h +++ b/vis/vis.h @@ -77,6 +77,7 @@ struct vis_v1 { struct iface_list_entry { char name[256]; uint8_t mac[ETH_ALEN]; + int devindex; struct list_head list; };
The debugfs entries are only available on the main network namespace. All other network namespaces have to fallback to netlink to read the local translation table and the originator table.
Signed-off-by: Sven Eckelmann sven@narfation.org --- vis/vis.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 217 insertions(+), 2 deletions(-)
diff --git a/vis/vis.c b/vis/vis.c index bac451b..d6bac41 100644 --- a/vis/vis.c +++ b/vis/vis.c @@ -35,10 +35,18 @@ #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> + +#include "batman_adv.h" +#include "netlink.h" #include "debugfs.h"
static struct globals vis_globals;
+struct vis_netlink_opts { + struct globals *globals; + struct nlquery_opts query_opts; +}; + static char *read_file(char *fname) { FILE *fp; @@ -163,6 +171,45 @@ static int get_if_index_byname(struct globals *globals, char *ifname) return i; }
+static int get_if_index_devindex(struct globals *globals, int devindex) +{ + struct iface_list_entry *i_entry; + char *ifname; + char ifnamebuf[IF_NAMESIZE]; + int i; + + if (!devindex) + return -1; + + i = 0; + list_for_each_entry(i_entry, &globals->iface_list, list) { + if (i_entry->devindex == devindex) + return i; + i++; + } + + ifname = if_indextoname(devindex, ifnamebuf); + if (!ifname) + return -1; + + i_entry = malloc(sizeof(*i_entry)); + if (!i_entry) + return -1; + + if (get_if_mac(ifname, i_entry->mac)) { + free(i_entry); + return -1; + } + + i_entry->devindex = devindex; + strncpy(i_entry->name, ifname, sizeof(i_entry->name)); + /* just to be safe ... */ + i_entry->name[sizeof(i_entry->name) - 1] = 0; + list_add_tail(&i_entry->list, &globals->iface_list); + + return i; +} + static int alfred_open_sock(struct globals *globals) { struct sockaddr_un addr; @@ -189,7 +236,75 @@ static int alfred_open_sock(struct globals *globals) return 0; }
-static int parse_transtable_local(struct globals *globals) +static const int parse_transtable_local_mandatory[] = { + BATADV_ATTR_TT_ADDRESS, +}; + +static int parse_transtable_local_netlink_cb(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlquery_opts *query_opts = arg; + struct vis_netlink_opts *opts; + struct genlmsghdr *ghdr; + struct vis_list_entry *v_entry; + uint8_t *addr; + + opts = container_of(query_opts, struct vis_netlink_opts, + query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_TRANSTABLE_LOCAL) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + return NL_OK; + } + + if (missing_mandatory_attrs(attrs, parse_transtable_local_mandatory, + ARRAY_SIZE(parse_transtable_local_mandatory))) + return NL_OK; + + addr = nla_data(attrs[BATADV_ATTR_TT_ADDRESS]); + + v_entry = malloc(sizeof(*v_entry)); + if (!v_entry) + return NL_OK; + + memcpy(v_entry->v.mac, addr, ETH_ALEN); + v_entry->v.ifindex = 255; + v_entry->v.qual = 0; + list_add_tail(&v_entry->list, &opts->globals->entry_list); + + return NL_OK; +} + +static int parse_transtable_local_netlink(struct globals *globals) +{ + struct vis_netlink_opts opts = { + .globals = globals, + .query_opts = { + .err = 0, + }, + }; + int ret; + + ret = netlink_query_common(globals->interface, + BATADV_CMD_GET_TRANSTABLE_LOCAL, + parse_transtable_local_netlink_cb, + &opts.query_opts); + if (ret < 0) + return ret; + + return 0; +} + +static int parse_transtable_local_debugfs(struct globals *globals) { char *fbuf; char *lptr, *tptr; @@ -241,6 +356,17 @@ static int parse_transtable_local(struct globals *globals) return 0; }
+static int parse_transtable_local(struct globals *globals) +{ + int ret; + + ret = parse_transtable_local_netlink(globals); + if (ret != EOPNOTSUPP) + return ret; + + return parse_transtable_local_debugfs(globals); +} + static void clear_lists(struct globals *globals) { struct vis_list_entry *v_entry, *v_entry_safe; @@ -325,8 +451,86 @@ err: return EXIT_FAILURE; }
+static const int parse_orig_list_mandatory[] = { + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_TQ, + BATADV_ATTR_HARD_IFINDEX, +};
-static int parse_orig_list(struct globals *globals) +static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlquery_opts *query_opts = arg; + struct vis_netlink_opts *opts; + struct genlmsghdr *ghdr; + struct vis_list_entry *v_entry; + uint8_t *orig; + uint8_t tq; + uint32_t hardif; + + opts = container_of(query_opts, struct vis_netlink_opts, + query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + return NL_OK; + } + + if (missing_mandatory_attrs(attrs, parse_orig_list_mandatory, + ARRAY_SIZE(parse_orig_list_mandatory))) + return NL_OK; + + if (!attrs[BATADV_ATTR_FLAG_BEST]) + return NL_OK; + + orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); + tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); + hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); + + if (tq < 1) + return NL_OK; + + v_entry = malloc(sizeof(*v_entry)); + if (!v_entry) + return NL_OK; + + memcpy(v_entry->v.mac, orig, ETH_ALEN); + v_entry->v.ifindex = get_if_index_devindex(opts->globals, hardif); + v_entry->v.qual = tq; + list_add_tail(&v_entry->list, &opts->globals->entry_list); + + return NL_OK; +} + +static int parse_orig_list_netlink(struct globals *globals) +{ + struct vis_netlink_opts opts = { + .globals = globals, + .query_opts = { + .err = 0, + }, + }; + int ret; + + ret = netlink_query_common(globals->interface, + BATADV_CMD_GET_ORIGINATORS, + parse_orig_list_netlink_cb, &opts.query_opts); + if (ret < 0) + return ret; + + return 0; +} + +static int parse_orig_list_debugfs(struct globals *globals) { char *fbuf; char *lptr, *tptr; @@ -393,6 +597,17 @@ static int parse_orig_list(struct globals *globals) return 0; }
+static int parse_orig_list(struct globals *globals) +{ + int ret; + + ret = parse_orig_list_netlink(globals); + if (ret != EOPNOTSUPP) + return ret; + + return parse_orig_list_debugfs(globals); +} + static int vis_publish_data(struct globals *globals) { int len, ret;
The batman_adv.h netlink header is used by userspace programs to use the genl interface of batman-adv. These programs may not use the GPL-2 license. The header should therefore state clearly that it can be used freely and the license of the program which uses this header is not affected.
Signed-off-by: Sven Eckelmann sven@narfation.org Acked-by: Matthias Schiffer mschiffer@universe-factory.net Signed-off-by: Marek Lindner mareklindner@neomailbox.ch --- batman_adv.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/batman_adv.h b/batman_adv.h index 37157d0..734fe83 100644 --- a/batman_adv.h +++ b/batman_adv.h @@ -2,17 +2,17 @@ * * Matthias Schiffer * - * 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. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * 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, see http://www.gnu.org/licenses/. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#ifndef _UAPI_LINUX_BATMAN_ADV_H_
On Sunday 05 June 2016 20:46:59 Sven Eckelmann wrote:
The content of batman_adv/iface_status ends with a newline. Thus register_interfaces has to make sure that it only compares the first line without the \n when comparing with the status string.
Signed-off-by: Sven Eckelmann sven@narfation.org
I've applied the whole series (78e1d64..5b67293). We can beautify the header stuff later.
Cheers, Simon
b.a.t.m.a.n@lists.open-mesh.org