aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2013-02-08 12:16:19 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-15 03:40:18 -0500
commit04f39047af2a6df64b763ea5a271db24879d0391 (patch)
tree883a946e25f18e27abad2ed487a4ed4c88ff349c /net/wireless/nl80211.c
parent2a0e047ed62f20664005881b8e7f9328f910316a (diff)
nl80211/cfg80211: add radar detection command/event
Add new NL80211_CMD_RADAR_DETECT, which starts the Channel Availability Check (CAC). This command will also notify the usermode about events (CAC finished, CAC aborted, radar detected, NOP finished). Once radar detection has started it should continuously monitor for radars as long as the channel is active. This patch enables DFS for AP mode in nl80211/cfg80211. Based on original patch by Victor Goldenshtein <victorg@ti.com> Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> [remove WIPHY_FLAG_HAS_RADAR_DETECT again -- my mistake] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c135
1 files changed, 130 insertions, 5 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d29a461b4981..c1e18ccf4049 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -552,9 +552,16 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
552 if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && 552 if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
553 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) 553 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
554 goto nla_put_failure; 554 goto nla_put_failure;
555 if ((chan->flags & IEEE80211_CHAN_RADAR) && 555 if (chan->flags & IEEE80211_CHAN_RADAR) {
556 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) 556 u32 time = elapsed_jiffies_msecs(chan->dfs_state_entered);
557 goto nla_put_failure; 557 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
558 goto nla_put_failure;
559 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
560 chan->dfs_state))
561 goto nla_put_failure;
562 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, time))
563 goto nla_put_failure;
564 }
558 565
559 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, 566 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
560 DBM_TO_MBM(chan->max_power))) 567 DBM_TO_MBM(chan->max_power)))
@@ -2775,6 +2782,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
2775 struct wireless_dev *wdev = dev->ieee80211_ptr; 2782 struct wireless_dev *wdev = dev->ieee80211_ptr;
2776 struct cfg80211_ap_settings params; 2783 struct cfg80211_ap_settings params;
2777 int err; 2784 int err;
2785 u8 radar_detect_width = 0;
2778 2786
2779 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && 2787 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2780 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) 2788 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
@@ -2893,9 +2901,19 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
2893 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef)) 2901 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
2894 return -EINVAL; 2902 return -EINVAL;
2895 2903
2904 err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef);
2905 if (err < 0)
2906 return err;
2907 if (err) {
2908 radar_detect_width = BIT(params.chandef.width);
2909 params.radar_required = true;
2910 }
2911
2896 mutex_lock(&rdev->devlist_mtx); 2912 mutex_lock(&rdev->devlist_mtx);
2897 err = cfg80211_can_use_chan(rdev, wdev, params.chandef.chan, 2913 err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
2898 CHAN_MODE_SHARED); 2914 params.chandef.chan,
2915 CHAN_MODE_SHARED,
2916 radar_detect_width);
2899 mutex_unlock(&rdev->devlist_mtx); 2917 mutex_unlock(&rdev->devlist_mtx);
2900 2918
2901 if (err) 2919 if (err)
@@ -5055,6 +5073,54 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb,
5055 return err; 5073 return err;
5056} 5074}
5057 5075
5076static int nl80211_start_radar_detection(struct sk_buff *skb,
5077 struct genl_info *info)
5078{
5079 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5080 struct net_device *dev = info->user_ptr[1];
5081 struct wireless_dev *wdev = dev->ieee80211_ptr;
5082 struct cfg80211_chan_def chandef;
5083 int err;
5084
5085 err = nl80211_parse_chandef(rdev, info, &chandef);
5086 if (err)
5087 return err;
5088
5089 if (wdev->cac_started)
5090 return -EBUSY;
5091
5092 err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef);
5093 if (err < 0)
5094 return err;
5095
5096 if (err == 0)
5097 return -EINVAL;
5098
5099 if (chandef.chan->dfs_state != NL80211_DFS_USABLE)
5100 return -EINVAL;
5101
5102 if (!rdev->ops->start_radar_detection)
5103 return -EOPNOTSUPP;
5104
5105 mutex_lock(&rdev->devlist_mtx);
5106 err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
5107 chandef.chan, CHAN_MODE_SHARED,
5108 BIT(chandef.width));
5109 if (err)
5110 goto err_locked;
5111
5112 err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef);
5113 if (!err) {
5114 wdev->channel = chandef.chan;
5115 wdev->cac_started = true;
5116 wdev->cac_start_time = jiffies;
5117 }
5118err_locked:
5119 mutex_unlock(&rdev->devlist_mtx);
5120
5121 return err;
5122}
5123
5058static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, 5124static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
5059 u32 seq, int flags, 5125 u32 seq, int flags,
5060 struct cfg80211_registered_device *rdev, 5126 struct cfg80211_registered_device *rdev,
@@ -8305,6 +8371,14 @@ static struct genl_ops nl80211_ops[] = {
8305 .internal_flags = NL80211_FLAG_NEED_NETDEV | 8371 .internal_flags = NL80211_FLAG_NEED_NETDEV |
8306 NL80211_FLAG_NEED_RTNL, 8372 NL80211_FLAG_NEED_RTNL,
8307 }, 8373 },
8374 {
8375 .cmd = NL80211_CMD_RADAR_DETECT,
8376 .doit = nl80211_start_radar_detection,
8377 .policy = nl80211_policy,
8378 .flags = GENL_ADMIN_PERM,
8379 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
8380 NL80211_FLAG_NEED_RTNL,
8381 },
8308}; 8382};
8309 8383
8310static struct genl_multicast_group nl80211_mlme_mcgrp = { 8384static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -9502,6 +9576,57 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
9502} 9576}
9503 9577
9504void 9578void
9579nl80211_radar_notify(struct cfg80211_registered_device *rdev,
9580 struct cfg80211_chan_def *chandef,
9581 enum nl80211_radar_event event,
9582 struct net_device *netdev, gfp_t gfp)
9583{
9584 struct sk_buff *msg;
9585 void *hdr;
9586
9587 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
9588 if (!msg)
9589 return;
9590
9591 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
9592 if (!hdr) {
9593 nlmsg_free(msg);
9594 return;
9595 }
9596
9597 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
9598 goto nla_put_failure;
9599
9600 /* NOP and radar events don't need a netdev parameter */
9601 if (netdev) {
9602 struct wireless_dev *wdev = netdev->ieee80211_ptr;
9603
9604 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
9605 nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
9606 goto nla_put_failure;
9607 }
9608
9609 if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
9610 goto nla_put_failure;
9611
9612 if (nl80211_send_chandef(msg, chandef))
9613 goto nla_put_failure;
9614
9615 if (genlmsg_end(msg, hdr) < 0) {
9616 nlmsg_free(msg);
9617 return;
9618 }
9619
9620 genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
9621 nl80211_mlme_mcgrp.id, gfp);
9622 return;
9623
9624 nla_put_failure:
9625 genlmsg_cancel(msg, hdr);
9626 nlmsg_free(msg);
9627}
9628
9629void
9505nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, 9630nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
9506 struct net_device *netdev, const u8 *peer, 9631 struct net_device *netdev, const u8 *peer,
9507 u32 num_packets, gfp_t gfp) 9632 u32 num_packets, gfp_t gfp)