Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f463c99b authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'batadv-next-for-davem-20161119' of git://git.open-mesh.org/linux-merge



Simon Wunderlich says:

====================
This feature patchset includes the following changes:

 - 6 patches adding functionality to detect a WiFi interface under
   other virtual interfaces, like VLANs. They introduce a cache for
   the detected the WiFi configuration to avoid RTNL locking in
   critical sections. Patches have been prepared by Marek Lindner
   and Sven Eckelmann

 - Enable automatic module loading for genl requests, by Sven Eckelmann

 - Fix a potential race condition on interface removal. This is not
   happening very often in practice, but requires bigger changes to fix,
   so we are sending this to net-next. By Linus Luessing
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5a213881 9b4aec64
Loading
Loading
Loading
Loading
+7 −14
Original line number Diff line number Diff line
@@ -717,17 +717,10 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
	if (direct_link)
		forw_packet_aggr->direct_link_flags |= 1;

	/* add new packet to packet list */
	spin_lock_bh(&bat_priv->forw_bat_list_lock);
	hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list);
	spin_unlock_bh(&bat_priv->forw_bat_list_lock);

	/* start timer for this packet */
	INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
			  batadv_iv_send_outstanding_bat_ogm_packet);
	queue_delayed_work(batadv_event_workqueue,
			   &forw_packet_aggr->delayed_work,
			   send_time - jiffies);

	batadv_forw_packet_ogmv1_queue(bat_priv, forw_packet_aggr, send_time);
}

/* aggregate a new packet into the existing ogm packet */
@@ -1272,7 +1265,7 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
	 */
	tq_iface_penalty = BATADV_TQ_MAX_VALUE;
	if (if_outgoing && (if_incoming == if_outgoing) &&
	    batadv_is_wifi_netdev(if_outgoing->net_dev))
	    batadv_is_wifi_hardif(if_outgoing))
		tq_iface_penalty = batadv_hop_penalty(BATADV_TQ_MAX_VALUE,
						      bat_priv);

@@ -1789,9 +1782,6 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
	forw_packet = container_of(delayed_work, struct batadv_forw_packet,
				   delayed_work);
	bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface);
	spin_lock_bh(&bat_priv->forw_bat_list_lock);
	hlist_del(&forw_packet->list);
	spin_unlock_bh(&bat_priv->forw_bat_list_lock);

	if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) {
		dropped = true;
@@ -1813,6 +1803,9 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
		batadv_iv_ogm_schedule(forw_packet->if_incoming);

out:
	/* do we get something for free()? */
	if (batadv_forw_packet_steal(forw_packet,
				     &bat_priv->forw_bat_list_lock))
		batadv_forw_packet_free(forw_packet, dropped);
}

