gluon-status-page-api: Switch from debugfs to batadv netlink

The batadv debugfs requires large memory blocks to write the text debug
tables. This is inefficient for large tables like the global translation
table or the originators table.

The memory requirement can be reduced by using netlink. It copies smaller
packets in a binary format to the userspace program. gluon-status-page-api
can therefore parse larger originator tables without causing an OOM on
systems which are tight on memory.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
This commit is contained in:
Sven Eckelmann 2016-09-24 19:59:44 +02:00
parent ff0ad20752
commit 6ac5b9cbc8
6 changed files with 536 additions and 33 deletions

View File

@ -14,7 +14,7 @@ define Package/gluon-status-page-api
SECTION:=gluon
CATEGORY:=Gluon
TITLE:=API for gluon-status-page
DEPENDS:=+gluon-core +uhttpd +sse-multiplex +gluon-neighbour-info +gluon-respondd +libiwinfo +libjson-c
DEPENDS:=+gluon-core +uhttpd +sse-multiplex +gluon-neighbour-info +gluon-respondd +libiwinfo +libjson-c +libnl-tiny
endef
define Build/Prepare

View File

@ -1,12 +1,29 @@
CFLAGS += -std=c99 -D_BSD_SOURCE
CPPFLAGS += -D_GNU_SOURCE
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-tiny
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_JSONC = $(shell pkg-config --cflags json-c)
LDFLAGS_JSONC = $(shell pkg-config --libs json-c)
all: neighbours-batadv stations respondd.so
neighbours-batadv: neighbours-batadv.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LDFLAGS) $(LDFLAGS_JSONC) -Wall -o $@ $^ $(LDLIBS)
neighbours-batadv: neighbours-batadv.c batadv-netlink.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LIBNL_CFLAGS) $(LDFLAGS) $(LDFLAGS_JSONC) $(LIBNL_LDLIBS) -Wall -o $@ $^ $(LDLIBS)
stations: stations.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LDFLAGS) $(LDFLAGS_JSONC) -Wall -o $@ $^ $(LDLIBS) -liwinfo

View File

@ -0,0 +1,145 @@
/*
* 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 "batadv-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>
#include <net/ethernet.h>
#include "batman_adv.h"
#ifndef __maybe_unused
#define __maybe_unused __attribute__((unused))
#endif
struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = {
[BATADV_ATTR_HARD_IFINDEX] = { .type = NLA_U32 },
[BATADV_ATTR_ORIG_ADDRESS] = { .type = NLA_UNSPEC,
.minlen = ETH_ALEN,
.maxlen = ETH_ALEN },
[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 },
};
static int nlquery_error_cb(struct sockaddr_nl *nla __maybe_unused,
struct nlmsgerr *nlerr, void *arg)
{
struct batadv_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 batadv_nlquery_opts *query_opts = arg;
int *error = nlmsg_data(nlh);
if (*error)
query_opts->err = *error;
return NL_STOP;
}
int batadv_nl_query_common(const char *mesh_iface,
enum batadv_nl_commands nl_cmd,
nl_recvmsg_msg_cb_t callback, int flags,
struct batadv_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, flags,
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;
}

View File

@ -0,0 +1,68 @@
/*
* 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 _BATADV_NETLINK_H
#define _BATADV_NETLINK_H
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <stddef.h>
#include <stdbool.h>
#include "batman_adv.h"
struct batadv_nlquery_opts {
int err;
};
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
#endif
#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 batadv_nl_query_common(const char *mesh_iface,
enum batadv_nl_commands nl_cmd,
nl_recvmsg_msg_cb_t callback, int flags,
struct batadv_nlquery_opts *query_opts);
static inline bool batadv_nl_missing_attrs(struct nlattr *attrs[],
const enum batadv_nl_attrs mandatory[],
size_t num)
{
size_t i;
for (i = 0; i < num; i++) {
if (!attrs[mandatory[i]])
return true;
}
return false;
}
extern struct nla_policy batadv_netlink_policy[];
#endif /* _BATADV_NETLINK_H */

View File

@ -0,0 +1,208 @@
/* Copyright (C) 2016 B.A.T.M.A.N. contributors:
*
* Matthias Schiffer
*
* 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.
*
* 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_
#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_ */

View File

@ -4,45 +4,110 @@
#include <json-c/json.h>
#include <net/if.h>
#include "batadv-netlink.h"
#define STR(x) #x
#define XSTR(x) STR(x)
struct neigh_netlink_opts {
struct json_object *obj;
struct batadv_nlquery_opts query_opts;
};
static const enum batadv_nl_attrs parse_orig_list_mandatory[] = {
BATADV_ATTR_ORIG_ADDRESS,
BATADV_ATTR_NEIGH_ADDRESS,
BATADV_ATTR_TQ,
BATADV_ATTR_HARD_IFINDEX,
BATADV_ATTR_LAST_SEEN_MSECS,
};
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 batadv_nlquery_opts *query_opts = arg;
struct genlmsghdr *ghdr;
uint8_t *orig;
uint8_t *dest;
uint8_t tq;
uint32_t hardif;
uint32_t lastseen;
char ifname_buf[IF_NAMESIZE], *ifname;
struct neigh_netlink_opts *opts;
char mac1[18];
opts = container_of(query_opts, struct neigh_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 (batadv_nl_missing_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]);
dest = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]);
tq = nla_get_u8(attrs[BATADV_ATTR_TQ]);
hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]);
lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]);
if (memcmp(orig, dest, 6) != 0)
return NL_OK;
ifname = if_indextoname(hardif, ifname_buf);
if (!ifname)
return NL_OK;
sprintf(mac1, "%02x:%02x:%02x:%02x:%02x:%02x",
orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]);
struct json_object *neigh = json_object_new_object();
if (!neigh)
return NL_OK;
json_object_object_add(neigh, "tq", json_object_new_int(tq));
json_object_object_add(neigh, "lastseen", json_object_new_double(lastseen / 1000.));
json_object_object_add(neigh, "ifname", json_object_new_string(ifname));
json_object_object_add(opts->obj, mac1, neigh);
return NL_OK;
}
static json_object *neighbours(void) {
struct json_object *obj = json_object_new_object();
struct neigh_netlink_opts opts = {
.query_opts = {
.err = 0,
},
};
int ret;
FILE *f;
f = fopen("/sys/kernel/debug/batman_adv/bat0/originators" , "r");
if (f == NULL)
opts.obj = json_object_new_object();
if (!opts.obj)
return NULL;
while (!feof(f)) {
char mac1[18];
char mac2[18];
char ifname[IF_NAMESIZE+1];
int tq;
double lastseen;
int count = fscanf(f, "%17s%*[\t ]%lfs%*[\t (]%d) %17s%*[[ ]%" XSTR(IF_NAMESIZE) "[^]]]", mac1, &lastseen, &tq, mac2, ifname);
if (count != 5)
continue;
if (strcmp(mac1, mac2) == 0) {
struct json_object *neigh = json_object_new_object();
json_object_object_add(neigh, "tq", json_object_new_int(tq));
json_object_object_add(neigh, "lastseen", json_object_new_double(lastseen));
json_object_object_add(neigh, "ifname", json_object_new_string(ifname));
json_object_object_add(obj, mac1, neigh);
}
ret = batadv_nl_query_common("bat0", BATADV_CMD_GET_ORIGINATORS,
parse_orig_list_netlink_cb, NLM_F_DUMP,
&opts.query_opts);
if (ret < 0) {
json_object_put(opts.obj);
return NULL;
}
fclose(f);
return obj;
return opts.obj;
}
int main(void) {