This feature patchset is all about adding netlink support, which should
supersede our debugfs configuration interface in the long run. It is especially necessary when batman-adv should be used in different namespaces, since debugfs can not differentiate between those. More specifically, the following changes are included: - Two fixes for namespace handling by Andrew Lunn, checking also the namespaces for parent interfaces, and supress debugfs entries for non-default netns - Implement various netlink commands for the new interface, by Matthias Schiffer, Andrew Lunn, Sven Eckelmann and Simon Wunderlich (13 patches): * routing algorithm list * hardif list * translation tables (local and global) * TTVN for the translation tables * originator and neighbor tables for B.A.T.M.A.N. IV and B.A.T.M.A.N. V * gateway dump functionality for B.A.T.M.A.N. IV and B.A.T.M.A.N. V * Bridge Loop Avoidance claims, and corresponding BLA group * Bridge Loop Avoidance backbone tables - Finally, mark batman-adv as netns compatible, by Andrew Lunn (1 patch) -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdBQJXss7MFhxzd0BzaW1vbnd1bmRlcmxpY2guZGUACgkQoSvjmEKS nqGvTBAAw7A0lG5ghEEDTVWl++/q3fc41ZPn+XGihizQ3z9Hy5ZAuyREKqMz43RP MJb2sHnoS/guCY7Y0Mn/ubQDuvp7PmqJxNmHiqdW0UVKrwgRrlhk/uZfd3Blib8J TR1ktRAT/OKtPIxps2CSq2UX1GcnadtstaUvDDSWnak/0zsQl5GWVYxOkbdsbYUb qYAbcHBXkdvTfIpZxSwb3QDfKoRs+Hf8hr09V19DH/GZs4puYbIxjw1QhC2TBe0f SkcMVkmQ6GqJsjRU4BDVCrrfYvv3ncBWXtb5CKyq8il2AvdI1HbXha9hpg0SO69p fAC5yzyB0rCCr7AKMYBgeIf9u6z5mllKly9QJkZMjtWuIIxt4J5rFK2PN+M3xprb BWXrINWR4/1C4LA3dDvCL7sFHlObHVKRjSNwzmQ3b6UNY72d6UILG0D9JTI8M+y7 YXtjwCQYNCvjmkprM6mgPMnlk90RdXNhNUngfOe2/2C1li2gaodX7lrx+lBS8/5N oK5W85vmO41FChLFof5PV6mn4cUV7sKlKPmv93xRvHd89RWBWIU/kGpQQjkCgh5U 44CJiD+FDRkEkDJVo7IkqTxGF39zYR39mQrNFXc6G1H4wRFtqHGP+VOa72a/7arV FeGtulzeGBK3z1Qi9UyjS2N9mDYSKkfj4f2H+AC1GCRC2mTMCQU= =KDfF -----END PGP SIGNATURE----- Merge tag 'batadv-next-for-davem-20160816' of git://git.open-mesh.org/linux-merge Simon Wunderlich says: ==================== pull request for net-next: batman-adv 2016-08-16 This feature patchset is all about adding netlink support, which should supersede our debugfs configuration interface in the long run. It is especially necessary when batman-adv should be used in different namespaces, since debugfs can not differentiate between those. More specifically, the following changes are included: - Two fixes for namespace handling by Andrew Lunn, checking also the namespaces for parent interfaces, and supress debugfs entries for non-default netns - Implement various netlink commands for the new interface, by Matthias Schiffer, Andrew Lunn, Sven Eckelmann and Simon Wunderlich (13 patches): * routing algorithm list * hardif list * translation tables (local and global) * TTVN for the translation tables * originator and neighbor tables for B.A.T.M.A.N. IV and B.A.T.M.A.N. V * gateway dump functionality for B.A.T.M.A.N. IV and B.A.T.M.A.N. V * Bridge Loop Avoidance claims, and corresponding BLA group * Bridge Loop Avoidance backbone tables - Finally, mark batman-adv as netns compatible, by Andrew Lunn (1 patch) ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
00062a934b
|
@ -22,6 +22,42 @@
|
|||
|
||||
#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
|
||||
*
|
||||
|
@ -40,6 +76,26 @@
|
|||
* @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
|
||||
|
@ -60,6 +116,26 @@ enum batadv_nl_attrs {
|
|||
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,
|
||||
|
@ -73,6 +149,15 @@ enum batadv_nl_attrs {
|
|||
* @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
|
||||
*/
|
||||
|
@ -81,6 +166,15 @@ enum batadv_nl_commands {
|
|||
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
|
||||
|
|
|
@ -20,12 +20,18 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/string.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/netlink.h>
|
||||
#include <uapi/linux/batman_adv.h>
|
||||
|
||||
#include "bat_algo.h"
|
||||
#include "netlink.h"
|
||||
|
||||
char batadv_routing_algo[20] = "BATMAN_IV";
|
||||
static struct hlist_head batadv_algo_list;
|
||||
|
@ -138,3 +144,65 @@ static struct kparam_string batadv_param_string_ra = {
|
|||
|
||||
module_param_cb(routing_algo, &batadv_param_ops_ra, &batadv_param_string_ra,
|
||||
0644);
|
||||
|
||||
/**
|
||||
* batadv_algo_dump_entry - fill in information about one supported routing
|
||||
* algorithm
|
||||
* @msg: netlink message to be sent back
|
||||
* @portid: Port to reply to
|
||||
* @seq: Sequence number of message
|
||||
* @bat_algo_ops: Algorithm to be dumped
|
||||
*
|
||||
* Return: Error number, or 0 on success
|
||||
*/
|
||||
static int batadv_algo_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_algo_ops *bat_algo_ops)
|
||||
{
|
||||
void *hdr;
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
|
||||
NLM_F_MULTI, BATADV_CMD_GET_ROUTING_ALGOS);
|
||||
if (!hdr)
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (nla_put_string(msg, BATADV_ATTR_ALGO_NAME, bat_algo_ops->name))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_algo_dump - fill in information about supported routing
|
||||
* algorithms
|
||||
* @msg: netlink message to be sent back
|
||||
* @cb: Parameters to the netlink request
|
||||
*
|
||||
* Return: Length of reply message.
|
||||
*/
|
||||
int batadv_algo_dump(struct sk_buff *msg, struct netlink_callback *cb)
|
||||
{
|
||||
int portid = NETLINK_CB(cb->skb).portid;
|
||||
struct batadv_algo_ops *bat_algo_ops;
|
||||
int skip = cb->args[0];
|
||||
int i = 0;
|
||||
|
||||
hlist_for_each_entry(bat_algo_ops, &batadv_algo_list, list) {
|
||||
if (i++ < skip)
|
||||
continue;
|
||||
|
||||
if (batadv_algo_dump_entry(msg, portid, cb->nlh->nlmsg_seq,
|
||||
bat_algo_ops)) {
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cb->args[0] = i;
|
||||
|
||||
return msg->len;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct netlink_callback;
|
||||
struct seq_file;
|
||||
struct sk_buff;
|
||||
|
||||
extern char batadv_routing_algo[];
|
||||
extern struct list_head batadv_hardif_list;
|
||||
|
@ -31,5 +33,6 @@ void batadv_algo_init(void);
|
|||
int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops);
|
||||
int batadv_algo_select(struct batadv_priv *bat_priv, char *name);
|
||||
int batadv_algo_seq_print_text(struct seq_file *seq, void *offset);
|
||||
int batadv_algo_dump(struct sk_buff *msg, struct netlink_callback *cb);
|
||||
|
||||
#endif /* _NET_BATMAN_ADV_BAT_ALGO_H_ */
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/pkt_sched.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/random.h>
|
||||
|
@ -48,6 +49,9 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/netlink.h>
|
||||
#include <uapi/linux/batman_adv.h>
|
||||
|
||||
#include "bat_algo.h"
|
||||
#include "bitarray.h"
|
||||
|
@ -55,6 +59,7 @@
|
|||
#include "hard-interface.h"
|
||||
#include "hash.h"
|
||||
#include "log.h"
|
||||
#include "netlink.h"
|
||||
#include "network-coding.h"
|
||||
#include "originator.h"
|
||||
#include "packet.h"
|
||||
|
@ -1947,6 +1952,235 @@ next:
|
|||
seq_puts(seq, "No batman nodes in range ...\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_ogm_neigh_get_tq_avg - Get the TQ average for a neighbour on a
|
||||
* given outgoing interface.
|
||||
* @neigh_node: Neighbour of interest
|
||||
* @if_outgoing: Outgoing interface of interest
|
||||
* @tq_avg: Pointer of where to store the TQ average
|
||||
*
|
||||
* Return: False if no average TQ available, otherwise true.
|
||||
*/
|
||||
static bool
|
||||
batadv_iv_ogm_neigh_get_tq_avg(struct batadv_neigh_node *neigh_node,
|
||||
struct batadv_hard_iface *if_outgoing,
|
||||
u8 *tq_avg)
|
||||
{
|
||||
struct batadv_neigh_ifinfo *n_ifinfo;
|
||||
|
||||
n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
|
||||
if (!n_ifinfo)
|
||||
return false;
|
||||
|
||||
*tq_avg = n_ifinfo->bat_iv.tq_avg;
|
||||
batadv_neigh_ifinfo_put(n_ifinfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_ogm_orig_dump_subentry - Dump an originator subentry into a
|
||||
* message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @if_outgoing: Limit dump to entries with this outgoing interface
|
||||
* @orig_node: Originator to dump
|
||||
* @neigh_node: Single hops neighbour
|
||||
* @best: Is the best originator
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_iv_ogm_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *if_outgoing,
|
||||
struct batadv_orig_node *orig_node,
|
||||
struct batadv_neigh_node *neigh_node,
|
||||
bool best)
|
||||
{
|
||||
void *hdr;
|
||||
u8 tq_avg;
|
||||
unsigned int last_seen_msecs;
|
||||
|
||||
last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen);
|
||||
|
||||
if (!batadv_iv_ogm_neigh_get_tq_avg(neigh_node, if_outgoing, &tq_avg))
|
||||
return 0;
|
||||
|
||||
if (if_outgoing != BATADV_IF_DEFAULT &&
|
||||
if_outgoing != neigh_node->if_incoming)
|
||||
return 0;
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
|
||||
NLM_F_MULTI, BATADV_CMD_GET_ORIGINATORS);
|
||||
if (!hdr)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
|
||||
orig_node->orig) ||
|
||||
nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
|
||||
neigh_node->addr) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
|
||||
neigh_node->if_incoming->net_dev->ifindex) ||
|
||||
nla_put_u8(msg, BATADV_ATTR_TQ, tq_avg) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
|
||||
last_seen_msecs))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_ogm_orig_dump_entry - Dump an originator entry into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @if_outgoing: Limit dump to entries with this outgoing interface
|
||||
* @orig_node: Originator to dump
|
||||
* @sub_s: Number of sub entries to skip
|
||||
*
|
||||
* This function assumes the caller holds rcu_read_lock().
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_iv_ogm_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *if_outgoing,
|
||||
struct batadv_orig_node *orig_node, int *sub_s)
|
||||
{
|
||||
struct batadv_neigh_node *neigh_node_best;
|
||||
struct batadv_neigh_node *neigh_node;
|
||||
int sub = 0;
|
||||
bool best;
|
||||
u8 tq_avg_best;
|
||||
|
||||
neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing);
|
||||
if (!neigh_node_best)
|
||||
goto out;
|
||||
|
||||
if (!batadv_iv_ogm_neigh_get_tq_avg(neigh_node_best, if_outgoing,
|
||||
&tq_avg_best))
|
||||
goto out;
|
||||
|
||||
if (tq_avg_best == 0)
|
||||
goto out;
|
||||
|
||||
hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
|
||||
if (sub++ < *sub_s)
|
||||
continue;
|
||||
|
||||
best = (neigh_node == neigh_node_best);
|
||||
|
||||
if (batadv_iv_ogm_orig_dump_subentry(msg, portid, seq,
|
||||
bat_priv, if_outgoing,
|
||||
orig_node, neigh_node,
|
||||
best)) {
|
||||
batadv_neigh_node_put(neigh_node_best);
|
||||
|
||||
*sub_s = sub - 1;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (neigh_node_best)
|
||||
batadv_neigh_node_put(neigh_node_best);
|
||||
|
||||
*sub_s = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_ogm_orig_dump_bucket - Dump an originator bucket into a
|
||||
* message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @if_outgoing: Limit dump to entries with this outgoing interface
|
||||
* @head: Bucket to be dumped
|
||||
* @idx_s: Number of entries to be skipped
|
||||
* @sub: Number of sub entries to be skipped
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_iv_ogm_orig_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *if_outgoing,
|
||||
struct hlist_head *head, int *idx_s, int *sub)
|
||||
{
|
||||
struct batadv_orig_node *orig_node;
|
||||
int idx = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
|
||||
if (idx++ < *idx_s)
|
||||
continue;
|
||||
|
||||
if (batadv_iv_ogm_orig_dump_entry(msg, portid, seq, bat_priv,
|
||||
if_outgoing, orig_node,
|
||||
sub)) {
|
||||
rcu_read_unlock();
|
||||
*idx_s = idx - 1;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
*idx_s = 0;
|
||||
*sub = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_ogm_orig_dump - Dump the originators into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @cb: Control block containing additional options
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @if_outgoing: Limit dump to entries with this outgoing interface
|
||||
*/
|
||||
static void
|
||||
batadv_iv_ogm_orig_dump(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *if_outgoing)
|
||||
{
|
||||
struct batadv_hashtable *hash = bat_priv->orig_hash;
|
||||
struct hlist_head *head;
|
||||
int bucket = cb->args[0];
|
||||
int idx = cb->args[1];
|
||||
int sub = cb->args[2];
|
||||
int portid = NETLINK_CB(cb->skb).portid;
|
||||
|
||||
while (bucket < hash->size) {
|
||||
head = &hash->table[bucket];
|
||||
|
||||
if (batadv_iv_ogm_orig_dump_bucket(msg, portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
bat_priv, if_outgoing, head,
|
||||
&idx, &sub))
|
||||
break;
|
||||
|
||||
bucket++;
|
||||
}
|
||||
|
||||
cb->args[0] = bucket;
|
||||
cb->args[1] = idx;
|
||||
cb->args[2] = sub;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_hardif_neigh_print - print a single hop neighbour node
|
||||
* @seq: neighbour table seq_file struct
|
||||
|
@ -2043,6 +2277,136 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_ogm_neigh_dump_neigh - Dump a neighbour into a netlink message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @hardif_neigh: Neighbour to be dumped
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_iv_ogm_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_hardif_neigh_node *hardif_neigh)
|
||||
{
|
||||
void *hdr;
|
||||
unsigned int last_seen_msecs;
|
||||
|
||||
last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen);
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
|
||||
NLM_F_MULTI, BATADV_CMD_GET_NEIGHBORS);
|
||||
if (!hdr)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
|
||||
hardif_neigh->addr) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
|
||||
hardif_neigh->if_incoming->net_dev->ifindex) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
|
||||
last_seen_msecs))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_ogm_neigh_dump_hardif - Dump the neighbours of a hard interface
|
||||
* into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @hard_iface: Hard interface to dump the neighbours for
|
||||
* @idx_s: Number of entries to skip
|
||||
*
|
||||
* This function assumes the caller holds rcu_read_lock().
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_iv_ogm_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *hard_iface,
|
||||
int *idx_s)
|
||||
{
|
||||
struct batadv_hardif_neigh_node *hardif_neigh;
|
||||
int idx = 0;
|
||||
|
||||
hlist_for_each_entry_rcu(hardif_neigh,
|
||||
&hard_iface->neigh_list, list) {
|
||||
if (idx++ < *idx_s)
|
||||
continue;
|
||||
|
||||
if (batadv_iv_ogm_neigh_dump_neigh(msg, portid, seq,
|
||||
hardif_neigh)) {
|
||||
*idx_s = idx - 1;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
*idx_s = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_ogm_neigh_dump - Dump the neighbours into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @cb: Control block containing additional options
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @single_hardif: Limit dump to this hard interfaace
|
||||
*/
|
||||
static void
|
||||
batadv_iv_ogm_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *single_hardif)
|
||||
{
|
||||
struct batadv_hard_iface *hard_iface;
|
||||
int i_hardif = 0;
|
||||
int i_hardif_s = cb->args[0];
|
||||
int idx = cb->args[1];
|
||||
int portid = NETLINK_CB(cb->skb).portid;
|
||||
|
||||
rcu_read_lock();
|
||||
if (single_hardif) {
|
||||
if (i_hardif_s == 0) {
|
||||
if (batadv_iv_ogm_neigh_dump_hardif(msg, portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
bat_priv,
|
||||
single_hardif,
|
||||
&idx) == 0)
|
||||
i_hardif++;
|
||||
}
|
||||
} else {
|
||||
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list,
|
||||
list) {
|
||||
if (hard_iface->soft_iface != bat_priv->soft_iface)
|
||||
continue;
|
||||
|
||||
if (i_hardif++ < i_hardif_s)
|
||||
continue;
|
||||
|
||||
if (batadv_iv_ogm_neigh_dump_hardif(msg, portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
bat_priv,
|
||||
hard_iface, &idx)) {
|
||||
i_hardif--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
cb->args[0] = i_hardif;
|
||||
cb->args[1] = idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors
|
||||
* @neigh1: the first neighbor object of the comparison
|
||||
|
@ -2317,6 +2681,110 @@ static void batadv_iv_gw_print(struct batadv_priv *bat_priv,
|
|||
seq_puts(seq, "No gateways in range ...\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_gw_dump_entry - Dump a gateway into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @gw_node: Gateway to be dumped
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_gw_node *gw_node)
|
||||
{
|
||||
struct batadv_neigh_ifinfo *router_ifinfo = NULL;
|
||||
struct batadv_neigh_node *router;
|
||||
struct batadv_gw_node *curr_gw;
|
||||
int ret = -EINVAL;
|
||||
void *hdr;
|
||||
|
||||
router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
|
||||
if (!router)
|
||||
goto out;
|
||||
|
||||
router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
|
||||
if (!router_ifinfo)
|
||||
goto out;
|
||||
|
||||
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
|
||||
NLM_F_MULTI, BATADV_CMD_GET_GATEWAYS);
|
||||
if (!hdr) {
|
||||
ret = -ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = -EMSGSIZE;
|
||||
|
||||
if (curr_gw == gw_node)
|
||||
if (nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
|
||||
gw_node->orig_node->orig) ||
|
||||
nla_put_u8(msg, BATADV_ATTR_TQ, router_ifinfo->bat_iv.tq_avg) ||
|
||||
nla_put(msg, BATADV_ATTR_ROUTER, ETH_ALEN,
|
||||
router->addr) ||
|
||||
nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
|
||||
router->if_incoming->net_dev->name) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN,
|
||||
gw_node->bandwidth_down) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_UP,
|
||||
gw_node->bandwidth_up)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (router_ifinfo)
|
||||
batadv_neigh_ifinfo_put(router_ifinfo);
|
||||
if (router)
|
||||
batadv_neigh_node_put(router);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_gw_dump - Dump gateways into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @cb: Control block containing additional options
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
*/
|
||||
static void batadv_iv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
struct batadv_priv *bat_priv)
|
||||
{
|
||||
int portid = NETLINK_CB(cb->skb).portid;
|
||||
struct batadv_gw_node *gw_node;
|
||||
int idx_skip = cb->args[0];
|
||||
int idx = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) {
|
||||
if (idx++ < idx_skip)
|
||||
continue;
|
||||
|
||||
if (batadv_iv_gw_dump_entry(msg, portid, cb->nlh->nlmsg_seq,
|
||||
bat_priv, gw_node)) {
|
||||
idx_skip = idx - 1;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
idx_skip = idx;
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
cb->args[0] = idx_skip;
|
||||
}
|
||||
|
||||
static struct batadv_algo_ops batadv_batman_iv __read_mostly = {
|
||||
.name = "BATMAN_IV",
|
||||
.iface = {
|
||||
|
@ -2330,9 +2798,11 @@ static struct batadv_algo_ops batadv_batman_iv __read_mostly = {
|
|||
.cmp = batadv_iv_ogm_neigh_cmp,
|
||||
.is_similar_or_better = batadv_iv_ogm_neigh_is_sob,
|
||||
.print = batadv_iv_neigh_print,
|
||||
.dump = batadv_iv_ogm_neigh_dump,
|
||||
},
|
||||
.orig = {
|
||||
.print = batadv_iv_ogm_orig_print,
|
||||
.dump = batadv_iv_ogm_orig_dump,
|
||||
.free = batadv_iv_ogm_orig_free,
|
||||
.add_if = batadv_iv_ogm_orig_add_if,
|
||||
.del_if = batadv_iv_ogm_orig_del_if,
|
||||
|
@ -2341,6 +2811,7 @@ static struct batadv_algo_ops batadv_batman_iv __read_mostly = {
|
|||
.get_best_gw_node = batadv_iv_gw_get_best_gw_node,
|
||||
.is_eligible = batadv_iv_gw_is_eligible,
|
||||
.print = batadv_iv_gw_print,
|
||||
.dump = batadv_iv_gw_dump,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -22,17 +22,22 @@
|
|||
#include <linux/bug.h>
|
||||
#include <linux/cache.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/netlink.h>
|
||||
#include <uapi/linux/batman_adv.h>
|
||||
|
||||
#include "bat_algo.h"
|
||||
#include "bat_v_elp.h"
|
||||
|
@ -42,9 +47,12 @@
|
|||
#include "hard-interface.h"
|
||||
#include "hash.h"
|
||||
#include "log.h"
|
||||
#include "netlink.h"
|
||||
#include "originator.h"
|
||||
#include "packet.h"
|
||||
|
||||
struct sk_buff;
|
||||
|
||||
static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
|
||||
|
@ -205,6 +213,138 @@ static void batadv_v_neigh_print(struct batadv_priv *bat_priv,
|
|||
seq_puts(seq, "No batman nodes in range ...\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_neigh_dump_neigh - Dump a neighbour into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @hardif_neigh: Neighbour to dump
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_v_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_hardif_neigh_node *hardif_neigh)
|
||||
{
|
||||
void *hdr;
|
||||
unsigned int last_seen_msecs;
|
||||
u32 throughput;
|
||||
|
||||
last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen);
|
||||
throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
|
||||
throughput = throughput * 100;
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
|
||||
BATADV_CMD_GET_NEIGHBORS);
|
||||
if (!hdr)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
|
||||
hardif_neigh->addr) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
|
||||
hardif_neigh->if_incoming->net_dev->ifindex) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
|
||||
last_seen_msecs) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_neigh_dump_hardif - Dump the neighbours of a hard interface into
|
||||
* a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @hard_iface: The hard interface to be dumped
|
||||
* @idx_s: Entries to be skipped
|
||||
*
|
||||
* This function assumes the caller holds rcu_read_lock().
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_v_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *hard_iface,
|
||||
int *idx_s)
|
||||
{
|
||||
struct batadv_hardif_neigh_node *hardif_neigh;
|
||||
int idx = 0;
|
||||
|
||||
hlist_for_each_entry_rcu(hardif_neigh,
|
||||
&hard_iface->neigh_list, list) {
|
||||
if (idx++ < *idx_s)
|
||||
continue;
|
||||
|
||||
if (batadv_v_neigh_dump_neigh(msg, portid, seq, hardif_neigh)) {
|
||||
*idx_s = idx - 1;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
*idx_s = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_neigh_dump - Dump the neighbours of a hard interface into a
|
||||
* message
|
||||
* @msg: Netlink message to dump into
|
||||
* @cb: Control block containing additional options
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @single_hardif: Limit dumping to this hard interface
|
||||
*/
|
||||
static void
|
||||
batadv_v_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *single_hardif)
|
||||
{
|
||||
struct batadv_hard_iface *hard_iface;
|
||||
int i_hardif = 0;
|
||||
int i_hardif_s = cb->args[0];
|
||||
int idx = cb->args[1];
|
||||
int portid = NETLINK_CB(cb->skb).portid;
|
||||
|
||||
rcu_read_lock();
|
||||
if (single_hardif) {
|
||||
if (i_hardif_s == 0) {
|
||||
if (batadv_v_neigh_dump_hardif(msg, portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
bat_priv, single_hardif,
|
||||
&idx) == 0)
|
||||
i_hardif++;
|
||||
}
|
||||
} else {
|
||||
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
|
||||
if (hard_iface->soft_iface != bat_priv->soft_iface)
|
||||
continue;
|
||||
|
||||
if (i_hardif++ < i_hardif_s)
|
||||
continue;
|
||||
|
||||
if (batadv_v_neigh_dump_hardif(msg, portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
bat_priv, hard_iface,
|
||||
&idx)) {
|
||||
i_hardif--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
cb->args[0] = i_hardif;
|
||||
cb->args[1] = idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_orig_print - print the originator table
|
||||
* @bat_priv: the bat priv with all the soft interface information
|
||||
|
@ -272,6 +412,204 @@ next:
|
|||
seq_puts(seq, "No batman nodes in range ...\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_orig_dump_subentry - Dump an originator subentry into a
|
||||
* message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @if_outgoing: Limit dump to entries with this outgoing interface
|
||||
* @orig_node: Originator to dump
|
||||
* @neigh_node: Single hops neighbour
|
||||
* @best: Is the best originator
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_v_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *if_outgoing,
|
||||
struct batadv_orig_node *orig_node,
|
||||
struct batadv_neigh_node *neigh_node,
|
||||
bool best)
|
||||
{
|
||||
struct batadv_neigh_ifinfo *n_ifinfo;
|
||||
unsigned int last_seen_msecs;
|
||||
u32 throughput;
|
||||
void *hdr;
|
||||
|
||||
n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
|
||||
if (!n_ifinfo)
|
||||
return 0;
|
||||
|
||||
throughput = n_ifinfo->bat_v.throughput * 100;
|
||||
|
||||
batadv_neigh_ifinfo_put(n_ifinfo);
|
||||
|
||||
last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen);
|
||||
|
||||
if (if_outgoing != BATADV_IF_DEFAULT &&
|
||||
if_outgoing != neigh_node->if_incoming)
|
||||
return 0;
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
|
||||
BATADV_CMD_GET_ORIGINATORS);
|
||||
if (!hdr)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, orig_node->orig) ||
|
||||
nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
|
||||
neigh_node->addr) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
|
||||
neigh_node->if_incoming->net_dev->ifindex) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
|
||||
last_seen_msecs))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_orig_dump_entry - Dump an originator entry into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @if_outgoing: Limit dump to entries with this outgoing interface
|
||||
* @orig_node: Originator to dump
|
||||
* @sub_s: Number of sub entries to skip
|
||||
*
|
||||
* This function assumes the caller holds rcu_read_lock().
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_v_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *if_outgoing,
|
||||
struct batadv_orig_node *orig_node, int *sub_s)
|
||||
{
|
||||
struct batadv_neigh_node *neigh_node_best;
|
||||
struct batadv_neigh_node *neigh_node;
|
||||
int sub = 0;
|
||||
bool best;
|
||||
|
||||
neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing);
|
||||
if (!neigh_node_best)
|
||||
goto out;
|
||||
|
||||
hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
|
||||
if (sub++ < *sub_s)
|
||||
continue;
|
||||
|
||||
best = (neigh_node == neigh_node_best);
|
||||
|
||||
if (batadv_v_orig_dump_subentry(msg, portid, seq, bat_priv,
|
||||
if_outgoing, orig_node,
|
||||
neigh_node, best)) {
|
||||
batadv_neigh_node_put(neigh_node_best);
|
||||
|
||||
*sub_s = sub - 1;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (neigh_node_best)
|
||||
batadv_neigh_node_put(neigh_node_best);
|
||||
|
||||
*sub_s = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_orig_dump_bucket - Dump an originator bucket into a
|
||||
* message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @if_outgoing: Limit dump to entries with this outgoing interface
|
||||
* @head: Bucket to be dumped
|
||||
* @idx_s: Number of entries to be skipped
|
||||
* @sub: Number of sub entries to be skipped
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_v_orig_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *if_outgoing,
|
||||
struct hlist_head *head, int *idx_s, int *sub)
|
||||
{
|
||||
struct batadv_orig_node *orig_node;
|
||||
int idx = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
|
||||
if (idx++ < *idx_s)
|
||||
continue;
|
||||
|
||||
if (batadv_v_orig_dump_entry(msg, portid, seq, bat_priv,
|
||||
if_outgoing, orig_node, sub)) {
|
||||
rcu_read_unlock();
|
||||
*idx_s = idx - 1;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
*idx_s = 0;
|
||||
*sub = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_orig_dump - Dump the originators into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @cb: Control block containing additional options
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @if_outgoing: Limit dump to entries with this outgoing interface
|
||||
*/
|
||||
static void
|
||||
batadv_v_orig_dump(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *if_outgoing)
|
||||
{
|
||||
struct batadv_hashtable *hash = bat_priv->orig_hash;
|
||||
struct hlist_head *head;
|
||||
int bucket = cb->args[0];
|
||||
int idx = cb->args[1];
|
||||
int sub = cb->args[2];
|
||||
int portid = NETLINK_CB(cb->skb).portid;
|
||||
|
||||
while (bucket < hash->size) {
|
||||
head = &hash->table[bucket];
|
||||
|
||||
if (batadv_v_orig_dump_bucket(msg, portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
bat_priv, if_outgoing, head, &idx,
|
||||
&sub))
|
||||
break;
|
||||
|
||||
bucket++;
|
||||
}
|
||||
|
||||
cb->args[0] = bucket;
|
||||
cb->args[1] = idx;
|
||||
cb->args[2] = sub;
|
||||
}
|
||||
|
||||
static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
|
||||
struct batadv_hard_iface *if_outgoing1,
|
||||
struct batadv_neigh_node *neigh2,
|
||||
|
@ -559,6 +897,130 @@ static void batadv_v_gw_print(struct batadv_priv *bat_priv,
|
|||
seq_puts(seq, "No gateways in range ...\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_gw_dump_entry - Dump a gateway into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @gw_node: Gateway to be dumped
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_gw_node *gw_node)
|
||||
{
|
||||
struct batadv_neigh_ifinfo *router_ifinfo = NULL;
|
||||
struct batadv_neigh_node *router;
|
||||
struct batadv_gw_node *curr_gw;
|
||||
int ret = -EINVAL;
|
||||
void *hdr;
|
||||
|
||||
router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
|
||||
if (!router)
|
||||
goto out;
|
||||
|
||||
router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
|
||||
if (!router_ifinfo)
|
||||
goto out;
|
||||
|
||||
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
|
||||
NLM_F_MULTI, BATADV_CMD_GET_GATEWAYS);
|
||||
if (!hdr) {
|
||||
ret = -ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = -EMSGSIZE;
|
||||
|
||||
if (curr_gw == gw_node) {
|
||||
if (nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
|
||||
gw_node->orig_node->orig)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nla_put_u32(msg, BATADV_ATTR_THROUGHPUT,
|
||||
router_ifinfo->bat_v.throughput)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nla_put(msg, BATADV_ATTR_ROUTER, ETH_ALEN, router->addr)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
|
||||
router->if_incoming->net_dev->name)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN,
|
||||
gw_node->bandwidth_down)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_UP, gw_node->bandwidth_up)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (router_ifinfo)
|
||||
batadv_neigh_ifinfo_put(router_ifinfo);
|
||||
if (router)
|
||||
batadv_neigh_node_put(router);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_gw_dump - Dump gateways into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @cb: Control block containing additional options
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
*/
|
||||
static void batadv_v_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
struct batadv_priv *bat_priv)
|
||||
{
|
||||
int portid = NETLINK_CB(cb->skb).portid;
|
||||
struct batadv_gw_node *gw_node;
|
||||
int idx_skip = cb->args[0];
|
||||
int idx = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) {
|
||||
if (idx++ < idx_skip)
|
||||
continue;
|
||||
|
||||
if (batadv_v_gw_dump_entry(msg, portid, cb->nlh->nlmsg_seq,
|
||||
bat_priv, gw_node)) {
|
||||
idx_skip = idx - 1;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
idx_skip = idx;
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
cb->args[0] = idx_skip;
|
||||
}
|
||||
|
||||
static struct batadv_algo_ops batadv_batman_v __read_mostly = {
|
||||
.name = "BATMAN_V",
|
||||
.iface = {
|
||||
|
@ -573,9 +1035,11 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
|
|||
.cmp = batadv_v_neigh_cmp,
|
||||
.is_similar_or_better = batadv_v_neigh_is_sob,
|
||||
.print = batadv_v_neigh_print,
|
||||
.dump = batadv_v_neigh_dump,
|
||||
},
|
||||
.orig = {
|
||||
.print = batadv_v_orig_print,
|
||||
.dump = batadv_v_orig_dump,
|
||||
},
|
||||
.gw = {
|
||||
.store_sel_class = batadv_v_store_sel_class,
|
||||
|
@ -583,6 +1047,7 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
|
|||
.get_best_gw_node = batadv_v_gw_get_best_gw_node,
|
||||
.is_eligible = batadv_v_gw_is_eligible,
|
||||
.print = batadv_v_gw_print,
|
||||
.dump = batadv_v_gw_dump,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
@ -45,12 +46,18 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <net/arp.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/sock.h>
|
||||
#include <uapi/linux/batman_adv.h>
|
||||
|
||||
#include "hard-interface.h"
|
||||
#include "hash.h"
|
||||
#include "log.h"
|
||||
#include "netlink.h"
|
||||
#include "originator.h"
|
||||
#include "packet.h"
|
||||
#include "soft-interface.h"
|
||||
#include "sysfs.h"
|
||||
#include "translation-table.h"
|
||||
|
||||
|
@ -2051,6 +2058,168 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_bla_claim_dump_entry - dump one entry of the claim table
|
||||
* to a netlink socket
|
||||
* @msg: buffer for the message
|
||||
* @portid: netlink port
|
||||
* @seq: Sequence number of netlink message
|
||||
* @primary_if: primary interface
|
||||
* @claim: entry to dump
|
||||
*
|
||||
* Return: 0 or error code.
|
||||
*/
|
||||
static int
|
||||
batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_hard_iface *primary_if,
|
||||
struct batadv_bla_claim *claim)
|
||||
{
|
||||
u8 *primary_addr = primary_if->net_dev->dev_addr;
|
||||
u16 backbone_crc;
|
||||
bool is_own;
|
||||
void *hdr;
|
||||
int ret = -EINVAL;
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
|
||||
NLM_F_MULTI, BATADV_CMD_GET_BLA_CLAIM);
|
||||
if (!hdr) {
|
||||
ret = -ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
is_own = batadv_compare_eth(claim->backbone_gw->orig,
|
||||
primary_addr);
|
||||
|
||||
spin_lock_bh(&claim->backbone_gw->crc_lock);
|
||||
backbone_crc = claim->backbone_gw->crc;
|
||||
spin_unlock_bh(&claim->backbone_gw->crc_lock);
|
||||
|
||||
if (is_own)
|
||||
if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nla_put(msg, BATADV_ATTR_BLA_ADDRESS, ETH_ALEN, claim->addr) ||
|
||||
nla_put_u16(msg, BATADV_ATTR_BLA_VID, claim->vid) ||
|
||||
nla_put(msg, BATADV_ATTR_BLA_BACKBONE, ETH_ALEN,
|
||||
claim->backbone_gw->orig) ||
|
||||
nla_put_u16(msg, BATADV_ATTR_BLA_CRC,
|
||||
backbone_crc)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_bla_claim_dump_bucket - dump one bucket of the claim table
|
||||
* to a netlink socket
|
||||
* @msg: buffer for the message
|
||||
* @portid: netlink port
|
||||
* @seq: Sequence number of netlink message
|
||||
* @primary_if: primary interface
|
||||
* @head: bucket to dump
|
||||
* @idx_skip: How many entries to skip
|
||||
*
|
||||
* Return: always 0.
|
||||
*/
|
||||
static int
|
||||
batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_hard_iface *primary_if,
|
||||
struct hlist_head *head, int *idx_skip)
|
||||
{
|
||||
struct batadv_bla_claim *claim;
|
||||
int idx = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(claim, head, hash_entry) {
|
||||
if (idx++ < *idx_skip)
|
||||
continue;
|
||||
if (batadv_bla_claim_dump_entry(msg, portid, seq,
|
||||
primary_if, claim)) {
|
||||
*idx_skip = idx - 1;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
*idx_skip = idx;
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_bla_claim_dump - dump claim table to a netlink socket
|
||||
* @msg: buffer for the message
|
||||
* @cb: callback structure containing arguments
|
||||
*
|
||||
* Return: message length.
|
||||
*/
|
||||
int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb)
|
||||
{
|
||||
struct batadv_hard_iface *primary_if = NULL;
|
||||
int portid = NETLINK_CB(cb->skb).portid;
|
||||
struct net *net = sock_net(cb->skb->sk);
|
||||
struct net_device *soft_iface;
|
||||
struct batadv_hashtable *hash;
|
||||
struct batadv_priv *bat_priv;
|
||||
int bucket = cb->args[0];
|
||||
struct hlist_head *head;
|
||||
int idx = cb->args[1];
|
||||
int ifindex;
|
||||
int ret = 0;
|
||||
|
||||
ifindex = batadv_netlink_get_ifindex(cb->nlh,
|
||||
BATADV_ATTR_MESH_IFINDEX);
|
||||
if (!ifindex)
|
||||
return -EINVAL;
|
||||
|
||||
soft_iface = dev_get_by_index(net, ifindex);
|
||||
if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bat_priv = netdev_priv(soft_iface);
|
||||
hash = bat_priv->bla.claim_hash;
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (bucket < hash->size) {
|
||||
head = &hash->table[bucket];
|
||||
|
||||
if (batadv_bla_claim_dump_bucket(msg, portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
primary_if, head, &idx))
|
||||
break;
|
||||
bucket++;
|
||||
}
|
||||
|
||||
cb->args[0] = bucket;
|
||||
cb->args[1] = idx;
|
||||
|
||||
ret = msg->len;
|
||||
|
||||
out:
|
||||
if (primary_if)
|
||||
batadv_hardif_put(primary_if);
|
||||
|
||||
if (soft_iface)
|
||||
dev_put(soft_iface);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_bla_backbone_table_seq_print_text - print the backbone table in a seq
|
||||
* file
|
||||
|
@ -2114,3 +2283,167 @@ out:
|
|||
batadv_hardif_put(primary_if);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_bla_backbone_dump_entry - dump one entry of the backbone table
|
||||
* to a netlink socket
|
||||
* @msg: buffer for the message
|
||||
* @portid: netlink port
|
||||
* @seq: Sequence number of netlink message
|
||||
* @primary_if: primary interface
|
||||
* @backbone_gw: entry to dump
|
||||
*
|
||||
* Return: 0 or error code.
|
||||
*/
|
||||
static int
|
||||
batadv_bla_backbone_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_hard_iface *primary_if,
|
||||
struct batadv_bla_backbone_gw *backbone_gw)
|
||||
{
|
||||
u8 *primary_addr = primary_if->net_dev->dev_addr;
|
||||
u16 backbone_crc;
|
||||
bool is_own;
|
||||
int msecs;
|
||||
void *hdr;
|
||||
int ret = -EINVAL;
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
|
||||
NLM_F_MULTI, BATADV_CMD_GET_BLA_BACKBONE);
|
||||
if (!hdr) {
|
||||
ret = -ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
is_own = batadv_compare_eth(backbone_gw->orig, primary_addr);
|
||||
|
||||
spin_lock_bh(&backbone_gw->crc_lock);
|
||||
backbone_crc = backbone_gw->crc;
|
||||
spin_unlock_bh(&backbone_gw->crc_lock);
|
||||
|
||||
msecs = jiffies_to_msecs(jiffies - backbone_gw->lasttime);
|
||||
|
||||
if (is_own)
|
||||
if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nla_put(msg, BATADV_ATTR_BLA_BACKBONE, ETH_ALEN,
|
||||
backbone_gw->orig) ||
|
||||
nla_put_u16(msg, BATADV_ATTR_BLA_VID, backbone_gw->vid) ||
|
||||
nla_put_u16(msg, BATADV_ATTR_BLA_CRC,
|
||||
backbone_crc) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, msecs)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_bla_backbone_dump_bucket - dump one bucket of the backbone table
|
||||
* to a netlink socket
|
||||
* @msg: buffer for the message
|
||||
* @portid: netlink port
|
||||
* @seq: Sequence number of netlink message
|
||||
* @primary_if: primary interface
|
||||
* @head: bucket to dump
|
||||
* @idx_skip: How many entries to skip
|
||||
*
|
||||
* Return: always 0.
|
||||
*/
|
||||
static int
|
||||
batadv_bla_backbone_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_hard_iface *primary_if,
|
||||
struct hlist_head *head, int *idx_skip)
|
||||
{
|
||||
struct batadv_bla_backbone_gw *backbone_gw;
|
||||
int idx = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
|
||||
if (idx++ < *idx_skip)
|
||||
continue;
|
||||
if (batadv_bla_backbone_dump_entry(msg, portid, seq,
|
||||
primary_if, backbone_gw)) {
|
||||
*idx_skip = idx - 1;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
*idx_skip = idx;
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_bla_backbone_dump - dump backbone table to a netlink socket
|
||||
* @msg: buffer for the message
|
||||
* @cb: callback structure containing arguments
|
||||
*
|
||||
* Return: message length.
|
||||
*/
|
||||
int batadv_bla_backbone_dump(struct sk_buff *msg, struct netlink_callback *cb)
|
||||
{
|
||||
struct batadv_hard_iface *primary_if = NULL;
|
||||
int portid = NETLINK_CB(cb->skb).portid;
|
||||
struct net *net = sock_net(cb->skb->sk);
|
||||
struct net_device *soft_iface;
|
||||
struct batadv_hashtable *hash;
|
||||
struct batadv_priv *bat_priv;
|
||||
int bucket = cb->args[0];
|
||||
struct hlist_head *head;
|
||||
int idx = cb->args[1];
|
||||
int ifindex;
|
||||
int ret = 0;
|
||||
|
||||
ifindex = batadv_netlink_get_ifindex(cb->nlh,
|
||||
BATADV_ATTR_MESH_IFINDEX);
|
||||
if (!ifindex)
|
||||
return -EINVAL;
|
||||
|
||||
soft_iface = dev_get_by_index(net, ifindex);
|
||||
if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bat_priv = netdev_priv(soft_iface);
|
||||
hash = bat_priv->bla.backbone_hash;
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (bucket < hash->size) {
|
||||
head = &hash->table[bucket];
|
||||
|
||||
if (batadv_bla_backbone_dump_bucket(msg, portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
primary_if, head, &idx))
|
||||
break;
|
||||
bucket++;
|
||||
}
|
||||
|
||||
cb->args[0] = bucket;
|
||||
cb->args[1] = idx;
|
||||
|
||||
ret = msg->len;
|
||||
|
||||
out:
|
||||
if (primary_if)
|
||||
batadv_hardif_put(primary_if);
|
||||
|
||||
if (soft_iface)
|
||||
dev_put(soft_iface);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
struct net_device;
|
||||
struct netlink_callback;
|
||||
struct seq_file;
|
||||
struct sk_buff;
|
||||
|
||||
|
@ -35,8 +36,10 @@ bool batadv_bla_is_backbone_gw(struct sk_buff *skb,
|
|||
struct batadv_orig_node *orig_node,
|
||||
int hdr_size);
|
||||
int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset);
|
||||
int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb);
|
||||
int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq,
|
||||
void *offset);
|
||||
int batadv_bla_backbone_dump(struct sk_buff *msg, struct netlink_callback *cb);
|
||||
bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig,
|
||||
unsigned short vid);
|
||||
bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
|
||||
|
@ -47,7 +50,7 @@ void batadv_bla_update_orig_address(struct batadv_priv *bat_priv,
|
|||
void batadv_bla_status_update(struct net_device *net_dev);
|
||||
int batadv_bla_init(struct batadv_priv *bat_priv);
|
||||
void batadv_bla_free(struct batadv_priv *bat_priv);
|
||||
|
||||
int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb);
|
||||
#define BATADV_BLA_CRC_INIT 0
|
||||
#else /* ifdef CONFIG_BATMAN_ADV_BLA */
|
||||
|
||||
|
@ -112,6 +115,18 @@ static inline void batadv_bla_free(struct batadv_priv *bat_priv)
|
|||
{
|
||||
}
|
||||
|
||||
static inline int batadv_bla_claim_dump(struct sk_buff *msg,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int batadv_bla_backbone_dump(struct sk_buff *msg,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif /* ifdef CONFIG_BATMAN_ADV_BLA */
|
||||
|
||||
#endif /* ifndef _NET_BATMAN_ADV_BLA_H_ */
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/stddef.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
#include "bat_algo.h"
|
||||
#include "bridge_loop_avoidance.h"
|
||||
|
@ -305,12 +306,16 @@ void batadv_debugfs_destroy(void)
|
|||
*/
|
||||
int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct net *net = dev_net(hard_iface->net_dev);
|
||||
struct batadv_debuginfo **bat_debug;
|
||||
struct dentry *file;
|
||||
|
||||
if (!batadv_debugfs)
|
||||
goto out;
|
||||
|
||||
if (net != &init_net)
|
||||
return 0;
|
||||
|
||||
hard_iface->debug_dir = debugfs_create_dir(hard_iface->net_dev->name,
|
||||
batadv_debugfs);
|
||||
if (!hard_iface->debug_dir)
|
||||
|
@ -341,6 +346,11 @@ out:
|
|||
*/
|
||||
void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct net *net = dev_net(hard_iface->net_dev);
|
||||
|
||||
if (net != &init_net)
|
||||
return;
|
||||
|
||||
if (batadv_debugfs) {
|
||||
debugfs_remove_recursive(hard_iface->debug_dir);
|
||||
hard_iface->debug_dir = NULL;
|
||||
|
@ -351,11 +361,15 @@ int batadv_debugfs_add_meshif(struct net_device *dev)
|
|||
{
|
||||
struct batadv_priv *bat_priv = netdev_priv(dev);
|
||||
struct batadv_debuginfo **bat_debug;
|
||||
struct net *net = dev_net(dev);
|
||||
struct dentry *file;
|
||||
|
||||
if (!batadv_debugfs)
|
||||
goto out;
|
||||
|
||||
if (net != &init_net)
|
||||
return 0;
|
||||
|
||||
bat_priv->debug_dir = debugfs_create_dir(dev->name, batadv_debugfs);
|
||||
if (!bat_priv->debug_dir)
|
||||
goto out;
|
||||
|
@ -392,6 +406,10 @@ out:
|
|||
void batadv_debugfs_del_meshif(struct net_device *dev)
|
||||
{
|
||||
struct batadv_priv *bat_priv = netdev_priv(dev);
|
||||
struct net *net = dev_net(dev);
|
||||
|
||||
if (net != &init_net)
|
||||
return;
|
||||
|
||||
batadv_debug_log_cleanup(bat_priv);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/byteorder/generic.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
@ -31,6 +32,7 @@
|
|||
#include <linux/kref.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
@ -39,13 +41,17 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/udp.h>
|
||||
#include <net/sock.h>
|
||||
#include <uapi/linux/batman_adv.h>
|
||||
|
||||
#include "gateway_common.h"
|
||||
#include "hard-interface.h"
|
||||
#include "log.h"
|
||||
#include "netlink.h"
|
||||
#include "originator.h"
|
||||
#include "packet.h"
|
||||
#include "routing.h"
|
||||
#include "soft-interface.h"
|
||||
#include "sysfs.h"
|
||||
#include "translation-table.h"
|
||||
|
||||
|
@ -500,6 +506,59 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_gw_dump - Dump gateways into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @cb: Control block containing additional options
|
||||
*
|
||||
* Return: Error code, or length of message
|
||||
*/
|
||||
int batadv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb)
|
||||
{
|
||||
struct batadv_hard_iface *primary_if = NULL;
|
||||
struct net *net = sock_net(cb->skb->sk);
|
||||
struct net_device *soft_iface;
|
||||
struct batadv_priv *bat_priv;
|
||||
int ifindex;
|
||||
int ret;
|
||||
|
||||
ifindex = batadv_netlink_get_ifindex(cb->nlh,
|
||||
BATADV_ATTR_MESH_IFINDEX);
|
||||
if (!ifindex)
|
||||
return -EINVAL;
|
||||
|
||||
soft_iface = dev_get_by_index(net, ifindex);
|
||||
if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bat_priv = netdev_priv(soft_iface);
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!bat_priv->algo_ops->gw.dump) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bat_priv->algo_ops->gw.dump(msg, cb, bat_priv);
|
||||
|
||||
ret = msg->len;
|
||||
|
||||
out:
|
||||
if (primary_if)
|
||||
batadv_hardif_put(primary_if);
|
||||
if (soft_iface)
|
||||
dev_put(soft_iface);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_gw_dhcp_recipient_get - check if a packet is a DHCP message
|
||||
* @skb: the packet to check
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
struct batadv_tvlv_gateway_data;
|
||||
struct netlink_callback;
|
||||
struct seq_file;
|
||||
struct sk_buff;
|
||||
|
||||
|
@ -43,6 +44,7 @@ void batadv_gw_node_put(struct batadv_gw_node *gw_node);
|
|||
struct batadv_gw_node *
|
||||
batadv_gw_get_selected_gw_node(struct batadv_priv *bat_priv);
|
||||
int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset);
|
||||
int batadv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb);
|
||||
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb);
|
||||
enum batadv_dhcp_recipient
|
||||
batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include <linux/rtnetlink.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/rtnetlink.h>
|
||||
|
||||
#include "bat_v.h"
|
||||
#include "bridge_loop_avoidance.h"
|
||||
|
@ -83,26 +85,56 @@ out:
|
|||
return hard_iface;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_getlink_net - return link net namespace (of use fallback)
|
||||
* @netdev: net_device to check
|
||||
* @fallback_net: return in case get_link_net is not available for @netdev
|
||||
*
|
||||
* Return: result of rtnl_link_ops->get_link_net or @fallback_net
|
||||
*/
|
||||
static const struct net *batadv_getlink_net(const struct net_device *netdev,
|
||||
const struct net *fallback_net)
|
||||
{
|
||||
if (!netdev->rtnl_link_ops)
|
||||
return fallback_net;
|
||||
|
||||
if (!netdev->rtnl_link_ops->get_link_net)
|
||||
return fallback_net;
|
||||
|
||||
return netdev->rtnl_link_ops->get_link_net(netdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_mutual_parents - check if two devices are each others parent
|
||||
* @dev1: 1st net_device
|
||||
* @dev2: 2nd net_device
|
||||
* @dev1: 1st net dev
|
||||
* @net1: 1st devices netns
|
||||
* @dev2: 2nd net dev
|
||||
* @net2: 2nd devices netns
|
||||
*
|
||||
* veth devices come in pairs and each is the parent of the other!
|
||||
*
|
||||
* Return: true if the devices are each others parent, otherwise false
|
||||
*/
|
||||
static bool batadv_mutual_parents(const struct net_device *dev1,
|
||||
const struct net_device *dev2)
|
||||
const struct net *net1,
|
||||
const struct net_device *dev2,
|
||||
const struct net *net2)
|
||||
{
|
||||
int dev1_parent_iflink = dev_get_iflink(dev1);
|
||||
int dev2_parent_iflink = dev_get_iflink(dev2);
|
||||
const struct net *dev1_parent_net;
|
||||
const struct net *dev2_parent_net;
|
||||
|
||||
dev1_parent_net = batadv_getlink_net(dev1, net1);
|
||||
dev2_parent_net = batadv_getlink_net(dev2, net2);
|
||||
|
||||
if (!dev1_parent_iflink || !dev2_parent_iflink)
|
||||
return false;
|
||||
|
||||
return (dev1_parent_iflink == dev2->ifindex) &&
|
||||
(dev2_parent_iflink == dev1->ifindex);
|
||||
(dev2_parent_iflink == dev1->ifindex) &&
|
||||
net_eq(dev1_parent_net, net2) &&
|
||||
net_eq(dev2_parent_net, net1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,8 +152,9 @@ static bool batadv_mutual_parents(const struct net_device *dev1,
|
|||
*/
|
||||
static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
|
||||
{
|
||||
struct net_device *parent_dev;
|
||||
struct net *net = dev_net(net_dev);
|
||||
struct net_device *parent_dev;
|
||||
const struct net *parent_net;
|
||||
bool ret;
|
||||
|
||||
/* check if this is a batman-adv mesh interface */
|
||||
|
@ -133,13 +166,16 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
|
|||
dev_get_iflink(net_dev) == net_dev->ifindex)
|
||||
return false;
|
||||
|
||||
parent_net = batadv_getlink_net(net_dev, net);
|
||||
|
||||
/* recurse over the parent device */
|
||||
parent_dev = __dev_get_by_index(net, dev_get_iflink(net_dev));
|
||||
parent_dev = __dev_get_by_index((struct net *)parent_net,
|
||||
dev_get_iflink(net_dev));
|
||||
/* if we got a NULL parent_dev there is something broken.. */
|
||||
if (WARN(!parent_dev, "Cannot find parent device"))
|
||||
return false;
|
||||
|
||||
if (batadv_mutual_parents(net_dev, parent_dev))
|
||||
if (batadv_mutual_parents(net_dev, net, parent_dev, parent_net))
|
||||
return false;
|
||||
|
||||
ret = batadv_is_on_batman_iface(parent_dev);
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "netlink.h"
|
||||
#include "main.h"
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/byteorder/generic.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/genetlink.h>
|
||||
|
@ -26,24 +28,33 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/sock.h>
|
||||
#include <uapi/linux/batman_adv.h>
|
||||
|
||||
#include "bat_algo.h"
|
||||
#include "bridge_loop_avoidance.h"
|
||||
#include "gateway_client.h"
|
||||
#include "hard-interface.h"
|
||||
#include "originator.h"
|
||||
#include "packet.h"
|
||||
#include "soft-interface.h"
|
||||
#include "tp_meter.h"
|
||||
#include "translation-table.h"
|
||||
|
||||
struct sk_buff;
|
||||
|
||||
static struct genl_family batadv_netlink_family = {
|
||||
struct genl_family batadv_netlink_family = {
|
||||
.id = GENL_ID_GENERATE,
|
||||
.hdrsize = 0,
|
||||
.name = BATADV_NL_NAME,
|
||||
.version = 1,
|
||||
.maxattr = BATADV_ATTR_MAX,
|
||||
.netnsok = true,
|
||||
};
|
||||
|
||||
/* multicast groups */
|
||||
|
@ -69,8 +80,43 @@ static struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = {
|
|||
[BATADV_ATTR_TPMETER_TEST_TIME] = { .type = NLA_U32 },
|
||||
[BATADV_ATTR_TPMETER_BYTES] = { .type = NLA_U64 },
|
||||
[BATADV_ATTR_TPMETER_COOKIE] = { .type = NLA_U32 },
|
||||
[BATADV_ATTR_ACTIVE] = { .type = NLA_FLAG },
|
||||
[BATADV_ATTR_TT_ADDRESS] = { .len = ETH_ALEN },
|
||||
[BATADV_ATTR_TT_TTVN] = { .type = NLA_U8 },
|
||||
[BATADV_ATTR_TT_LAST_TTVN] = { .type = NLA_U8 },
|
||||
[BATADV_ATTR_TT_CRC32] = { .type = NLA_U32 },
|
||||
[BATADV_ATTR_TT_VID] = { .type = NLA_U16 },
|
||||
[BATADV_ATTR_TT_FLAGS] = { .type = NLA_U32 },
|
||||
[BATADV_ATTR_FLAG_BEST] = { .type = NLA_FLAG },
|
||||
[BATADV_ATTR_LAST_SEEN_MSECS] = { .type = NLA_U32 },
|
||||
[BATADV_ATTR_NEIGH_ADDRESS] = { .len = ETH_ALEN },
|
||||
[BATADV_ATTR_TQ] = { .type = NLA_U8 },
|
||||
[BATADV_ATTR_THROUGHPUT] = { .type = NLA_U32 },
|
||||
[BATADV_ATTR_BANDWIDTH_UP] = { .type = NLA_U32 },
|
||||
[BATADV_ATTR_BANDWIDTH_DOWN] = { .type = NLA_U32 },
|
||||
[BATADV_ATTR_ROUTER] = { .len = ETH_ALEN },
|
||||
[BATADV_ATTR_BLA_OWN] = { .type = NLA_FLAG },
|
||||
[BATADV_ATTR_BLA_ADDRESS] = { .len = ETH_ALEN },
|
||||
[BATADV_ATTR_BLA_VID] = { .type = NLA_U16 },
|
||||
[BATADV_ATTR_BLA_BACKBONE] = { .len = ETH_ALEN },
|
||||
[BATADV_ATTR_BLA_CRC] = { .type = NLA_U16 },
|
||||
};
|
||||
|
||||
/**
|
||||
* batadv_netlink_get_ifindex - Extract an interface index from a message
|
||||
* @nlh: Message header
|
||||
* @attrtype: Attribute which holds an interface index
|
||||
*
|
||||
* Return: interface index, or 0.
|
||||
*/
|
||||
int
|
||||
batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype)
|
||||
{
|
||||
struct nlattr *attr = nlmsg_find_attr(nlh, GENL_HDRLEN, attrtype);
|
||||
|
||||
return attr ? nla_get_u32(attr) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_netlink_mesh_info_put - fill in generic information about mesh
|
||||
* interface
|
||||
|
@ -93,9 +139,17 @@ batadv_netlink_mesh_info_put(struct sk_buff *msg, struct net_device *soft_iface)
|
|||
nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, soft_iface->ifindex) ||
|
||||
nla_put_string(msg, BATADV_ATTR_MESH_IFNAME, soft_iface->name) ||
|
||||
nla_put(msg, BATADV_ATTR_MESH_ADDRESS, ETH_ALEN,
|
||||
soft_iface->dev_addr))
|
||||
soft_iface->dev_addr) ||
|
||||
nla_put_u8(msg, BATADV_ATTR_TT_TTVN,
|
||||
(u8)atomic_read(&bat_priv->tt.vn)))
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_BATMAN_ADV_BLA
|
||||
if (nla_put_u16(msg, BATADV_ATTR_BLA_CRC,
|
||||
ntohs(bat_priv->bla.claim_dest.group)))
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
if (primary_if && primary_if->if_status == BATADV_IF_ACTIVE) {
|
||||
hard_iface = primary_if->net_dev;
|
||||
|
@ -380,6 +434,106 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_netlink_dump_hardif_entry - Dump one hard interface into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @hard_iface: Hard interface to dump
|
||||
*
|
||||
* Return: error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_netlink_dump_hardif_entry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct net_device *net_dev = hard_iface->net_dev;
|
||||
void *hdr;
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
|
||||
BATADV_CMD_GET_HARDIFS);
|
||||
if (!hdr)
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
|
||||
net_dev->ifindex) ||
|
||||
nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
|
||||
net_dev->name) ||
|
||||
nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN,
|
||||
net_dev->dev_addr))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (hard_iface->if_status == BATADV_IF_ACTIVE) {
|
||||
if (nla_put_flag(msg, BATADV_ATTR_ACTIVE))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_netlink_dump_hardifs - Dump all hard interface into a messages
|
||||
* @msg: Netlink message to dump into
|
||||
* @cb: Parameters from query
|
||||
*
|
||||
* Return: error code, or length of reply message on success
|
||||
*/
|
||||
static int
|
||||
batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb)
|
||||
{
|
||||
struct net *net = sock_net(cb->skb->sk);
|
||||
struct net_device *soft_iface;
|
||||
struct batadv_hard_iface *hard_iface;
|
||||
int ifindex;
|
||||
int portid = NETLINK_CB(cb->skb).portid;
|
||||
int seq = cb->nlh->nlmsg_seq;
|
||||
int skip = cb->args[0];
|
||||
int i = 0;
|
||||
|
||||
ifindex = batadv_netlink_get_ifindex(cb->nlh,
|
||||
BATADV_ATTR_MESH_IFINDEX);
|
||||
if (!ifindex)
|
||||
return -EINVAL;
|
||||
|
||||
soft_iface = dev_get_by_index(net, ifindex);
|
||||
if (!soft_iface)
|
||||
return -ENODEV;
|
||||
|
||||
if (!batadv_softif_is_valid(soft_iface)) {
|
||||
dev_put(soft_iface);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
|
||||
if (hard_iface->soft_iface != soft_iface)
|
||||
continue;
|
||||
|
||||
if (i++ < skip)
|
||||
continue;
|
||||
|
||||
if (batadv_netlink_dump_hardif_entry(msg, portid, seq,
|
||||
hard_iface)) {
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
dev_put(soft_iface);
|
||||
|
||||
cb->args[0] = i;
|
||||
|
||||
return msg->len;
|
||||
}
|
||||
|
||||
static struct genl_ops batadv_netlink_ops[] = {
|
||||
{
|
||||
.cmd = BATADV_CMD_GET_MESH_INFO,
|
||||
|
@ -399,6 +553,61 @@ static struct genl_ops batadv_netlink_ops[] = {
|
|||
.policy = batadv_netlink_policy,
|
||||
.doit = batadv_netlink_tp_meter_cancel,
|
||||
},
|
||||
{
|
||||
.cmd = BATADV_CMD_GET_ROUTING_ALGOS,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = batadv_netlink_policy,
|
||||
.dumpit = batadv_algo_dump,
|
||||
},
|
||||
{
|
||||
.cmd = BATADV_CMD_GET_HARDIFS,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = batadv_netlink_policy,
|
||||
.dumpit = batadv_netlink_dump_hardifs,
|
||||
},
|
||||
{
|
||||
.cmd = BATADV_CMD_GET_TRANSTABLE_LOCAL,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = batadv_netlink_policy,
|
||||
.dumpit = batadv_tt_local_dump,
|
||||
},
|
||||
{
|
||||
.cmd = BATADV_CMD_GET_TRANSTABLE_GLOBAL,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = batadv_netlink_policy,
|
||||
.dumpit = batadv_tt_global_dump,
|
||||
},
|
||||
{
|
||||
.cmd = BATADV_CMD_GET_ORIGINATORS,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = batadv_netlink_policy,
|
||||
.dumpit = batadv_orig_dump,
|
||||
},
|
||||
{
|
||||
.cmd = BATADV_CMD_GET_NEIGHBORS,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = batadv_netlink_policy,
|
||||
.dumpit = batadv_hardif_neigh_dump,
|
||||
},
|
||||
{
|
||||
.cmd = BATADV_CMD_GET_GATEWAYS,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = batadv_netlink_policy,
|
||||
.dumpit = batadv_gw_dump,
|
||||
},
|
||||
{
|
||||
.cmd = BATADV_CMD_GET_BLA_CLAIM,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = batadv_netlink_policy,
|
||||
.dumpit = batadv_bla_claim_dump,
|
||||
},
|
||||
{
|
||||
.cmd = BATADV_CMD_GET_BLA_BACKBONE,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = batadv_netlink_policy,
|
||||
.dumpit = batadv_bla_backbone_dump,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,12 +21,18 @@
|
|||
#include "main.h"
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
struct nlmsghdr;
|
||||
|
||||
void batadv_netlink_register(void);
|
||||
void batadv_netlink_unregister(void);
|
||||
int batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype);
|
||||
|
||||
int batadv_netlink_tpmeter_notify(struct batadv_priv *bat_priv, const u8 *dst,
|
||||
u8 result, u32 test_time, u64 total_bytes,
|
||||
u32 cookie);
|
||||
|
||||
extern struct genl_family batadv_netlink_family;
|
||||
|
||||
#endif /* _NET_BATMAN_ADV_NETLINK_H_ */
|
||||
|
|
|
@ -28,11 +28,15 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <net/sock.h>
|
||||
#include <uapi/linux/batman_adv.h>
|
||||
|
||||
#include "bat_algo.h"
|
||||
#include "distributed-arp-table.h"
|
||||
|
@ -42,8 +46,10 @@
|
|||
#include "hash.h"
|
||||
#include "log.h"
|
||||
#include "multicast.h"
|
||||
#include "netlink.h"
|
||||
#include "network-coding.h"
|
||||
#include "routing.h"
|
||||
#include "soft-interface.h"
|
||||
#include "translation-table.h"
|
||||
|
||||
/* hash class keys */
|
||||
|
@ -720,6 +726,83 @@ int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_hardif_neigh_dump - Dump to netlink the neighbor infos for a specific
|
||||
* outgoing interface
|
||||
* @msg: message to dump into
|
||||
* @cb: parameters for the dump
|
||||
*
|
||||
* Return: 0 or error value
|
||||
*/
|
||||
int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb)
|
||||
{
|
||||
struct net *net = sock_net(cb->skb->sk);
|
||||
struct net_device *soft_iface;
|
||||
struct net_device *hard_iface = NULL;
|
||||
struct batadv_hard_iface *hardif = BATADV_IF_DEFAULT;
|
||||
struct batadv_priv *bat_priv;
|
||||
struct batadv_hard_iface *primary_if = NULL;
|
||||
int ret;
|
||||
int ifindex, hard_ifindex;
|
||||
|
||||
ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
|
||||
if (!ifindex)
|
||||
return -EINVAL;
|
||||
|
||||
soft_iface = dev_get_by_index(net, ifindex);
|
||||
if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bat_priv = netdev_priv(soft_iface);
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hard_ifindex = batadv_netlink_get_ifindex(cb->nlh,
|
||||
BATADV_ATTR_HARD_IFINDEX);
|
||||
if (hard_ifindex) {
|
||||
hard_iface = dev_get_by_index(net, hard_ifindex);
|
||||
if (hard_iface)
|
||||
hardif = batadv_hardif_get_by_netdev(hard_iface);
|
||||
|
||||
if (!hardif) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hardif->soft_iface != soft_iface) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bat_priv->algo_ops->neigh.dump) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bat_priv->algo_ops->neigh.dump(msg, cb, bat_priv, hardif);
|
||||
|
||||
ret = msg->len;
|
||||
|
||||
out:
|
||||
if (hardif)
|
||||
batadv_hardif_put(hardif);
|
||||
if (hard_iface)
|
||||
dev_put(hard_iface);
|
||||
if (primary_if)
|
||||
batadv_hardif_put(primary_if);
|
||||
if (soft_iface)
|
||||
dev_put(soft_iface);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_orig_ifinfo_release - release orig_ifinfo from lists and queue for
|
||||
* free after rcu grace period
|
||||
|
@ -1330,6 +1413,83 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_orig_dump - Dump to netlink the originator infos for a specific
|
||||
* outgoing interface
|
||||
* @msg: message to dump into
|
||||
* @cb: parameters for the dump
|
||||
*
|
||||
* Return: 0 or error value
|
||||
*/
|
||||
int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb)
|
||||
{
|
||||
struct net *net = sock_net(cb->skb->sk);
|
||||
struct net_device *soft_iface;
|
||||
struct net_device *hard_iface = NULL;
|
||||
struct batadv_hard_iface *hardif = BATADV_IF_DEFAULT;
|
||||
struct batadv_priv *bat_priv;
|
||||
struct batadv_hard_iface *primary_if = NULL;
|
||||
int ret;
|
||||
int ifindex, hard_ifindex;
|
||||
|
||||
ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
|
||||
if (!ifindex)
|
||||
return -EINVAL;
|
||||
|
||||
soft_iface = dev_get_by_index(net, ifindex);
|
||||
if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bat_priv = netdev_priv(soft_iface);
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hard_ifindex = batadv_netlink_get_ifindex(cb->nlh,
|
||||
BATADV_ATTR_HARD_IFINDEX);
|
||||
if (hard_ifindex) {
|
||||
hard_iface = dev_get_by_index(net, hard_ifindex);
|
||||
if (hard_iface)
|
||||
hardif = batadv_hardif_get_by_netdev(hard_iface);
|
||||
|
||||
if (!hardif) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hardif->soft_iface != soft_iface) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bat_priv->algo_ops->orig.dump) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bat_priv->algo_ops->orig.dump(msg, cb, bat_priv, hardif);
|
||||
|
||||
ret = msg->len;
|
||||
|
||||
out:
|
||||
if (hardif)
|
||||
batadv_hardif_put(hardif);
|
||||
if (hard_iface)
|
||||
dev_put(hard_iface);
|
||||
if (primary_if)
|
||||
batadv_hardif_put(primary_if);
|
||||
if (soft_iface)
|
||||
dev_put(soft_iface);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
|
||||
int max_if_num)
|
||||
{
|
||||
|
|
|
@ -31,7 +31,9 @@
|
|||
|
||||
#include "hash.h"
|
||||
|
||||
struct netlink_callback;
|
||||
struct seq_file;
|
||||
struct sk_buff;
|
||||
|
||||
bool batadv_compare_orig(const struct hlist_node *node, const void *data2);
|
||||
int batadv_originator_init(struct batadv_priv *bat_priv);
|
||||
|
@ -61,6 +63,7 @@ batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
|
|||
struct batadv_hard_iface *if_outgoing);
|
||||
void batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo);
|
||||
|
||||
int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb);
|
||||
int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset);
|
||||
|
||||
struct batadv_orig_ifinfo *
|
||||
|
@ -72,6 +75,7 @@ batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
|
|||
void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo);
|
||||
|
||||
int batadv_orig_seq_print_text(struct seq_file *seq, void *offset);
|
||||
int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb);
|
||||
int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset);
|
||||
int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
|
||||
int max_if_num);
|
||||
|
|
|
@ -128,42 +128,6 @@ enum batadv_tt_data_flags {
|
|||
BATADV_TT_FULL_TABLE = BIT(4),
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 = BIT(0),
|
||||
BATADV_TT_CLIENT_ROAM = BIT(1),
|
||||
BATADV_TT_CLIENT_WIFI = BIT(4),
|
||||
BATADV_TT_CLIENT_ISOLA = BIT(5),
|
||||
BATADV_TT_CLIENT_NOPURGE = BIT(8),
|
||||
BATADV_TT_CLIENT_NEW = BIT(9),
|
||||
BATADV_TT_CLIENT_PENDING = BIT(10),
|
||||
BATADV_TT_CLIENT_TEMP = BIT(11),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum batadv_vlan_flags - flags for the four MSB of any vlan ID field
|
||||
* @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not
|
||||
|
|
|
@ -37,20 +37,27 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/sock.h>
|
||||
#include <uapi/linux/batman_adv.h>
|
||||
|
||||
#include "bridge_loop_avoidance.h"
|
||||
#include "hard-interface.h"
|
||||
#include "hash.h"
|
||||
#include "log.h"
|
||||
#include "multicast.h"
|
||||
#include "netlink.h"
|
||||
#include "originator.h"
|
||||
#include "packet.h"
|
||||
#include "soft-interface.h"
|
||||
|
@ -1108,6 +1115,164 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_dump_entry - Dump one TT local entry into a message
|
||||
* @msg :Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @common: tt local & tt global common data
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_tt_common_entry *common)
|
||||
{
|
||||
void *hdr;
|
||||
struct batadv_softif_vlan *vlan;
|
||||
struct batadv_tt_local_entry *local;
|
||||
unsigned int last_seen_msecs;
|
||||
u32 crc;
|
||||
|
||||
local = container_of(common, struct batadv_tt_local_entry, common);
|
||||
last_seen_msecs = jiffies_to_msecs(jiffies - local->last_seen);
|
||||
|
||||
vlan = batadv_softif_vlan_get(bat_priv, common->vid);
|
||||
if (!vlan)
|
||||
return 0;
|
||||
|
||||
crc = vlan->tt.crc;
|
||||
|
||||
batadv_softif_vlan_put(vlan);
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
|
||||
NLM_F_MULTI,
|
||||
BATADV_CMD_GET_TRANSTABLE_LOCAL);
|
||||
if (!hdr)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
|
||||
nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common->flags))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (!(common->flags & BATADV_TT_CLIENT_NOPURGE) &&
|
||||
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, last_seen_msecs))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_dump_bucket - Dump one TT local bucket into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @head: Pointer to the list containing the local tt entries
|
||||
* @idx_s: Number of entries to skip
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct hlist_head *head, int *idx_s)
|
||||
{
|
||||
struct batadv_tt_common_entry *common;
|
||||
int idx = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(common, head, hash_entry) {
|
||||
if (idx++ < *idx_s)
|
||||
continue;
|
||||
|
||||
if (batadv_tt_local_dump_entry(msg, portid, seq, bat_priv,
|
||||
common)) {
|
||||
rcu_read_unlock();
|
||||
*idx_s = idx - 1;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
*idx_s = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_dump - Dump TT local entries into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @cb: Parameters from query
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
|
||||
{
|
||||
struct net *net = sock_net(cb->skb->sk);
|
||||
struct net_device *soft_iface;
|
||||
struct batadv_priv *bat_priv;
|
||||
struct batadv_hard_iface *primary_if = NULL;
|
||||
struct batadv_hashtable *hash;
|
||||
struct hlist_head *head;
|
||||
int ret;
|
||||
int ifindex;
|
||||
int bucket = cb->args[0];
|
||||
int idx = cb->args[1];
|
||||
int portid = NETLINK_CB(cb->skb).portid;
|
||||
|
||||
ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
|
||||
if (!ifindex)
|
||||
return -EINVAL;
|
||||
|
||||
soft_iface = dev_get_by_index(net, ifindex);
|
||||
if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bat_priv = netdev_priv(soft_iface);
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hash = bat_priv->tt.local_hash;
|
||||
|
||||
while (bucket < hash->size) {
|
||||
head = &hash->table[bucket];
|
||||
|
||||
if (batadv_tt_local_dump_bucket(msg, portid, cb->nlh->nlmsg_seq,
|
||||
bat_priv, head, &idx))
|
||||
break;
|
||||
|
||||
bucket++;
|
||||
}
|
||||
|
||||
ret = msg->len;
|
||||
|
||||
out:
|
||||
if (primary_if)
|
||||
batadv_hardif_put(primary_if);
|
||||
if (soft_iface)
|
||||
dev_put(soft_iface);
|
||||
|
||||
cb->args[0] = bucket;
|
||||
cb->args[1] = idx;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
|
||||
struct batadv_tt_local_entry *tt_local_entry,
|
||||
|
@ -1755,6 +1920,218 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_global_dump_subentry - Dump all TT local entries into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @common: tt local & tt global common data
|
||||
* @orig: Originator node announcing a non-mesh client
|
||||
* @best: Is the best originator for the TT entry
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_tt_common_entry *common,
|
||||
struct batadv_tt_orig_list_entry *orig,
|
||||
bool best)
|
||||
{
|
||||
void *hdr;
|
||||
struct batadv_orig_node_vlan *vlan;
|
||||
u8 last_ttvn;
|
||||
u32 crc;
|
||||
|
||||
vlan = batadv_orig_node_vlan_get(orig->orig_node,
|
||||
common->vid);
|
||||
if (!vlan)
|
||||
return 0;
|
||||
|
||||
crc = vlan->tt.crc;
|
||||
|
||||
batadv_orig_node_vlan_put(vlan);
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
|
||||
NLM_F_MULTI,
|
||||
BATADV_CMD_GET_TRANSTABLE_GLOBAL);
|
||||
if (!hdr)
|
||||
return -ENOBUFS;
|
||||
|
||||
last_ttvn = atomic_read(&orig->orig_node->last_ttvn);
|
||||
|
||||
if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
|
||||
nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
|
||||
orig->orig_node->orig) ||
|
||||
nla_put_u8(msg, BATADV_ATTR_TT_TTVN, orig->ttvn) ||
|
||||
nla_put_u8(msg, BATADV_ATTR_TT_LAST_TTVN, last_ttvn) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
|
||||
nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common->flags))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_global_dump_entry - Dump one TT global entry into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @common: tt local & tt global common data
|
||||
* @sub_s: Number of entries to skip
|
||||
*
|
||||
* This function assumes the caller holds rcu_read_lock().
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_tt_global_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct batadv_tt_common_entry *common, int *sub_s)
|
||||
{
|
||||
struct batadv_tt_orig_list_entry *orig_entry, *best_entry;
|
||||
struct batadv_tt_global_entry *global;
|
||||
struct hlist_head *head;
|
||||
int sub = 0;
|
||||
bool best;
|
||||
|
||||
global = container_of(common, struct batadv_tt_global_entry, common);
|
||||
best_entry = batadv_transtable_best_orig(bat_priv, global);
|
||||
head = &global->orig_list;
|
||||
|
||||
hlist_for_each_entry_rcu(orig_entry, head, list) {
|
||||
if (sub++ < *sub_s)
|
||||
continue;
|
||||
|
||||
best = (orig_entry == best_entry);
|
||||
|
||||
if (batadv_tt_global_dump_subentry(msg, portid, seq, common,
|
||||
orig_entry, best)) {
|
||||
*sub_s = sub - 1;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
*sub_s = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_global_dump_bucket - Dump one TT local bucket into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @portid: Port making netlink request
|
||||
* @seq: Sequence number of netlink message
|
||||
* @bat_priv: The bat priv with all the soft interface information
|
||||
* @head: Pointer to the list containing the global tt entries
|
||||
* @idx_s: Number of entries to skip
|
||||
* @sub: Number of entries to skip
|
||||
*
|
||||
* Return: Error code, or 0 on success
|
||||
*/
|
||||
static int
|
||||
batadv_tt_global_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
struct batadv_priv *bat_priv,
|
||||
struct hlist_head *head, int *idx_s, int *sub)
|
||||
{
|
||||
struct batadv_tt_common_entry *common;
|
||||
int idx = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(common, head, hash_entry) {
|
||||
if (idx++ < *idx_s)
|
||||
continue;
|
||||
|
||||
if (batadv_tt_global_dump_entry(msg, portid, seq, bat_priv,
|
||||
common, sub)) {
|
||||
rcu_read_unlock();
|
||||
*idx_s = idx - 1;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
*idx_s = 0;
|
||||
*sub = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_global_dump - Dump TT global entries into a message
|
||||
* @msg: Netlink message to dump into
|
||||
* @cb: Parameters from query
|
||||
*
|
||||
* Return: Error code, or length of message on success
|
||||
*/
|
||||
int batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb)
|
||||
{
|
||||
struct net *net = sock_net(cb->skb->sk);
|
||||
struct net_device *soft_iface;
|
||||
struct batadv_priv *bat_priv;
|
||||
struct batadv_hard_iface *primary_if = NULL;
|
||||
struct batadv_hashtable *hash;
|
||||
struct hlist_head *head;
|
||||
int ret;
|
||||
int ifindex;
|
||||
int bucket = cb->args[0];
|
||||
int idx = cb->args[1];
|
||||
int sub = cb->args[2];
|
||||
int portid = NETLINK_CB(cb->skb).portid;
|
||||
|
||||
ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
|
||||
if (!ifindex)
|
||||
return -EINVAL;
|
||||
|
||||
soft_iface = dev_get_by_index(net, ifindex);
|
||||
if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bat_priv = netdev_priv(soft_iface);
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hash = bat_priv->tt.global_hash;
|
||||
|
||||
while (bucket < hash->size) {
|
||||
head = &hash->table[bucket];
|
||||
|
||||
if (batadv_tt_global_dump_bucket(msg, portid,
|
||||
cb->nlh->nlmsg_seq, bat_priv,
|
||||
head, &idx, &sub))
|
||||
break;
|
||||
|
||||
bucket++;
|
||||
}
|
||||
|
||||
ret = msg->len;
|
||||
|
||||
out:
|
||||
if (primary_if)
|
||||
batadv_hardif_put(primary_if);
|
||||
if (soft_iface)
|
||||
dev_put(soft_iface);
|
||||
|
||||
cb->args[0] = bucket;
|
||||
cb->args[1] = idx;
|
||||
cb->args[2] = sub;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* _batadv_tt_global_del_orig_entry - remove and free an orig_entry
|
||||
* @tt_global_entry: the global entry to remove the orig_entry from
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct netlink_callback;
|
||||
struct net_device;
|
||||
struct seq_file;
|
||||
struct sk_buff;
|
||||
|
||||
int batadv_tt_init(struct batadv_priv *bat_priv);
|
||||
bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
|
||||
|
@ -33,6 +35,8 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv,
|
|||
const char *message, bool roaming);
|
||||
int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset);
|
||||
int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset);
|
||||
int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb);
|
||||
int batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb);
|
||||
void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
|
||||
struct batadv_orig_node *orig_node,
|
||||
s32 match_vid, const char *message);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/if_ether.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/sched.h> /* for linux/wait.h */
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
@ -1418,6 +1419,7 @@ struct batadv_algo_iface_ops {
|
|||
* @is_similar_or_better: check if neigh1 is equally similar or better than
|
||||
* neigh2 for their respective outgoing interface from the metric prospective
|
||||
* @print: print the single hop neighbor list (optional)
|
||||
* @dump: dump neighbors to a netlink socket (optional)
|
||||
*/
|
||||
struct batadv_algo_neigh_ops {
|
||||
void (*hardif_init)(struct batadv_hardif_neigh_node *neigh);
|
||||
|
@ -1430,6 +1432,9 @@ struct batadv_algo_neigh_ops {
|
|||
struct batadv_neigh_node *neigh2,
|
||||
struct batadv_hard_iface *if_outgoing2);
|
||||
void (*print)(struct batadv_priv *priv, struct seq_file *seq);
|
||||
void (*dump)(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
struct batadv_priv *priv,
|
||||
struct batadv_hard_iface *hard_iface);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1441,6 +1446,7 @@ struct batadv_algo_neigh_ops {
|
|||
* @del_if: ask the routing algorithm to apply the needed changes to the
|
||||
* orig_node due to an hard-interface being removed from the mesh (optional)
|
||||
* @print: print the originator table (optional)
|
||||
* @dump: dump originators to a netlink socket (optional)
|
||||
*/
|
||||
struct batadv_algo_orig_ops {
|
||||
void (*free)(struct batadv_orig_node *orig_node);
|
||||
|
@ -1449,6 +1455,9 @@ struct batadv_algo_orig_ops {
|
|||
int del_if_num);
|
||||
void (*print)(struct batadv_priv *priv, struct seq_file *seq,
|
||||
struct batadv_hard_iface *hard_iface);
|
||||
void (*dump)(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
struct batadv_priv *priv,
|
||||
struct batadv_hard_iface *hard_iface);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1460,6 +1469,7 @@ struct batadv_algo_orig_ops {
|
|||
* @is_eligible: check if a newly discovered GW is a potential candidate for
|
||||
* the election as best GW (optional)
|
||||
* @print: print the gateway table (optional)
|
||||
* @dump: dump gateways to a netlink socket (optional)
|
||||
*/
|
||||
struct batadv_algo_gw_ops {
|
||||
ssize_t (*store_sel_class)(struct batadv_priv *bat_priv, char *buff,
|
||||
|
@ -1471,6 +1481,8 @@ struct batadv_algo_gw_ops {
|
|||
struct batadv_orig_node *curr_gw_orig,
|
||||
struct batadv_orig_node *orig_node);
|
||||
void (*print)(struct batadv_priv *bat_priv, struct seq_file *seq);
|
||||
void (*dump)(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
struct batadv_priv *priv);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue