From 2e2cd0e802f020aaa4620b8c9ffeab560b584f53 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 28 Oct 2016 15:16:57 +0200 Subject: [PATCH 1/4] batman-adv: Import batman-adv 2016.4 Signed-off-by: Sven Eckelmann --- modules | 2 +- ...-adv-introduce-no_rebroadcast-option.patch | 71 ++++++++++--------- ...n-adv-decrease-maximum-fragment-size.patch | 18 ++--- 3 files changed, 42 insertions(+), 49 deletions(-) diff --git a/modules b/modules index d586f720..450d8195 100644 --- a/modules +++ b/modules @@ -12,7 +12,7 @@ PACKAGES_GLUON_REPO=git://github.com/freifunk-gluon/packages.git PACKAGES_GLUON_COMMIT=738d8a236583233c0d49bbef73ac9b721534d1fc PACKAGES_ROUTING_REPO=git://github.com/openwrt-routing/packages.git -PACKAGES_ROUTING_COMMIT=a4eae82c155079a4372e4b910ec733f77288b717 +PACKAGES_ROUTING_COMMIT=899235a4a6370e86ad3674c38c3f95d23c8f3dc8 PACKAGES_LUCI_REPO=git://github.com/openwrt/luci.git PACKAGES_LUCI_COMMIT=70a4d43cc895b7d728b4fc201f2b6fd9f4b8aaec diff --git a/patches/packages/routing/0002-batman-adv-introduce-no_rebroadcast-option.patch b/patches/packages/routing/0002-batman-adv-introduce-no_rebroadcast-option.patch index f564a011..aa0a1009 100644 --- a/patches/packages/routing/0002-batman-adv-introduce-no_rebroadcast-option.patch +++ b/patches/packages/routing/0002-batman-adv-introduce-no_rebroadcast-option.patch @@ -33,18 +33,13 @@ index 1e0c9d0..d0ab238 100644 } diff --git a/batman-adv/patches/1001-batman-adv-introduce-no_rebroadcast-option.patch b/batman-adv/patches/1001-batman-adv-introduce-no_rebroadcast-option.patch new file mode 100644 -index 0000000..e9f5ffb +index 0000000..2f328d2 --- /dev/null +++ b/batman-adv/patches/1001-batman-adv-introduce-no_rebroadcast-option.patch -@@ -0,0 +1,189 @@ -+From bb66988dc6972d5400b4ff4f0b49ed090007d635 Mon Sep 17 00:00:00 2001 -+Message-Id: -+From: =?UTF-8?q?Linus=20L=C3=BCssing?= +@@ -0,0 +1,190 @@ ++From: Linus Lüssing +Date: Tue, 24 Sep 2013 04:36:27 +0200 -+Subject: [PATCH 1/2] batman-adv: introduce 'no_rebroadcast' option -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit ++Subject: [PATCH] batman-adv: introduce 'no_rebroadcast' option + +This patch introduces a new sysfs option named "no_rebroadcast" on +a per hard interface basis. It allows manually enabling a split-horizon @@ -68,20 +63,19 @@ index 0000000..e9f5ffb +--- + .../ABI/testing/sysfs-class-net-batman-adv | 11 ++++ + net/batman-adv/hard-interface.c | 2 + -+ net/batman-adv/send.c | 4 ++ ++ net/batman-adv/send.c | 5 ++ + net/batman-adv/sysfs.c | 59 ++++++++++++++++++++++ + net/batman-adv/types.h | 1 + -+ 5 files changed, 77 insertions(+) ++ 5 files changed, 78 insertions(+) + +diff --git a/Documentation/ABI/testing/sysfs-class-net-batman-adv b/Documentation/ABI/testing/sysfs-class-net-batman-adv -+index 518f6a1..896c480 100644 ++index 8981068..ac04928 100644 +--- a/Documentation/ABI/testing/sysfs-class-net-batman-adv ++++ b/Documentation/ABI/testing/sysfs-class-net-batman-adv -+@@ -28,3 +28,14 @@ Description: -+ The /sys/class/net//batman-adv/mesh_iface file ++@@ -20,6 +20,17 @@ Description: + displays the batman mesh interface this + currently is associated with. -++ ++ ++What: /sys/class/net//batman-adv/no_rebroadcast ++Date: Sep 2013 ++Contact: Linus Lüssing @@ -92,39 +86,49 @@ index 0000000..e9f5ffb ++ and symmetric only, for instance point-to-point wifi longshots ++ or wired links. Using this option wrongly is going to ++ break your mesh network, use at your own risk! +++ ++ What: /sys/class/net//batman-adv/throughput_override ++ Date: Feb 2014 ++ Contact: Antonio Quartulli +diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c -+index 8c2f399..48e53d0 100644 ++index e034afb..b485a88 100644 +--- a/net/batman-adv/hard-interface.c ++++ b/net/batman-adv/hard-interface.c -+@@ -690,6 +690,8 @@ batadv_hardif_add_interface(struct net_device *net_dev) -+ kref_init(&hard_iface->refcount); -+ kref_get(&hard_iface->refcount); ++@@ -701,6 +701,8 @@ batadv_hardif_add_interface(struct net_device *net_dev) ++ ++ batadv_v_hardif_init(hard_iface); + ++ atomic_set(&hard_iface->no_rebroadcast, 0); ++ + batadv_check_known_mac_addr(hard_iface->net_dev); ++ kref_get(&hard_iface->refcount); + list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list); -+ +diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c -+index f2f1256..3736d75 100644 ++index 8d4e1f5..cb1b275 100644 +--- a/net/batman-adv/send.c ++++ b/net/batman-adv/send.c -+@@ -578,6 +578,10 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work) -+ if (forw_packet->num_packets >= hard_iface->num_bcasts) ++@@ -639,11 +639,16 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work) ++ if (!kref_get_unless_zero(&hard_iface->refcount)) + continue; + ++ if (atomic_read(&hard_iface->no_rebroadcast) && ++ forw_packet->skb->dev == hard_iface->net_dev) -++ continue; +++ goto put_hardif; ++ -+ if (!kref_get_unless_zero(&hard_iface->refcount)) -+ continue; ++ /* send a copy of the saved skb */ ++ skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC); ++ if (skb1) ++ batadv_send_broadcast_skb(skb1, hard_iface); + +++put_hardif: ++ batadv_hardif_put(hard_iface); ++ } ++ rcu_read_unlock(); +diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c -+index 414b207..9aa043f 100644 ++index 02d96f2..f91d09c 100644 +--- a/net/batman-adv/sysfs.c ++++ b/net/batman-adv/sysfs.c -+@@ -134,6 +134,17 @@ struct batadv_attribute batadv_attr_vlan_##_name = { \ ++@@ -136,6 +136,17 @@ struct batadv_attribute batadv_attr_vlan_##_name = { \ + .store = _store, \ + } + @@ -142,7 +146,7 @@ index 0000000..e9f5ffb + /* Use this, if you have customized show and store functions */ + #define BATADV_ATTR(_name, _mode, _show, _store) \ + struct batadv_attribute batadv_attr_##_name = { \ -+@@ -293,6 +304,52 @@ ssize_t batadv_show_##_name(struct kobject *kobj, \ ++@@ -295,6 +306,52 @@ ssize_t batadv_show_##_name(struct kobject *kobj, \ + static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ + batadv_store_##_name) + @@ -195,7 +199,7 @@ index 0000000..e9f5ffb + static int batadv_store_bool_attr(char *buff, size_t count, + struct net_device *net_dev, + const char *attr_name, atomic_t *attr, -+@@ -993,6 +1050,7 @@ static ssize_t batadv_show_throughput_override(struct kobject *kobj, ++@@ -1119,6 +1176,7 @@ static ssize_t batadv_show_throughput_override(struct kobject *kobj, + static BATADV_ATTR(mesh_iface, S_IRUGO | S_IWUSR, batadv_show_mesh_iface, + batadv_store_mesh_iface); + static BATADV_ATTR(iface_status, S_IRUGO, batadv_show_iface_status, NULL); @@ -203,7 +207,7 @@ index 0000000..e9f5ffb + #ifdef CONFIG_BATMAN_ADV_BATMAN_V + BATADV_ATTR_HIF_UINT(elp_interval, bat_v.elp_interval, S_IRUGO | S_IWUSR, + 2 * BATADV_JITTER, INT_MAX, NULL); -+@@ -1004,6 +1062,7 @@ static BATADV_ATTR(throughput_override, S_IRUGO | S_IWUSR, ++@@ -1130,6 +1188,7 @@ static BATADV_ATTR(throughput_override, S_IRUGO | S_IWUSR, + static struct batadv_attribute *batadv_batman_attrs[] = { + &batadv_attr_mesh_iface, + &batadv_attr_iface_status, @@ -212,7 +216,7 @@ index 0000000..e9f5ffb + &batadv_attr_elp_interval, + &batadv_attr_throughput_override, +diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h -+index ba846b0..1a596c5 100644 ++index b3dd1a3..9ee810d 100644 +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -156,6 +156,7 @@ struct batadv_hard_iface { @@ -223,6 +227,3 @@ index 0000000..e9f5ffb + }; + + /** -+-- -+2.8.3 -+ diff --git a/patches/packages/routing/0003-batman-adv-decrease-maximum-fragment-size.patch b/patches/packages/routing/0003-batman-adv-decrease-maximum-fragment-size.patch index ede150b3..d0929d34 100644 --- a/patches/packages/routing/0003-batman-adv-decrease-maximum-fragment-size.patch +++ b/patches/packages/routing/0003-batman-adv-decrease-maximum-fragment-size.patch @@ -4,27 +4,22 @@ Subject: batman-adv: decrease maximum fragment size diff --git a/batman-adv/patches/1002-batman-adv-decrease-maximum-fragment-size.patch b/batman-adv/patches/1002-batman-adv-decrease-maximum-fragment-size.patch new file mode 100644 -index 0000000..a97146b +index 0000000..011380e --- /dev/null +++ b/batman-adv/patches/1002-batman-adv-decrease-maximum-fragment-size.patch -@@ -0,0 +1,28 @@ -+From 9e7384fde3c5a71f733221a137fdc4593a9638be Mon Sep 17 00:00:00 2001 -+Message-Id: <9e7384fde3c5a71f733221a137fdc4593a9638be.1466048916.git.mschiffer@universe-factory.net> -+In-Reply-To: <8e4c2084bbf2a65ad663a2b1ba27144e5dadfd5f.1466048916.git.mschiffer@universe-factory.net> -+References: <8e4c2084bbf2a65ad663a2b1ba27144e5dadfd5f.1466048916.git.mschiffer@universe-factory.net> +@@ -0,0 +1,20 @@ +From: Matthias Schiffer +Date: Thu, 6 Aug 2015 22:27:01 +0200 -+Subject: [PATCH 2/2] batman-adv: decrease maximum fragment size -+ ++Subject: [PATCH] batman-adv: decrease maximum fragment size +--- + net/batman-adv/main.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h -+index 7692526..d314e6c 100644 ++index 09af21e..23ebb8e 100644 +--- a/net/batman-adv/main.h ++++ b/net/batman-adv/main.h -+@@ -159,7 +159,7 @@ enum batadv_uev_type { ++@@ -167,7 +167,7 @@ enum batadv_uev_type { + /* Maximum number of fragments for one packet */ + #define BATADV_FRAG_MAX_FRAGMENTS 16 + /* Maxumim size of each fragment */ @@ -33,6 +28,3 @@ index 0000000..a97146b + /* Time to keep fragments while waiting for rest of the fragments */ + #define BATADV_FRAG_TIMEOUT 10000 + -+-- -+2.8.3 -+ From 27501ae6942df6d91dd370d565fb489e50a01554 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 8 Dec 2016 19:53:16 +0100 Subject: [PATCH 2/4] kernel: Add uapi/batman_adv.h from batman-adv 2016.4 The batman_adv.h is required by userspace applications to send/receive generic netlink messages. This file either has to be included in each program which uses it (like iw/hostapd/wavemon/... does it for nl80211.h) or the included file in the uapi kernel headers has to be patched to always be at the correct version. gluon decided to prefer a patched kernel to reduce the number of copies of this file in its own sources. Signed-off-by: Sven Eckelmann --- ...-batman_adv.h-from-batman-adv-2016.4.patch | 240 ++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 patches/openwrt/0083-kernel-Add-uapi-batman_adv.h-from-batman-adv-2016.4.patch diff --git a/patches/openwrt/0083-kernel-Add-uapi-batman_adv.h-from-batman-adv-2016.4.patch b/patches/openwrt/0083-kernel-Add-uapi-batman_adv.h-from-batman-adv-2016.4.patch new file mode 100644 index 00000000..5b78db9d --- /dev/null +++ b/patches/openwrt/0083-kernel-Add-uapi-batman_adv.h-from-batman-adv-2016.4.patch @@ -0,0 +1,240 @@ +From: Sven Eckelmann +Date: Thu, 8 Dec 2016 19:46:21 +0100 +Subject: kernel: Add uapi/batman_adv.h from batman-adv 2016.4 + +The batman_adv.h is required by userspace applications to send/receive +generic netlink messages. This file either has to be included in each +program which uses it (like iw/hostapd/wavemon/... does it for nl80211.h) +or the included file in the uapi kernel headers has to be patched to always +be at the correct version. + +gluon decided to prefer a patched kernel to reduce the number of copies of +this file in its own sources. + +diff --git a/target/linux/generic/patches-3.18/690-uapi-batman_adv.patch b/target/linux/generic/patches-3.18/690-uapi-batman_adv.patch +new file mode 100644 +index 0000000000..b5063eb64b +--- /dev/null ++++ b/target/linux/generic/patches-3.18/690-uapi-batman_adv.patch +@@ -0,0 +1,221 @@ ++--- /dev/null +++++ b/include/uapi/linux/batman_adv.h ++@@ -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_ */ ++--- a/include/uapi/linux/Kbuild +++++ b/include/uapi/linux/Kbuild ++@@ -61,6 +61,7 @@ header-y += auto_fs4.h ++ header-y += auxvec.h ++ header-y += ax25.h ++ header-y += b1lli.h +++header-y += batman_adv.h ++ header-y += baycom.h ++ header-y += bcm933xx_hcs.h ++ header-y += bfs_fs.h From 4bbd073f7325fe187f257070c3ea8a020ac5c025 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sat, 24 Sep 2016 19:59:44 +0200 Subject: [PATCH 3/4] 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 --- package/gluon-status-page-api/Makefile | 2 +- package/gluon-status-page-api/src/Makefile | 21 ++- .../src/neighbours-batadv.c | 125 ++++++++++---- package/gluon-status-page-api/src/netlink.c | 155 ++++++++++++++++++ package/gluon-status-page-api/src/netlink.h | 49 ++++++ 5 files changed, 320 insertions(+), 32 deletions(-) create mode 100644 package/gluon-status-page-api/src/netlink.c create mode 100644 package/gluon-status-page-api/src/netlink.h diff --git a/package/gluon-status-page-api/Makefile b/package/gluon-status-page-api/Makefile index ddad2cab..703d97f6 100644 --- a/package/gluon-status-page-api/Makefile +++ b/package/gluon-status-page-api/Makefile @@ -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 diff --git a/package/gluon-status-page-api/src/Makefile b/package/gluon-status-page-api/src/Makefile index 81b48b6d..319ee5a5 100644 --- a/package/gluon-status-page-api/src/Makefile +++ b/package/gluon-status-page-api/src/Makefile @@ -1,11 +1,30 @@ 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 += $(LIBNL_CFLAGS) +LDLIBS += $(LIBNL_LDLIBS) 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 +neighbours-batadv: neighbours-batadv.c netlink.c $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LDFLAGS) $(LDFLAGS_JSONC) -Wall -o $@ $^ $(LDLIBS) stations: stations.c diff --git a/package/gluon-status-page-api/src/neighbours-batadv.c b/package/gluon-status-page-api/src/neighbours-batadv.c index f0a484b2..8cc3f0a6 100644 --- a/package/gluon-status-page-api/src/neighbours-batadv.c +++ b/package/gluon-status-page-api/src/neighbours-batadv.c @@ -2,47 +2,112 @@ #include #include #include +#include #include +#include "netlink.h" + #define STR(x) #x #define XSTR(x) STR(x) +struct neigh_netlink_opts { + struct json_object *obj; + struct nlquery_opts query_opts; +}; + +static const int 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 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 (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]); + 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 = netlink_query_common("bat0", BATADV_CMD_GET_ORIGINATORS, + parse_orig_list_netlink_cb, &opts.query_opts); + if (ret < 0) { + json_object_put(opts.obj); + return NULL; } - fclose(f); - - return obj; + return opts.obj; } int main(void) { diff --git a/package/gluon-status-page-api/src/netlink.c b/package/gluon-status-page-api/src/netlink.c new file mode 100644 index 00000000..127b6c03 --- /dev/null +++ b/package/gluon-status-page-api/src/netlink.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2009-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner , Andrew Lunn + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 }, +}; + +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 __maybe_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; +} diff --git a/package/gluon-status-page-api/src/netlink.h b/package/gluon-status-page-api/src/netlink.h new file mode 100644 index 00000000..56e841a6 --- /dev/null +++ b/package/gluon-status-page-api/src/netlink.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner , Andrew Lunn + * + * 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 +#include +#include + +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); + +extern struct nla_policy batadv_netlink_policy[]; + +#endif /* _BATADV_NETLINK_H */ From 223ffce972ece5a52af993900f7283f8a3ec5516 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sat, 24 Sep 2016 19:59:44 +0200 Subject: [PATCH 4/4] gluon-mesh-batman-adv-core: 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. The respondd module of gluon-mesh-batman-adv-core can therefore parse larger originator tables without causing an OOM on systems which are tight on memory. Signed-off-by: Sven Eckelmann --- package/gluon-mesh-batman-adv-core/Makefile | 2 +- .../gluon-mesh-batman-adv-core/src/Makefile | 20 +- .../gluon-mesh-batman-adv-core/src/netlink.c | 159 +++++++++ .../gluon-mesh-batman-adv-core/src/netlink.h | 47 +++ .../gluon-mesh-batman-adv-core/src/respondd.c | 302 +++++++++++++----- 5 files changed, 448 insertions(+), 82 deletions(-) create mode 100644 package/gluon-mesh-batman-adv-core/src/netlink.c create mode 100644 package/gluon-mesh-batman-adv-core/src/netlink.h diff --git a/package/gluon-mesh-batman-adv-core/Makefile b/package/gluon-mesh-batman-adv-core/Makefile index efcf1698..af5016f7 100644 --- a/package/gluon-mesh-batman-adv-core/Makefile +++ b/package/gluon-mesh-batman-adv-core/Makefile @@ -13,7 +13,7 @@ define Package/gluon-mesh-batman-adv-core SECTION:=gluon CATEGORY:=Gluon TITLE:=Support for batman-adv meshing (core) - DEPENDS:=+gluon-core +libgluonutil +gluon-client-bridge +firewall +libiwinfo +kmod-dummy + DEPENDS:=+gluon-core +libgluonutil +gluon-client-bridge +firewall +libiwinfo +kmod-dummy +libnl-tiny endef define Build/Prepare diff --git a/package/gluon-mesh-batman-adv-core/src/Makefile b/package/gluon-mesh-batman-adv-core/src/Makefile index 84d9d48e..75ec0ebe 100644 --- a/package/gluon-mesh-batman-adv-core/src/Makefile +++ b/package/gluon-mesh-batman-adv-core/src/Makefile @@ -2,5 +2,23 @@ all: respondd.so CFLAGS += -Wall -respondd.so: respondd.c +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 += $(LIBNL_CFLAGS) +LDLIBS += $(LIBNL_LDLIBS) + +respondd.so: respondd.c netlink.c $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -liwinfo -luci diff --git a/package/gluon-mesh-batman-adv-core/src/netlink.c b/package/gluon-mesh-batman-adv-core/src/netlink.c new file mode 100644 index 00000000..41be404b --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/src/netlink.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2009-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner , Andrew Lunn + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_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_ROUTER] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, +}; + +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 __maybe_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; +} diff --git a/package/gluon-mesh-batman-adv-core/src/netlink.h b/package/gluon-mesh-batman-adv-core/src/netlink.h new file mode 100644 index 00000000..9594b213 --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/src/netlink.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner , Andrew Lunn + * + * 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 +#include +#include + +struct nlquery_opts { + int err; +}; + +#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); + +extern struct nla_policy batadv_netlink_policy[]; + +#endif /* _BATADV_NETLINK_H */ diff --git a/package/gluon-mesh-batman-adv-core/src/respondd.c b/package/gluon-mesh-batman-adv-core/src/respondd.c index ba14997a..04921bde 100644 --- a/package/gluon-mesh-batman-adv-core/src/respondd.c +++ b/package/gluon-mesh-batman-adv-core/src/respondd.c @@ -47,15 +47,34 @@ #include #include +#include #include #include #include +#include "netlink.h" + #define _STRINGIFY(s) #s #define STRINGIFY(s) _STRINGIFY(s) +struct neigh_netlink_opts { + struct json_object *interfaces; + struct nlquery_opts query_opts; +}; + +struct gw_netlink_opts { + struct json_object *obj; + struct nlquery_opts query_opts; +}; + +struct clients_netlink_opts { + size_t total; + size_t wifi; + struct nlquery_opts query_opts; +}; + static struct json_object * get_addresses(void) { FILE *f = fopen("/proc/net/if_inet6", "r"); @@ -223,29 +242,69 @@ static struct json_object * respondd_provider_nodeinfo(void) { return ret; } +static const int gateways_mandatory[] = { + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_ROUTER, +}; + +static int parse_gw_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 genlmsghdr *ghdr; + uint8_t *orig; + uint8_t *router; + struct gw_netlink_opts *opts; + char addr[18]; + + opts = container_of(query_opts, struct gw_netlink_opts, query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_GATEWAYS) + 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, gateways_mandatory, + ARRAY_SIZE(gateways_mandatory))) + return NL_OK; + + if (!attrs[BATADV_ATTR_FLAG_BEST]) + return NL_OK; + + orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); + router = nla_data(attrs[BATADV_ATTR_ROUTER]); + + sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", + orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); + + json_object_object_add(opts->obj, "gateway", json_object_new_string(addr)); + + sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", + router[0], router[1], router[2], router[3], router[4], router[5]); + + json_object_object_add(opts->obj, "gateway_nexthop", json_object_new_string(addr)); + + return NL_STOP; +} static void add_gateway(struct json_object *obj) { - FILE *f = fopen("/sys/kernel/debug/batman_adv/bat0/gateways", "r"); - if (!f) - return; + struct gw_netlink_opts opts = { + .obj = obj, + .query_opts = { + .err = 0, + }, + }; - char *line = NULL; - size_t len = 0; - - while (getline(&line, &len, f) >= 0) { - char addr[18]; - char nexthop[18]; - - if (sscanf(line, "=> %17[0-9a-fA-F:] ( %*u) %17[0-9a-fA-F:]", addr, nexthop) != 2) - continue; - - json_object_object_add(obj, "gateway", json_object_new_string(addr)); - json_object_object_add(obj, "gateway_nexthop", json_object_new_string(nexthop)); - break; - } - - free(line); - fclose(f); + netlink_query_common("bat0", BATADV_CMD_GET_GATEWAYS, + parse_gw_list_netlink_cb, &opts.query_opts); } static inline bool ethtool_ioctl(int fd, struct ifreq *ifr, void *data) { @@ -421,39 +480,68 @@ static void count_stations(size_t *wifi24, size_t *wifi5) { uci_free_context(ctx); } +static const int clients_mandatory[] = { + BATADV_ATTR_TT_FLAGS, +}; + +static int parse_clients_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 genlmsghdr *ghdr; + struct clients_netlink_opts *opts; + uint32_t flags; + + opts = container_of(query_opts, struct clients_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, clients_mandatory, + ARRAY_SIZE(clients_mandatory))) + return NL_OK; + + flags = nla_get_u32(attrs[BATADV_ATTR_TT_FLAGS]); + + if (flags & BATADV_TT_CLIENT_NOPURGE) + return NL_OK; + + if (flags & BATADV_TT_CLIENT_WIFI) + opts->wifi++; + + opts->total++; + + return NL_OK; +} + static struct json_object * get_clients(void) { - size_t total = 0, wifi = 0, wifi24 = 0, wifi5 = 0; + size_t wifi24 = 0, wifi5 = 0; + struct clients_netlink_opts opts = { + .total = 0, + .wifi = 0, + .query_opts = { + .err = 0, + }, + }; - FILE *f = fopen("/sys/kernel/debug/batman_adv/bat0/transtable_local", "r"); - if (!f) - return NULL; - - char *line = NULL; - size_t len = 0; - - while (getline(&line, &len, f) >= 0) { - char flags[16]; - - if (sscanf(line, " * %*[^[] [%15[^]]]", flags) != 1) - continue; - - if (strchr(flags, 'P')) - continue; - - total++; - - if (strchr(flags, 'W')) - wifi++; - } - - free(line); - fclose(f); + netlink_query_common("bat0", BATADV_CMD_GET_TRANSTABLE_LOCAL, + parse_clients_list_netlink_cb, &opts.query_opts); count_stations(&wifi24, &wifi5); struct json_object *ret = json_object_new_object(); - json_object_object_add(ret, "total", json_object_new_int(total)); - json_object_object_add(ret, "wifi", json_object_new_int(wifi)); + json_object_object_add(ret, "total", json_object_new_int(opts.total)); + json_object_object_add(ret, "wifi", json_object_new_int(opts.wifi)); json_object_object_add(ret, "wifi24", json_object_new_int(wifi24)); json_object_object_add(ret, "wifi5", json_object_new_int(wifi5)); return ret; @@ -492,49 +580,103 @@ static struct json_object * ifnames2addrs(struct json_object *interfaces) { return ret; } -static struct json_object * get_batadv(void) { - FILE *f = fopen("/sys/kernel/debug/batman_adv/bat0/originators", "r"); - if (!f) - return NULL; +static const int parse_orig_list_mandatory[] = { + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_NEIGH_ADDRESS, + BATADV_ATTR_TQ, + BATADV_ATTR_HARD_IFINDEX, + BATADV_ATTR_LAST_SEEN_MSECS, +}; - char *line = NULL; - size_t len = 0; +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 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]; - struct json_object *interfaces = json_object_new_object(); + opts = container_of(query_opts, struct neigh_netlink_opts, query_opts); - while (getline(&line, &len, f) >= 0) { - char mac1[18], mac2[18]; - /* IF_NAMESIZE would be enough, but adding 1 here is simpler than subtracting 1 in the format string */ - char ifname[IF_NAMESIZE+1]; - double lastseen; - int tq; + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; - if (sscanf(line, - "%17[0-9a-fA-F:] %lfs ( %i ) %17[0-9a-fA-F:] [ %"STRINGIFY(IF_NAMESIZE)"[^]] ]", - mac1, &lastseen, &tq, mac2, ifname) != 5) - continue; + ghdr = nlmsg_data(nlh); - if (strcmp(mac1, mac2)) - continue; + if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS) + return NL_OK; - struct json_object *interface; - if (!json_object_object_get_ex(interfaces, ifname, &interface)) { - interface = json_object_new_object(); - json_object_object_add(interfaces, ifname, interface); - } + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) + return NL_OK; - struct json_object *obj = json_object_new_object(); - json_object_object_add(obj, "tq", json_object_new_int(tq)); - struct json_object *jso = json_object_new_double(lastseen); - json_object_set_serializer(jso, json_object_double_to_json_string, "%.3f", NULL); - json_object_object_add(obj, "lastseen", jso); - json_object_object_add(interface, mac1, obj); + 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]); + 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 *obj = json_object_new_object(); + if (!obj) + return NL_OK; + + struct json_object *interface; + if (!json_object_object_get_ex(opts->interfaces, ifname, &interface)) { + interface = json_object_new_object(); + json_object_object_add(opts->interfaces, ifname, interface); } - fclose(f); - free(line); + json_object_object_add(obj, "tq", json_object_new_int(tq)); + json_object_object_add(obj, "lastseen", json_object_new_double(lastseen / 1000.)); + json_object_object_add(interface, mac1, obj); - return ifnames2addrs(interfaces); + return NL_OK; +} + +static struct json_object * get_batadv(void) { + struct neigh_netlink_opts opts = { + .query_opts = { + .err = 0, + }, + }; + int ret; + + opts.interfaces = json_object_new_object(); + if (!opts.interfaces) + return NULL; + + ret = netlink_query_common("bat0", BATADV_CMD_GET_ORIGINATORS, + parse_orig_list_netlink_cb, &opts.query_opts); + if (ret < 0) { + json_object_put(opts.interfaces); + return NULL; + } + + return ifnames2addrs(opts.interfaces); } static struct json_object * get_wifi_neighbours(const char *ifname) {