+23 −18
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
{
	struct batadv_hard_iface *hard_iface = neigh->if_incoming;
	struct ethtool_link_ksettings link_settings;
	struct net_device *real_netdev;
	struct station_info sinfo;
	u32 throughput;
	int ret;
@@ -89,10 +90,18 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
	/* if this is a wireless device, then ask its throughput through
	 * cfg80211 API
	 */
	if (batadv_is_wifi_netdev(hard_iface->net_dev)) {
		if (hard_iface->net_dev->ieee80211_ptr) {
			ret = cfg80211_get_station(hard_iface->net_dev,
						   neigh->addr, &sinfo);
	if (batadv_is_wifi_hardif(hard_iface)) {
		if (!batadv_is_cfg80211_hardif(hard_iface))
			/* unsupported WiFi driver version */
			goto default_throughput;

		real_netdev = batadv_get_real_netdev(hard_iface->net_dev);
		if (!real_netdev)
			goto default_throughput;

		ret = cfg80211_get_station(real_netdev, neigh->addr, &sinfo);

		dev_put(real_netdev);
		if (ret == -ENOENT) {
			/* Node is not associated anymore! It would be
			 * possible to delete this neighbor. For now set
@@ -104,10 +113,6 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
			return sinfo.expected_throughput / 100;
	}

		/* unsupported WiFi driver version */
		goto default_throughput;
	}

	/* if not a wifi interface, check if this device provides data via
	 * ethtool (e.g. an Ethernet adapter)
	 */
@@ -187,7 +192,7 @@ batadv_v_elp_wifi_neigh_probe(struct batadv_hardif_neigh_node *neigh)
	int elp_skb_len;

	/* this probing routine is for Wifi neighbours only */
	if (!batadv_is_wifi_netdev(hard_iface->net_dev))
	if (!batadv_is_wifi_hardif(hard_iface))
		return true;

	/* probe the neighbor only if no unicast packets have been sent
@@ -352,7 +357,7 @@ int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface)
	/* warn the user (again) if there is no throughput data is available */
	hard_iface->bat_v.flags &= ~BATADV_WARNING_DEFAULT;

	if (batadv_is_wifi_netdev(hard_iface->net_dev))
	if (batadv_is_wifi_hardif(hard_iface))
		hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;

	INIT_DELAYED_WORK(&hard_iface->bat_v.elp_wq,
+163 −10
Original line number Diff line number Diff line
@@ -92,8 +92,8 @@ batadv_hardif_get_by_netdev(const struct net_device *net_dev)
 *
 * 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)
static struct net *batadv_getlink_net(const struct net_device *netdev,
				      struct net *fallback_net)
{
	if (!netdev->rtnl_link_ops)
		return fallback_net;
@@ -116,9 +116,9 @@ static const struct net *batadv_getlink_net(const struct net_device *netdev,
 * Return: true if the devices are each others parent, otherwise false
 */
static bool batadv_mutual_parents(const struct net_device *dev1,
				  const struct net *net1,
				  struct net *net1,
				  const struct net_device *dev2,
				  const struct net *net2)
				  struct net *net2)
{
	int dev1_parent_iflink = dev_get_iflink(dev1);
	int dev2_parent_iflink = dev_get_iflink(dev2);
@@ -154,7 +154,7 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
{
	struct net *net = dev_net(net_dev);
	struct net_device *parent_dev;
	const struct net *parent_net;
	struct net *parent_net;
	bool ret;

	/* check if this is a batman-adv mesh interface */
@@ -202,13 +202,77 @@ static bool batadv_is_valid_iface(const struct net_device *net_dev)
}

/**
 * batadv_is_wifi_netdev - check if the given net_device struct is a wifi
 *  interface
 * batadv_get_real_netdevice - check if the given netdev struct is a virtual
 *  interface on top of another 'real' interface
 * @netdev: the device to check
 *
 * Callers must hold the rtnl semaphore. You may want batadv_get_real_netdev()
 * instead of this.
 *
 * Return: the 'real' net device or the original net device and NULL in case
 *  of an error.
 */
static struct net_device *batadv_get_real_netdevice(struct net_device *netdev)
{
	struct batadv_hard_iface *hard_iface = NULL;
	struct net_device *real_netdev = NULL;
	struct net *real_net;
	struct net *net;
	int ifindex;

	ASSERT_RTNL();

	if (!netdev)
		return NULL;

	if (netdev->ifindex == dev_get_iflink(netdev)) {
		dev_hold(netdev);
		return netdev;
	}

	hard_iface = batadv_hardif_get_by_netdev(netdev);
	if (!hard_iface || !hard_iface->soft_iface)
		goto out;

	net = dev_net(hard_iface->soft_iface);
	ifindex = dev_get_iflink(netdev);
	real_net = batadv_getlink_net(netdev, net);
	real_netdev = dev_get_by_index(real_net, ifindex);

out:
	if (hard_iface)
		batadv_hardif_put(hard_iface);
	return real_netdev;
}

/**
 * batadv_get_real_netdev - check if the given net_device struct is a virtual
 *  interface on top of another 'real' interface
 * @net_device: the device to check
 *
 * Return: true if the net device is a 802.11 wireless device, false otherwise.
 * Return: the 'real' net device or the original net device and NULL in case
 *  of an error.
 */
struct net_device *batadv_get_real_netdev(struct net_device *net_device)
{
	struct net_device *real_netdev;

	rtnl_lock();
	real_netdev = batadv_get_real_netdevice(net_device);
	rtnl_unlock();

	return real_netdev;
}

/**
 * batadv_is_wext_netdev - check if the given net_device struct is a
 *  wext wifi interface
 * @net_device: the device to check
 *
 * Return: true if the net device is a wext wireless device, false
 *  otherwise.
 */
bool batadv_is_wifi_netdev(struct net_device *net_device)
static bool batadv_is_wext_netdev(struct net_device *net_device)
{
	if (!net_device)
		return false;
@@ -221,6 +285,22 @@ bool batadv_is_wifi_netdev(struct net_device *net_device)
		return true;
#endif

	return false;
}

/**
 * batadv_is_cfg80211_netdev - check if the given net_device struct is a
 *  cfg80211 wifi interface
 * @net_device: the device to check
 *
 * Return: true if the net device is a cfg80211 wireless device, false
 *  otherwise.
 */
static bool batadv_is_cfg80211_netdev(struct net_device *net_device)
{
	if (!net_device)
		return false;

	/* cfg80211 drivers have to set ieee80211_ptr */
	if (net_device->ieee80211_ptr)
		return true;
@@ -228,6 +308,73 @@ bool batadv_is_wifi_netdev(struct net_device *net_device)
	return false;
}

/**
 * batadv_wifi_flags_evaluate - calculate wifi flags for net_device
 * @net_device: the device to check
 *
 * Return: batadv_hard_iface_wifi_flags flags of the device
 */
static u32 batadv_wifi_flags_evaluate(struct net_device *net_device)
{
	u32 wifi_flags = 0;
	struct net_device *real_netdev;

	if (batadv_is_wext_netdev(net_device))
		wifi_flags |= BATADV_HARDIF_WIFI_WEXT_DIRECT;

	if (batadv_is_cfg80211_netdev(net_device))
		wifi_flags |= BATADV_HARDIF_WIFI_CFG80211_DIRECT;

	real_netdev = batadv_get_real_netdevice(net_device);
	if (!real_netdev)
		return wifi_flags;

	if (real_netdev == net_device)
		goto out;

	if (batadv_is_wext_netdev(real_netdev))
		wifi_flags |= BATADV_HARDIF_WIFI_WEXT_INDIRECT;

	if (batadv_is_cfg80211_netdev(real_netdev))
		wifi_flags |= BATADV_HARDIF_WIFI_CFG80211_INDIRECT;

out:
	dev_put(real_netdev);
	return wifi_flags;
}

/**
 * batadv_is_cfg80211_hardif - check if the given hardif is a cfg80211 wifi
 *  interface
 * @hard_iface: the device to check
 *
 * Return: true if the net device is a cfg80211 wireless device, false
 *  otherwise.
 */
bool batadv_is_cfg80211_hardif(struct batadv_hard_iface *hard_iface)
{
	u32 allowed_flags = 0;

	allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_DIRECT;
	allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_INDIRECT;

	return !!(hard_iface->wifi_flags & allowed_flags);
}

/**
 * batadv_is_wifi_hardif - check if the given hardif is a wifi interface
 * @hard_iface: the device to check
 *
 * Return: true if the net device is a 802.11 wireless device, false otherwise.
 */
bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface)
{
	if (!hard_iface)
		return false;

	return hard_iface->wifi_flags != 0;
}

/**
 * batadv_hardif_no_broadcast - check whether (re)broadcast is necessary
 * @if_outgoing: the outgoing interface checked and considered for (re)broadcast
@@ -748,7 +895,8 @@ batadv_hardif_add_interface(struct net_device *net_dev)
	kref_init(&hard_iface->refcount);

	hard_iface->num_bcasts = BATADV_NUM_BCASTS_DEFAULT;
	if (batadv_is_wifi_netdev(net_dev))
	hard_iface->wifi_flags = batadv_wifi_flags_evaluate(net_dev);
	if (batadv_is_wifi_hardif(hard_iface))
		hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;

	batadv_v_hardif_init(hard_iface);
@@ -857,6 +1005,11 @@ static int batadv_hard_if_event(struct notifier_block *this,
		if (hard_iface == primary_if)
			batadv_primary_if_update_addr(bat_priv, NULL);
		break;
	case NETDEV_CHANGEUPPER:
		hard_iface->wifi_flags = batadv_wifi_flags_evaluate(net_dev);
		if (batadv_is_wifi_hardif(hard_iface))
			hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;
		break;
	default:
		break;
	}
+3 −2
Original line number Diff line number Diff line
@@ -65,8 +65,9 @@ enum batadv_hard_if_cleanup {

extern struct notifier_block batadv_hard_if_notifier;

bool batadv_is_wifi_netdev(struct net_device *net_device);
bool batadv_is_wifi_iface(int ifindex);
struct net_device *batadv_get_real_netdev(struct net_device *net_device);
bool batadv_is_cfg80211_hardif(struct batadv_hard_iface *hard_iface);
bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface);
struct batadv_hard_iface*
batadv_hardif_get_by_netdev(const struct net_device *net_dev);
int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
+3 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/crc32c.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/genetlink.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/init.h>
@@ -44,6 +45,7 @@
#include <linux/workqueue.h>
#include <net/dsfield.h>
#include <net/rtnetlink.h>
#include <uapi/linux/batman_adv.h>

#include "bat_algo.h"
#include "bat_iv_ogm.h"
@@ -648,3 +650,4 @@ MODULE_DESCRIPTION(BATADV_DRIVER_DESC);
MODULE_SUPPORTED_DEVICE(BATADV_DRIVER_DEVICE);
MODULE_VERSION(BATADV_SOURCE_VERSION);
MODULE_ALIAS_RTNL_LINK("batadv");
MODULE_ALIAS_GENL_FAMILY(BATADV_NL_NAME);
Loading