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@davemloft.net>
This commit is contained in:
@@ -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 @@ 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.
|
||||
*/
|
||||
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 @@ 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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user