cfg80211: always notify userspace of new wireless netdevs
authorDenis Kenzior <denkenz@gmail.com>
Wed, 3 Aug 2016 21:58:33 +0000 (16:58 -0500)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 11 Aug 2016 14:51:41 +0000 (16:51 +0200)
This change alters the semantics of NL80211_CMD_NEW_INTERFACE events
by always sending this event whenever a new net_device object
associated with a wdev is registered.  Prior to this change, this event
was only sent as a result of NL80211_CMD_NEW_INTERFACE command sent
from userspace.  This allows userspace to reliably detect new wireless
interfaces (e.g. due to hardware hot-plug events, etc).

For wdevs created without an associated net_device object (e.g.
NL80211_IFTYPE_P2P_DEVICE), the NL80211_CMD_NEW_INTERFACE event is
still generated inside the relevant nl80211 command handler.

Signed-off-by: Denis Kenzior <denkenz@gmail.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/core.c
net/wireless/nl80211.c
net/wireless/nl80211.h

index 7645e97..7758c0f 100644 (file)
@@ -1079,6 +1079,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                     wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
                     wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
                        dev->priv_flags |= IFF_DONT_BRIDGE;
+
+               nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
                break;
        case NETDEV_GOING_DOWN:
                cfg80211_leave(rdev, wdev);
index f02653a..a8c062d 100644 (file)
@@ -2751,7 +2751,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct vif_params params;
        struct wireless_dev *wdev;
-       struct sk_buff *msg, *event;
+       struct sk_buff *msg;
        int err;
        enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
        u32 flags;
@@ -2855,20 +2855,15 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                return -ENOBUFS;
        }
 
-       event = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (event) {
-               if (nl80211_send_iface(event, 0, 0, 0,
-                                      rdev, wdev, false) < 0) {
-                       nlmsg_free(event);
-                       goto out;
-               }
-
-               genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
-                                       event, 0, NL80211_MCGRP_CONFIG,
-                                       GFP_KERNEL);
-       }
+       /*
+        * For wdevs which have no associated netdev object (e.g. of type
+        * NL80211_IFTYPE_P2P_DEVICE), emit the NEW_INTERFACE event here.
+        * For all other types, the event will be generated from the
+        * netdev notifier
+        */
+       if (!wdev->netdev)
+               nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
 
-out:
        return genlmsg_reply(msg, info);
 }
 
@@ -11847,6 +11842,29 @@ void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
                                NL80211_MCGRP_CONFIG, GFP_KERNEL);
 }
 
+void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
+                               struct wireless_dev *wdev,
+                               enum nl80211_commands cmd)
+{
+       struct sk_buff *msg;
+
+       WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
+               cmd != NL80211_CMD_DEL_INTERFACE);
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return;
+
+       if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev,
+                              cmd == NL80211_CMD_DEL_INTERFACE) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+                               NL80211_MCGRP_CONFIG, GFP_KERNEL);
+}
+
 static int nl80211_add_scan_req(struct sk_buff *msg,
                                struct cfg80211_registered_device *rdev)
 {
index a63f402..7e3821d 100644 (file)
@@ -7,6 +7,9 @@ int nl80211_init(void);
 void nl80211_exit(void);
 void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
                          enum nl80211_commands cmd);
+void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
+                         struct wireless_dev *wdev,
+                         enum nl80211_commands cmd);
 void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
                             struct wireless_dev *wdev);
 struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,