The following commit has been merged in the master branch: commit f463c99b208718b4fd25ec3501e0bd9d2e30f522 Merge: 5a2138812604c32b7617b3b2e53e336617121d3b 9b4aec647a92a2464337db10507348aecf0f0fd7 Author: David S. Miller davem@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@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; }