Search Linux Wireless

[PATCH 5/5] cfg80211: userspace commands/notifications

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---
 include/linux/nl80211.h |   11 +++++
 include/net/cfg80211.h  |   18 ++++++++
 net/mac80211/cfg.c      |    1 +
 net/mac80211/radar.c    |   21 +++++++++
 net/wireless/nl80211.c  |  104 +++++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/nl80211.h  |    4 ++
 net/wireless/util.c     |   20 +++++++++
 7 files changed, 179 insertions(+), 0 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index acb3c33..fa65287 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -410,6 +410,12 @@
  *	notification. This event is used to indicate that an unprotected
  *	disassociation frame was dropped when MFP is in use.
  *
+ * @NL80211_CMD_RADAR_CAC_START: Request a CAC
+ * @NL80211_CMD_RADAR_CAC_STOP: Stop as CAC earler
+ * @NL80211_CMD_RADAR_CAC_DONE: Notification sent if a CAC has completed.
+ * @NL80211_CMD_RADAR_FLAGS_CHANGED: Notification sent if channel flags
+ *	have changed.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -522,6 +528,11 @@ enum nl80211_commands {
 	NL80211_CMD_UNPROT_DEAUTHENTICATE,
 	NL80211_CMD_UNPROT_DISASSOCIATE,
 
+	NL80211_CMD_RADAR_CAC_START,
+	NL80211_CMD_RADAR_CAC_STOP,
+	NL80211_CMD_RADAR_CAC_DONE,
+	NL80211_CMD_RADAR_FLAGS_CHANGED,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1e9a052..4f77662 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1200,6 +1200,8 @@ struct cfg80211_pmksa {
  *	(also see nl80211.h @NL80211_ATTR_WIPHY_ANTENNA_TX).
  *
  * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant).
+ *
+ * @radar_cac: Request CAC.
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy);
@@ -1367,6 +1369,8 @@ struct cfg80211_ops {
 
 	int	(*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant);
 	int	(*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant);
+
+	int	(*radar_cac)(struct wiphy *wiphy, int enable);
 };
 
 /*
@@ -2720,6 +2724,20 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 void cfg80211_cqm_pktloss_notify(struct net_device *dev,
 				 const u8 *peer, u32 num_packets, gfp_t gfp);
 
+/**
+ * cfg80211_radar_cac_done - notify userspace that a CAC has been done.
+ * @wiphy: the wireless device to give the hint
+ */
+int cfg80211_radar_cac_done(struct wiphy *wiphy);
+
+/**
+ * cfg80211_radar_flags_changed - notify userspace about channel flag changes
+ * @wiphy: the wireless device to give the hint
+ * @channel: the channel on which flag changes occurred
+ */
+int cfg80211_radar_flags_changed(struct wiphy *wiphy,
+				 struct ieee80211_channel *channel);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a6a2c0b..43f657d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1999,4 +1999,5 @@ struct cfg80211_ops mac80211_config_ops = {
 	.mgmt_frame_register = ieee80211_mgmt_frame_register,
 	.set_antenna = ieee80211_set_antenna,
 	.get_antenna = ieee80211_get_antenna,
+	.radar_cac = ieee80211_radar_cac,
 };
diff --git a/net/mac80211/radar.c b/net/mac80211/radar.c
index afb2ae1..d825e3c 100644
--- a/net/mac80211/radar.c
+++ b/net/mac80211/radar.c
@@ -18,8 +18,10 @@
 static void cac_timer(unsigned long data)
 {
 	struct ieee80211_local *local = (void *) data;
+	struct wiphy *wiphy = local->hw.wiphy;
 	struct ieee80211_radar *radar = &local->radar;
 	struct ieee80211_channel *chan;
+	int changed = 0;
 
 	printk(KERN_INFO "CAC done\n");
 
@@ -27,9 +29,16 @@ static void cac_timer(unsigned long data)
 	mutex_lock(&radar->mtx);
 	if ((chan->flags & IEEE80211_CHAN_RADAR_INTERFERENCE) == 0) {
 		chan->flags |= IEEE80211_CHAN_RADAR_CLEAR;
+		changed = 1;
 	}
+	mutex_unlock(&radar->mtx);
+	if (changed)
+		cfg80211_radar_flags_changed(wiphy, chan);
+
+	mutex_lock(&radar->mtx);
 	radar->cac = 0;
 	mutex_unlock(&radar->mtx);
+	cfg80211_radar_cac_done(wiphy);
 }
 
 int ieee80211_radar_cac(struct wiphy *wiphy, int enable)
@@ -52,9 +61,12 @@ int ieee80211_radar_cac(struct wiphy *wiphy, int enable)
 		mutex_lock(&radar->mtx);
 		radar->cac = 0;
 		mutex_unlock(&radar->mtx);
