]> Git Repo - linux.git/commitdiff
Merge tag 'batadv-next-for-davem-20161119' of git://git.open-mesh.org/linux-merge
authorDavid S. Miller <[email protected]>
Sat, 19 Nov 2016 16:13:05 +0000 (11:13 -0500)
committerDavid S. Miller <[email protected]>
Sat, 19 Nov 2016 16:13:05 +0000 (11:13 -0500)
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 <[email protected]>
1  2 
net/batman-adv/hard-interface.c

index dc1816e9d53bca0c78f91772ec657bf4d95d979d,61a431a9772ba96418644b399c9e787cbfd0e743..672150b42c61b6cb4e1595e5a9a4d570b600cf06
@@@ -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;
   * 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;
                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;
        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
@@@ -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;
        }
This page took 0.082257 seconds and 4 git commands to generate.