All of lore.kernel.org
 help / color / mirror / Atom feed
From: Matthias Schiffer <mschiffer@universe-factory.net>
To: b.a.t.m.a.n@lists.open-mesh.org
Subject: Re: [B.A.T.M.A.N.] [RFC] batman-adv: add generic netlink query API to replace debugfs files
Date: Wed, 24 Jun 2015 21:00:30 +0200	[thread overview]
Message-ID: <558AFE4E.7040107@universe-factory.net> (raw)
In-Reply-To: <2ce4491cf3eb01922d0fec97147a1533cca30c41.1435170868.git.mschiffer@universe-factory.net>


[-- Attachment #1.1: Type: text/plain, Size: 368 bytes --]

This is the mentioned userspace tool.
Build with:

cc -o batnl batnl.c $(pkg-config --cflags --libs libnl-1) -Wall

It uses the outdated libnl-1 instead of the current libnl-3 API to be
compatible with OpenWrt's libnl-tiny.

It is only a quick-and-dirty example for the usage of the GENL API, so
it doesn't check for a lot of errors...

Regards,
Matthias

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: batnl.c --]
[-- Type: text/x-csrc; name="batnl.c", Size: 10341 bytes --]

#include <stdio.h>
#include <string.h>

#include <net/if.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "batman_adv.h"


static void usage()
{
	fprintf(stderr, "Usage:\n\n");
	fprintf(stderr, "  batnl <mesh> info\n");
	fprintf(stderr, "  batnl <mesh> translocal\n");
	fprintf(stderr, "  batnl <mesh> transglobal\n");
	fprintf(stderr, "  batnl <mesh> originators [<outgoing>]\n");
	exit(2);
}

static int print_error(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg)
{
	fprintf(stderr, "Error received: %s\n", strerror(-nlerr->error));
	exit(1);
}

static int info_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct genlmsghdr *ghdr;
	struct nlattr *attrs[BATADV_ATTR_MAX+1];

	if (!genlmsg_valid_hdr(nlh, 0)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	ghdr = nlmsg_data(nlh);

	if (ghdr->cmd != BATADV_CMD_GET_MESH_INFO)
		return NL_OK;

	if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), genlmsg_len(ghdr), NULL)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	const char *mesh_name = nla_get_string(attrs[BATADV_ATTR_MESH_IFNAME]);

	if (attrs[BATADV_ATTR_PRIMARY_IFNAME]) {
		const char *version = nla_get_string(attrs[BATADV_ATTR_VERSION]);
		const char *algo_name = nla_get_string(attrs[BATADV_ATTR_ALGO_NAME]);
		const char *primary_if = nla_get_string(attrs[BATADV_ATTR_PRIMARY_IFNAME]);
		const uint8_t *primary_mac = nla_data(attrs[BATADV_ATTR_PRIMARY_ADDRESS]);

		printf("[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%02x:%02x:%02x:%02x:%02x:%02x (%s %s)]\n",
		       version, primary_if,
		       primary_mac[0], primary_mac[1], primary_mac[2],
		       primary_mac[3], primary_mac[4], primary_mac[5],
		       mesh_name, algo_name);

	}
	else {
		printf("BATMAN mesh %s disabled\n", mesh_name);
	}

	return NL_STOP;
}

static void info(struct nl_handle *sock, int family, int ifindex)
{
	struct nl_msg *msg;
	struct nl_cb *cb;

	msg = nlmsg_alloc();
	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, 0, BATADV_CMD_GET_MESH_INFO, 1);

	nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex);

	nl_send_auto_complete(sock, msg);

	nlmsg_free(msg);

	cb = nl_cb_alloc(NL_CB_DEFAULT);
	nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, info_callback, NULL);
	nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);

	nl_recvmsgs(sock, cb);
}

static int stop_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	int *error = nlmsg_data(nlh);

	if (*error)
		fprintf(stderr, "Error received: %s\n", strerror(-*error));

	return NL_STOP;
}

static int translocal_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct genlmsghdr *ghdr;
	struct nlattr *attrs[BATADV_ATTR_MAX+1];

	if (!genlmsg_valid_hdr(nlh, 0)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	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), NULL)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	uint8_t *addr = nla_data(attrs[BATADV_ATTR_TT_ADDRESS]);
	int16_t vid = nla_get_u16(attrs[BATADV_ATTR_TT_VID]);
	uint32_t crc32 = nla_get_u32(attrs[BATADV_ATTR_TT_CRC32]);
	int last_seen_msecs = 0, last_seen_secs = 0;

	char r = '.', p = '.', n = '.', x = '.', w = '.', i = '.';
	if (attrs[BATADV_ATTR_FLAG_ROAM])
		r = 'R';
	if (attrs[BATADV_ATTR_FLAG_NEW])
		n = 'N';
	if (attrs[BATADV_ATTR_FLAG_PENDING])
		x = 'X';
	if (attrs[BATADV_ATTR_FLAG_WIFI])
		w = 'W';
	if (attrs[BATADV_ATTR_FLAG_ISOLA])
		i = 'I';

	if (attrs[BATADV_ATTR_FLAG_NOPURGE])  {
		p = 'P';
	}
	else {
		last_seen_msecs = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]);
		last_seen_secs = last_seen_msecs / 1000;
		last_seen_msecs = last_seen_msecs % 1000;
	}


	printf(" * %02x:%02x:%02x:%02x:%02x:%02x %4i [%c%c%c%c%c%c] %3u.%03u   (0x%.8x)\n",
	       addr[0], addr[1], addr[2],
	       addr[3], addr[4], addr[5],
	       vid, r, p, n, x, w, i,
	       last_seen_secs, last_seen_msecs,
	       crc32);

	return NL_OK;
}

static void translocal(struct nl_handle *sock, int family, int ifindex)
{
	struct nl_msg *msg;
	struct nl_cb *cb;

	msg = nlmsg_alloc();
	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_DUMP, BATADV_CMD_GET_TRANSTABLE_LOCAL, 1);

	nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex);

	nl_send_auto_complete(sock, msg);

	nlmsg_free(msg);

	cb = nl_cb_alloc(NL_CB_DEFAULT);
	nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, translocal_callback, NULL);
	nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, stop_callback, NULL);
	nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);

	nl_recvmsgs(sock, cb);
}

static int transglobal_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct genlmsghdr *ghdr;
	struct nlattr *attrs[BATADV_ATTR_MAX+1];

	if (!genlmsg_valid_hdr(nlh, 0)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	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), NULL)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	uint8_t *addr = nla_data(attrs[BATADV_ATTR_TT_ADDRESS]);
	uint8_t *orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]);
	int16_t vid = nla_get_u16(attrs[BATADV_ATTR_TT_VID]);
	uint8_t ttvn = nla_get_u8(attrs[BATADV_ATTR_TT_TTVN]);
	uint8_t last_ttvn = nla_get_u8(attrs[BATADV_ATTR_TT_LAST_TTVN]);
	uint32_t crc32 = nla_get_u32(attrs[BATADV_ATTR_TT_CRC32]);

	char c = '+', r = '.', w = '.', i = '.', t = '.';
	if (attrs[BATADV_ATTR_FLAG_BEST])
		c = '*';
	if (attrs[BATADV_ATTR_FLAG_ROAM])
		r = 'R';
	if (attrs[BATADV_ATTR_FLAG_WIFI])
		w = 'W';
	if (attrs[BATADV_ATTR_FLAG_ISOLA])
		i = 'I';
	if (attrs[BATADV_ATTR_FLAG_TEMP])
		t = 'T';


	printf(" %c %02x:%02x:%02x:%02x:%02x:%02x %4i   (%3u) via %02x:%02x:%02x:%02x:%02x:%02x     (%3u)   (0x%.8x) [%c%c%c%c]\n",
	       c,
	       addr[0], addr[1], addr[2],
	       addr[3], addr[4], addr[5],
	       vid, ttvn,
	       orig[0], orig[1], orig[2],
	       orig[3], orig[4], orig[5],
	       last_ttvn, crc32, r, w, i, t);

	return NL_OK;
}

static void transglobal(struct nl_handle *sock, int family, int ifindex)
{
	struct nl_msg *msg;
	struct nl_cb *cb;

	msg = nlmsg_alloc();
	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_DUMP, BATADV_CMD_GET_TRANSTABLE_GLOBAL, 1);

	nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex);

	nl_send_auto_complete(sock, msg);

	nlmsg_free(msg);

	cb = nl_cb_alloc(NL_CB_DEFAULT);
	nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, transglobal_callback, NULL);
	nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, stop_callback, NULL);
	nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);

	nl_recvmsgs(sock, cb);
}

static int originators_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct genlmsghdr *ghdr;
	struct nlattr *attrs[BATADV_ATTR_MAX+1];

	if (!genlmsg_valid_hdr(nlh, 0)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	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), NULL)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	uint8_t *orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]);
	uint8_t *neigh = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]);
	uint8_t tq = nla_get_u8(attrs[BATADV_ATTR_TQ]);

	char ifname[IF_NAMESIZE];
	if (!if_indextoname(nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]), ifname))
		ifname[0] = '\0';

	char c = '+';
	if (attrs[BATADV_ATTR_FLAG_BEST])
		c = '*';

	int last_seen_msecs, last_seen_secs;
	last_seen_msecs = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]);
	last_seen_secs = last_seen_msecs / 1000;
	last_seen_msecs = last_seen_msecs % 1000;

	printf(" %c %02x:%02x:%02x:%02x:%02x:%02x %4i.%03is   (%3i) %02x:%02x:%02x:%02x:%02x:%02x [%10s]\n",
	       c,
	       orig[0], orig[1], orig[2],
	       orig[3], orig[4], orig[5],
	       last_seen_secs, last_seen_msecs, tq,
	       neigh[0], neigh[1], neigh[2],
	       neigh[3], neigh[4], neigh[5],
	       ifname);

	return NL_OK;
}

static void originators(struct nl_handle *sock, int family, int ifindex, int outgoing_ifindex)
{
	struct nl_msg *msg;
	struct nl_cb *cb;

	msg = nlmsg_alloc();
	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_DUMP, BATADV_CMD_GET_ORIGINATORS, 1);

	nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex);

	if (outgoing_ifindex)
		nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, outgoing_ifindex);

	nl_send_auto_complete(sock, msg);

	nlmsg_free(msg);

	cb = nl_cb_alloc(NL_CB_DEFAULT);
	nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, originators_callback, NULL);
	nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, stop_callback, NULL);
	nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);

	nl_recvmsgs(sock, cb);
}

int main(int argc, char *argv[])
{
	struct nl_handle *sock;
	int family;

	sock = nl_handle_alloc();
	genl_connect(sock);

	family = genl_ctrl_resolve(sock, BATADV_NL_NAME);
	if (family < 0) {
		fputs("Your kernel doesn't support the batman-adv netlink interface.\n", stderr);
		exit(1);
	}

	if (argc != 3 && argc != 4)
		usage();

	int ifindex = if_nametoindex(argv[1]);
	if (!ifindex)
		usage();

	int outgoing_ifindex = 0;

	if (argc == 4) {
		outgoing_ifindex = if_nametoindex(argv[3]);
		if (!outgoing_ifindex)
			usage();
	}

	if (!strcmp(argv[2], "info"))
		info(sock, family, ifindex);
	else if (!strcmp(argv[2], "translocal"))
		translocal(sock, family, ifindex);
	else if (!strcmp(argv[2], "transglobal"))
		transglobal(sock, family, ifindex);
	else if (!strcmp(argv[2], "originators"))
		originators(sock, family, ifindex, outgoing_ifindex);
	else
		usage();

	return 0;
}

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

  reply	other threads:[~2015-06-24 19:00 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-24 18:34 [B.A.T.M.A.N.] [RFC] batman-adv: add generic netlink query API to replace debugfs files Matthias Schiffer
2015-06-24 19:00 ` Matthias Schiffer [this message]
2015-08-07 16:16 ` Linus Lüssing
2015-08-07 17:37   ` Matthias Schiffer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=558AFE4E.7040107@universe-factory.net \
    --to=mschiffer@universe-factory.net \
    --cc=b.a.t.m.a.n@lists.open-mesh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.