The following commit has been merged in the master branch:
commit f463c99b208718b4fd25ec3501e0bd9d2e30f522
Merge: 5a2138812604c32b7617b3b2e53e336617121d3b 9b4aec647a92a2464337db10507348aecf0f0fd7
Author: David S. Miller <davem(a)davemloft.net>
Date: Sat Nov 19 11:13:05 2016 -0500
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: David S. Miller <davem(a)davemloft.net>
diff --combined net/batman-adv/hard-interface.c
index dc1816e,61a431a..672150b4
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@@ -92,8 -92,8 +92,8 @@@ out
*
* 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 +116,9 @@@
* 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 +154,7 @@@ static bool batadv_is_on_batman_iface(c
{
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 +202,77 @@@ static bool batadv_is_valid_iface(cons
}
/**
- * 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.
*/
- bool batadv_is_wifi_netdev(struct net_device *net_device)
+ 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.
+ */
+ static bool batadv_is_wext_netdev(struct net_device *net_device)
{
if (!net_device)
return false;
@@@ -221,6 -285,22 +285,22 @@@
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;
@@@ -229,6 -309,73 +309,73 @@@
}
/**
+ * 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
* @orig_addr: the originator of this packet
@@@ -704,6 -851,7 +851,6 @@@ void batadv_hardif_disable_interface(st
batadv_softif_destroy_sysfs(hard_iface->soft_iface);
}
- hard_iface->soft_iface = NULL;
batadv_hardif_put(hard_iface);
out:
@@@ -748,7 -896,8 +895,8 @@@ batadv_hardif_add_interface(struct net_
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 -1006,11 +1005,11 @@@ static int batadv_hard_if_event(struct
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;
}
--
LinuxNextTracking