+		cfg80211_radar_cac_done(wiphy);
 		return 0;
 	}
 	if (enable) {
+		int changed = 0;
+
 		if ((chan->flags & IEEE80211_CHAN_RADAR_INTERFERENCE))
 			return -EINVAL;
 
@@ -65,7 +77,12 @@ int ieee80211_radar_cac(struct wiphy *wiphy, int enable)
 		if ((chan->flags & IEEE80211_CHAN_RADAR) &&
 		    (chan->flags & IEEE80211_CHAN_RADAR_CLEAR)) {
 			chan->flags &= ~IEEE80211_CHAN_RADAR_CLEAR;
+			changed = 1;
 		}
+		mutex_unlock(&radar->mtx);
+		if (changed)
+			cfg80211_radar_flags_changed(wiphy, chan);
+		mutex_lock(&radar->mtx);
 		radar->cac = 1;
 		mutex_unlock(&radar->mtx);
 		mod_timer(&radar->cac_timer, jiffies +
@@ -78,6 +95,7 @@ int ieee80211_radar_cac(struct wiphy *wiphy, int enable)
 static void nol_timer(unsigned long data)
 {
 	struct ieee80211_local *local = (void *) data;
+	struct wiphy *wiphy = local->hw.wiphy;
 	struct ieee80211_radar *radar = &local->radar;
 	struct ieee80211_radar_nol_list *nol, *tmp;
 
@@ -93,6 +111,7 @@ static void nol_timer(unsigned long data)
 			list_del(&nol->list);
 			mutex_unlock(&radar->mtx);
 			kfree(nol);
+			cfg80211_radar_flags_changed(wiphy, chan);
 		}
 	}
 
@@ -103,6 +122,7 @@ int ieee80211_radar_interference(struct ieee80211_hw *hw,
 				 struct ieee80211_channel *chan)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
+	struct wiphy *wiphy = local->hw.wiphy;
 	struct ieee80211_radar *radar = &local->radar;
 	struct ieee80211_radar_nol_list *nol, *tmp;
 
@@ -131,6 +151,7 @@ int ieee80211_radar_interference(struct ieee80211_hw *hw,
 	chan->flags |= IEEE80211_CHAN_RADAR_INTERFERENCE;
 	list_add_tail(&nol->list, &radar->nol_list);
 	mutex_unlock(&radar->mtx);
+	cfg80211_radar_flags_changed(wiphy, chan);
 
 	return 0;
 }
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0524423..2f43b6e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4729,6 +4729,26 @@ out:
 	return err;
 }
 
+static int nl80211_radar_start_cac(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+	if (!rdev->ops->radar_cac)
+		return -EOPNOTSUPP;
+
+	return rdev->ops->radar_cac(&rdev->wiphy, 1);
+}
+
+static int nl80211_radar_stop_cac(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+	if (!rdev->ops->radar_cac)
+		return -EOPNOTSUPP;
+
+	return rdev->ops->radar_cac(&rdev->wiphy, 0);
+}
+
 static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -5271,6 +5291,22 @@ static struct genl_ops nl80211_ops[] = {
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_RADAR_CAC_START,
+		.doit = nl80211_radar_start_cac,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
+		.cmd = NL80211_CMD_RADAR_CAC_STOP,
+		.doit = nl80211_radar_stop_cac,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV |
+				  NL80211_FLAG_NEED_RTNL,
+	},
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -6128,6 +6164,74 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
 	nlmsg_free(msg);
 }
 
+void nl80211_radar_cac_done(struct cfg80211_registered_device *rdev)
+{
+	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_RADAR_CAC_DONE);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+
+	if (genlmsg_end(msg, hdr) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+				nl80211_mlme_mcgrp.id, GFP_KERNEL);
+	return;
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+}
+
+void nl80211_radar_flags_changed(struct cfg80211_registered_device *rdev,
+				 struct ieee80211_channel *chan)
+{
+	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_RADAR_FLAGS_CHANGED);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+	NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, chan->center_freq);
+	if ((chan->flags & IEEE80211_CHAN_RADAR_CLEAR))
+		NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR_CLEAR);
+	if ((chan->flags & IEEE80211_CHAN_RADAR_INTERFERENCE))
+		NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR_INTERFERENCE);
+
+	if (genlmsg_end(msg, hdr) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+				nl80211_mlme_mcgrp.id, GFP_KERNEL);
+	return;
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+}
+
 static int nl80211_netlink_notify(struct notifier_block * nb,
 				  unsigned long state,
 				  void *_notify)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index e3f7fa8..e7f84d8 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -98,4 +98,8 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
 				struct net_device *netdev, const u8 *peer,
 				u32 num_packets, gfp_t gfp);
 
+void nl80211_radar_cac_done(struct cfg80211_registered_device *rdev);
+void nl80211_radar_flags_changed(struct cfg80211_registered_device *rdev,
+				 struct ieee80211_channel *chan);
+
 #endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 7620ae2..3c87c2f 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -9,6 +9,7 @@
 #include <net/cfg80211.h>
 #include <net/ip.h>
 #include "core.h"
+#include "nl80211.h"
 
 struct ieee80211_rate *
 ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
@@ -885,3 +886,22 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate)
 	/* do NOT round down here */
 	return (bitrate + 50000) / 100000;
 }
+
+int cfg80211_radar_cac_done(struct wiphy *wiphy)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	nl80211_radar_cac_done(rdev);
+	return 0;
+}
+EXPORT_SYMBOL(cfg80211_radar_cac_done);
+
+int cfg80211_radar_flags_changed(struct wiphy *wiphy,
+				 struct ieee80211_channel *chan)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	nl80211_radar_flags_changed(rdev, chan);
+	return 0;
+}
+EXPORT_SYMBOL(cfg80211_radar_flags_changed);
-- 
1.5.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux