summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2014-01-24 14:06:29 +0100
committerJohannes Berg <johannes.berg@intel.com>2014-02-04 21:58:08 +0100
commit348baf0eac3391c62d441ec29b4c5da62ed91e74 (patch)
treed8255b3c6b16e330fc97671c5afcd666bee5a9be
parentd8ca16db6bb23d03fcb794df44bae64ae976f27c (diff)
nl80211: send event when AP operation is stopped
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>
-rw-r--r--net/wireless/ap.c1
-rw-r--r--net/wireless/nl80211.c29
-rw-r--r--net/wireless/nl80211.h2
3 files changed, 32 insertions, 0 deletions
diff --git a/net/wireless/ap.c b/net/wireless/ap.c
index 11ee4ed04f7..4760d6554e6 100644
--- a/net/wireless/ap.c
+++ b/net/wireless/ap.c
@@ -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;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 9ed6ef6fd2c..043bfbd58b5 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -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)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index b1b231324e1..cb0216e1a00 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -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 */