aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/chan.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/chan.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/chan.c')
-rw-r--r--net/wireless/chan.c129
1 files changed, 127 insertions, 2 deletions
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 396373f3ec26..810c23cfb894 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -147,6 +147,32 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
147 } 147 }
148} 148}
149 149
150static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
151{
152 int width;
153
154 switch (c->width) {
155 case NL80211_CHAN_WIDTH_20:
156 case NL80211_CHAN_WIDTH_20_NOHT:
157 width = 20;
158 break;
159 case NL80211_CHAN_WIDTH_40:
160 width = 40;
161 break;
162 case NL80211_CHAN_WIDTH_80P80:
163 case NL80211_CHAN_WIDTH_80:
164 width = 80;
165 break;
166 case NL80211_CHAN_WIDTH_160:
167 width = 160;
168 break;
169 default:
170 WARN_ON_ONCE(1);
171 return -1;
172 }
173 return width;
174}
175
150const struct cfg80211_chan_def * 176const struct cfg80211_chan_def *
151cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, 177cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
152 const struct cfg80211_chan_def *c2) 178 const struct cfg80211_chan_def *c2)
@@ -192,6 +218,93 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
192} 218}
193EXPORT_SYMBOL(cfg80211_chandef_compatible); 219EXPORT_SYMBOL(cfg80211_chandef_compatible);
194 220
221static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
222 u32 bandwidth,
223 enum nl80211_dfs_state dfs_state)
224{
225 struct ieee80211_channel *c;
226 u32 freq;
227
228 for (freq = center_freq - bandwidth/2 + 10;
229 freq <= center_freq + bandwidth/2 - 10;
230 freq += 20) {
231 c = ieee80211_get_channel(wiphy, freq);
232 if (!c || !(c->flags & IEEE80211_CHAN_RADAR))
233 continue;
234
235 c->dfs_state = dfs_state;
236 c->dfs_state_entered = jiffies;
237 }
238}
239
240void cfg80211_set_dfs_state(struct wiphy *wiphy,
241 const struct cfg80211_chan_def *chandef,
242 enum nl80211_dfs_state dfs_state)
243{
244 int width;
245
246 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
247 return;
248
249 width = cfg80211_chandef_get_width(chandef);
250 if (width < 0)
251 return;
252
253 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
254 width, dfs_state);
255
256 if (!chandef->center_freq2)
257 return;
258 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
259 width, dfs_state);
260}
261
262static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
263 u32 center_freq,
264 u32 bandwidth)
265{
266 struct ieee80211_channel *c;
267 u32 freq;
268
269 for (freq = center_freq - bandwidth/2 + 10;
270 freq <= center_freq + bandwidth/2 - 10;
271 freq += 20) {
272 c = ieee80211_get_channel(wiphy, freq);
273 if (!c)
274 return -EINVAL;
275
276 if (c->flags & IEEE80211_CHAN_RADAR)
277 return 1;
278 }
279 return 0;
280}
281
282
283int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
284 const struct cfg80211_chan_def *chandef)
285{
286 int width;
287 int r;
288
289 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
290 return -EINVAL;
291
292 width = cfg80211_chandef_get_width(chandef);
293 if (width < 0)
294 return -EINVAL;
295
296 r = cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq1,
297 width);
298 if (r)
299 return r;
300
301 if (!chandef->center_freq2)
302 return 0;
303
304 return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2,
305 width);
306}
307
195static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, 308static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
196 u32 center_freq, u32 bandwidth, 309 u32 center_freq, u32 bandwidth,
197 u32 prohibited_flags) 310 u32 prohibited_flags)
@@ -203,7 +316,16 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
203 freq <= center_freq + bandwidth/2 - 10; 316 freq <= center_freq + bandwidth/2 - 10;
204 freq += 20) { 317 freq += 20) {
205 c = ieee80211_get_channel(wiphy, freq); 318 c = ieee80211_get_channel(wiphy, freq);
206 if (!c || c->flags & prohibited_flags) 319 if (!c)
320 return false;
321
322 /* check for radar flags */
323 if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) &&
324 (c->dfs_state != NL80211_DFS_AVAILABLE))
325 return false;
326
327 /* check for the other flags */
328 if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR)
207 return false; 329 return false;
208 } 330 }
209 331
@@ -344,7 +466,10 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
344 break; 466 break;
345 case NL80211_IFTYPE_AP: 467 case NL80211_IFTYPE_AP:
346 case NL80211_IFTYPE_P2P_GO: 468 case NL80211_IFTYPE_P2P_GO:
347 if (wdev->beacon_interval) { 469 if (wdev->cac_started) {
470 *chan = wdev->channel;
471 *chanmode = CHAN_MODE_SHARED;
472 } else if (wdev->beacon_interval) {
348 *chan = wdev->channel; 473 *chan = wdev->channel;
349 *chanmode = CHAN_MODE_SHARED; 474 *chanmode = CHAN_MODE_SHARED;
350 } 475 }