nl80211: send event when AP operation is stopped
authorJohannes Berg <johannes.berg@intel.com>
Fri, 24 Jan 2014 13:06:29 +0000 (14:06 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 4 Feb 2014 20:58:08 +0000 (21:58 +0100)
There are a few cases, e.g. suspend, where an AP interface is
stopped by the kernel rather than by userspace request, most
commonly when suspending. To let userspace know about this,
send the NL80211_CMD_STOP_AP command as an event every time
an AP interface is stopped. This also happens when userspace
did in fact request the AP stop, but that's not a problem.

For full-MAC drivers this may need to be extended to also
cover cases where the device stopped the AP operation for
some reason, this a bit more complicated because then all
cfg80211 state also needs to be reset; such API is not part
of this patch.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/ap.c
net/wireless/nl80211.c
net/wireless/nl80211.h

index 11ee4ed04f73ea2ae0dd1ae6293837785d8fd5f8..4760d6554e62c88862ddac7670c95359788b4342 100644 (file)
@@ -30,6 +30,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
                wdev->channel = NULL;
                wdev->ssid_len = 0;
                rdev_set_qos_map(rdev, dev, NULL);
+               nl80211_send_ap_stopped(wdev);
        }
 
        return err;
index 9ed6ef6fd2c5413250dd9d11e6566cd5723c6546..043bfbd58b56c08f5908f3d564ec8001ad0fd1a1 100644 (file)
@@ -11677,6 +11677,35 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
 }
 EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
 
+void nl80211_send_ap_stopped(struct wireless_dev *wdev)
+{
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
+       if (!hdr)
+               goto out;
+
+       if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+           nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
+           nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
+               goto out;
+
+       genlmsg_end(msg, hdr);
+
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, GFP_KERNEL);
+       return;
+ out:
+       nlmsg_free(msg);
+}
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)
index b1b231324e102a44218bcf2354e52662fac78f5a..cb0216e1a0041b1c66b2a4a3e55405492b7743f7 100644 (file)
@@ -74,6 +74,8 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
                     enum nl80211_radar_event event,
                     struct net_device *netdev, gfp_t gfp);
 
+void nl80211_send_ap_stopped(struct wireless_dev *wdev);
+
 void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev);
 
 #endif /* __NET_WIRELESS_NL80211_H */