aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/mlme.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/mlme.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/mlme.c')
-rw-r--r--net/wireless/mlme.c120
1 files changed, 120 insertions, 0 deletions
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 8e6920728c43..caddca35d686 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -987,3 +987,123 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
987 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); 987 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
988} 988}
989EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); 989EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
990
991void cfg80211_dfs_channels_update_work(struct work_struct *work)
992{
993 struct delayed_work *delayed_work;
994 struct cfg80211_registered_device *rdev;
995 struct cfg80211_chan_def chandef;
996 struct ieee80211_supported_band *sband;
997 struct ieee80211_channel *c;
998 struct wiphy *wiphy;
999 bool check_again = false;
1000 unsigned long timeout, next_time = 0;
1001 int bandid, i;
1002
1003 delayed_work = container_of(work, struct delayed_work, work);
1004 rdev = container_of(delayed_work, struct cfg80211_registered_device,
1005 dfs_update_channels_wk);
1006 wiphy = &rdev->wiphy;
1007
1008 mutex_lock(&cfg80211_mutex);
1009 for (bandid = 0; bandid < IEEE80211_NUM_BANDS; bandid++) {
1010 sband = wiphy->bands[bandid];
1011 if (!sband)
1012 continue;
1013
1014 for (i = 0; i < sband->n_channels; i++) {
1015 c = &sband->channels[i];
1016
1017 if (c->dfs_state != NL80211_DFS_UNAVAILABLE)
1018 continue;
1019
1020 timeout = c->dfs_state_entered +
1021 IEEE80211_DFS_MIN_NOP_TIME_MS;
1022
1023 if (time_after_eq(jiffies, timeout)) {
1024 c->dfs_state = NL80211_DFS_USABLE;
1025 cfg80211_chandef_create(&chandef, c,
1026 NL80211_CHAN_NO_HT);
1027
1028 nl80211_radar_notify(rdev, &chandef,
1029 NL80211_RADAR_NOP_FINISHED,
1030 NULL, GFP_ATOMIC);
1031 continue;
1032 }
1033
1034 if (!check_again)
1035 next_time = timeout - jiffies;
1036 else
1037 next_time = min(next_time, timeout - jiffies);
1038 check_again = true;
1039 }
1040 }
1041 mutex_unlock(&cfg80211_mutex);
1042
1043 /* reschedule if there are other channels waiting to be cleared again */
1044 if (check_again)
1045 queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk,
1046 next_time);
1047}
1048
1049
1050void cfg80211_radar_event(struct wiphy *wiphy,
1051 struct cfg80211_chan_def *chandef,
1052 gfp_t gfp)
1053{
1054 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
1055 unsigned long timeout;
1056
1057 trace_cfg80211_radar_event(wiphy, chandef);
1058
1059 /* only set the chandef supplied channel to unavailable, in
1060 * case the radar is detected on only one of multiple channels
1061 * spanned by the chandef.
1062 */
1063 cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE);
1064
1065 timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS);
1066 queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk,
1067 timeout);
1068
1069 nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp);
1070}
1071EXPORT_SYMBOL(cfg80211_radar_event);
1072
1073void cfg80211_cac_event(struct net_device *netdev,
1074 enum nl80211_radar_event event, gfp_t gfp)
1075{
1076 struct wireless_dev *wdev = netdev->ieee80211_ptr;
1077 struct wiphy *wiphy = wdev->wiphy;
1078 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
1079 struct cfg80211_chan_def chandef;
1080 unsigned long timeout;
1081
1082 trace_cfg80211_cac_event(netdev, event);
1083
1084 if (WARN_ON(!wdev->cac_started))
1085 return;
1086
1087 if (WARN_ON(!wdev->channel))
1088 return;
1089
1090 cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT);
1091
1092 switch (event) {
1093 case NL80211_RADAR_CAC_FINISHED:
1094 timeout = wdev->cac_start_time +
1095 msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
1096 WARN_ON(!time_after_eq(jiffies, timeout));
1097 cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE);
1098 break;
1099 case NL80211_RADAR_CAC_ABORTED:
1100 break;
1101 default:
1102 WARN_ON(1);
1103 return;
1104 }
1105 wdev->cac_started = false;
1106
1107 nl80211_radar_notify(rdev, &chandef, event, netdev, gfp);
1108}
1109EXPORT_SYMBOL(cfg80211_cac_event);