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 --]
next prev parent 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox