Skip to content

Commit

Permalink
nl80211/cfg80211: add radar detection command/event
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Simon Wunderlich authored and Johannes Berg committed Feb 15, 2013
1 parent 2a0e047 commit 04f3904
Show file tree
Hide file tree
Showing 11 changed files with 570 additions and 17 deletions.
46 changes: 46 additions & 0 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ enum ieee80211_channel_flags {
#define IEEE80211_CHAN_NO_HT40 \
(IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)

#define IEEE80211_DFS_MIN_CAC_TIME_MS 60000
#define IEEE80211_DFS_MIN_NOP_TIME_MS (30 * 60 * 1000)

/**
* struct ieee80211_channel - channel definition
*
Expand All @@ -134,6 +137,9 @@ enum ieee80211_channel_flags {
* to enable this, this is useful only on 5 GHz band.
* @orig_mag: internal use
* @orig_mpwr: internal use
* @dfs_state: current state of this channel. Only relevant if radar is required
* on this channel.
* @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
*/
struct ieee80211_channel {
enum ieee80211_band band;
Expand All @@ -146,6 +152,8 @@ struct ieee80211_channel {
bool beacon_found;
u32 orig_flags;
int orig_mag, orig_mpwr;
enum nl80211_dfs_state dfs_state;
unsigned long dfs_state_entered;
};

/**
Expand Down Expand Up @@ -569,6 +577,7 @@ struct cfg80211_acl_data {
* @p2p_opp_ps: P2P opportunistic PS
* @acl: ACL configuration used by the drivers which has support for
* MAC address based access control
* @radar_required: set if radar detection is required
*/
struct cfg80211_ap_settings {
struct cfg80211_chan_def chandef;
Expand All @@ -586,6 +595,7 @@ struct cfg80211_ap_settings {
u8 p2p_ctwindow;
bool p2p_opp_ps;
const struct cfg80211_acl_data *acl;
bool radar_required;
};

/**
Expand Down Expand Up @@ -1909,6 +1919,8 @@ struct cfg80211_gtk_rekey_data {
* this new list replaces the existing one. Driver has to clear its ACL
* when number of MAC addresses entries is passed as 0. Drivers which
* advertise the support for MAC based ACL have to implement this callback.
*
* @start_radar_detection: Start radar detection in the driver.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
Expand Down Expand Up @@ -2132,6 +2144,10 @@ struct cfg80211_ops {

int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev,
const struct cfg80211_acl_data *params);

int (*start_radar_detection)(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_chan_def *chandef);
};

/*
Expand Down Expand Up @@ -2715,6 +2731,8 @@ struct cfg80211_cached_keys;
* beacons, 0 when not valid
* @address: The address for this device, valid only if @netdev is %NULL
* @p2p_started: true if this is a P2P Device that has been started
* @cac_started: true if DFS channel availability check has been started
* @cac_start_time: timestamp (jiffies) when the dfs state was entered.
*/
struct wireless_dev {
struct wiphy *wiphy;
Expand Down Expand Up @@ -2766,6 +2784,9 @@ struct wireless_dev {

u32 ap_unexpected_nlportid;

bool cac_started;
unsigned long cac_start_time;

#ifdef CONFIG_CFG80211_WEXT
/* wext data */
struct {
Expand Down Expand Up @@ -3754,6 +3775,31 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
enum nl80211_cqm_rssi_threshold_event rssi_event,
gfp_t gfp);

/**
* cfg80211_radar_event - radar detection event
* @wiphy: the wiphy
* @chandef: chandef for the current channel
* @gfp: context flags
*
* This function is called when a radar is detected on the current chanenl.
*/
void cfg80211_radar_event(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef, gfp_t gfp);

/**
* cfg80211_cac_event - Channel availability check (CAC) event
* @netdev: network device
* @event: type of event
* @gfp: context flags
*
* This function is called when a Channel availability check (CAC) is finished
* or aborted. This must be called to notify the completion of a CAC process,
* also by full-MAC drivers.
*/
void cfg80211_cac_event(struct net_device *netdev,
enum nl80211_radar_event event, gfp_t gfp);


/**
* cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer
* @dev: network device
Expand Down
61 changes: 61 additions & 0 deletions include/uapi/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,14 @@
* command is used in AP/P2P GO mode. Driver has to make sure to clear its
* ACL list during %NL80211_CMD_STOP_AP.
*
* @NL80211_CMD_RADAR_DETECT: Start a Channel availability check (CAC). Once
* a radar is detected or the channel availability scan (CAC) has finished
* or was aborted, or a radar was detected, usermode will be notified with
* this event. This command is also used to notify userspace about radars
* while operating on this channel.
* %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the
* event.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
Expand Down Expand Up @@ -755,6 +763,8 @@ enum nl80211_commands {

NL80211_CMD_SET_MAC_ACL,

NL80211_CMD_RADAR_DETECT,

/* add new commands above here */

/* used to define NL80211_CMD_MAX below */
Expand Down Expand Up @@ -1342,6 +1352,9 @@ enum nl80211_commands {
* number of MAC addresses that a device can support for MAC
* ACL.
*
* @NL80211_ATTR_RADAR_EVENT: Type of radar event for notification to userspace,
* contains a value of enum nl80211_radar_event (u32).
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
Expand Down Expand Up @@ -1620,6 +1633,8 @@ enum nl80211_attrs {

NL80211_ATTR_MAC_ACL_MAX,

NL80211_ATTR_RADAR_EVENT,

/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
Expand Down Expand Up @@ -2022,6 +2037,10 @@ enum nl80211_band_attr {
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
* (100 * dBm).
* @NL80211_FREQUENCY_ATTR_DFS_STATE: current state for DFS
* (enum nl80211_dfs_state)
* @NL80211_FREQUENCY_ATTR_DFS_TIME: time in miliseconds for how long
* this channel is in this DFS state.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
Expand All @@ -2034,6 +2053,8 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_IBSS,
NL80211_FREQUENCY_ATTR_RADAR,
NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
NL80211_FREQUENCY_ATTR_DFS_STATE,
NL80211_FREQUENCY_ATTR_DFS_TIME,

/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
Expand Down Expand Up @@ -3489,4 +3510,44 @@ enum nl80211_acl_policy {
NL80211_ACL_POLICY_DENY_UNLESS_LISTED,
};

/**
* enum nl80211_radar_event - type of radar event for DFS operation
*
* Type of event to be used with NL80211_ATTR_RADAR_EVENT to inform userspace
* about detected radars or success of the channel available check (CAC)
*
* @NL80211_RADAR_DETECTED: A radar pattern has been detected. The channel is
* now unusable.
* @NL80211_RADAR_CAC_FINISHED: Channel Availability Check has been finished,
* the channel is now available.
* @NL80211_RADAR_CAC_ABORTED: Channel Availability Check has been aborted, no
* change to the channel status.
* @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is
* over, channel becomes usable.
*/
enum nl80211_radar_event {
NL80211_RADAR_DETECTED,
NL80211_RADAR_CAC_FINISHED,
NL80211_RADAR_CAC_ABORTED,
NL80211_RADAR_NOP_FINISHED,
};

/**
* enum nl80211_dfs_state - DFS states for channels
*
* Channel states used by the DFS code.
*
* @IEEE80211_DFS_USABLE: The channel can be used, but channel availability
* check (CAC) must be performed before using it for AP or IBSS.
* @IEEE80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
* is therefore marked as not available.
* @IEEE80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
*/

enum nl80211_dfs_state {
NL80211_DFS_USABLE,
NL80211_DFS_UNAVAILABLE,
NL80211_DFS_AVAILABLE,
};

#endif /* __LINUX_NL80211_H */
129 changes: 127 additions & 2 deletions net/wireless/chan.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,32 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
}
}

static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
{
int width;

switch (c->width) {
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_20_NOHT:
width = 20;
break;
case NL80211_CHAN_WIDTH_40:
width = 40;
break;
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_80:
width = 80;
break;
case NL80211_CHAN_WIDTH_160:
width = 160;
break;
default:
WARN_ON_ONCE(1);
return -1;
}
return width;
}

const struct cfg80211_chan_def *
cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
const struct cfg80211_chan_def *c2)
Expand Down Expand Up @@ -192,6 +218,93 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
}
EXPORT_SYMBOL(cfg80211_chandef_compatible);

static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
u32 bandwidth,
enum nl80211_dfs_state dfs_state)
{
struct ieee80211_channel *c;
u32 freq;

for (freq = center_freq - bandwidth/2 + 10;
freq <= center_freq + bandwidth/2 - 10;
freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
if (!c || !(c->flags & IEEE80211_CHAN_RADAR))
continue;

c->dfs_state = dfs_state;
c->dfs_state_entered = jiffies;
}
}

void cfg80211_set_dfs_state(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef,
enum nl80211_dfs_state dfs_state)
{
int width;

if (WARN_ON(!cfg80211_chandef_valid(chandef)))
return;

width = cfg80211_chandef_get_width(chandef);
if (width < 0)
return;

cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
width, dfs_state);

if (!chandef->center_freq2)
return;
cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
width, dfs_state);
}

static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
u32 center_freq,
u32 bandwidth)
{
struct ieee80211_channel *c;
u32 freq;

for (freq = center_freq - bandwidth/2 + 10;
freq <= center_freq + bandwidth/2 - 10;
freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
if (!c)
return -EINVAL;

if (c->flags & IEEE80211_CHAN_RADAR)
return 1;
}
return 0;
}


int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef)
{
int width;
int r;

if (WARN_ON(!cfg80211_chandef_valid(chandef)))
return -EINVAL;

width = cfg80211_chandef_get_width(chandef);
if (width < 0)
return -EINVAL;

r = cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq1,
width);
if (r)
return r;

if (!chandef->center_freq2)
return 0;

return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2,
width);
}

static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
u32 center_freq, u32 bandwidth,
u32 prohibited_flags)
Expand All @@ -203,7 +316,16 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
freq <= center_freq + bandwidth/2 - 10;
freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
if (!c || c->flags & prohibited_flags)
if (!c)
return false;

/* check for radar flags */
if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) &&
(c->dfs_state != NL80211_DFS_AVAILABLE))
return false;

/* check for the other flags */
if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR)
return false;
}

Expand Down Expand Up @@ -344,7 +466,10 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
if (wdev->beacon_interval) {
if (wdev->cac_started) {
*chan = wdev->channel;
*chanmode = CHAN_MODE_SHARED;
} else if (wdev->beacon_interval) {
*chan = wdev->channel;
*chanmode = CHAN_MODE_SHARED;
}
Expand Down
3 changes: 3 additions & 0 deletions net/wireless/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
INIT_LIST_HEAD(&rdev->bss_list);
INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results);
INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk,
cfg80211_dfs_channels_update_work);
#ifdef CONFIG_CFG80211_WEXT
rdev->wiphy.wext = &cfg80211_wext_handler;
#endif
Expand Down Expand Up @@ -695,6 +697,7 @@ void wiphy_unregister(struct wiphy *wiphy)
flush_work(&rdev->scan_done_wk);
cancel_work_sync(&rdev->conn_work);
flush_work(&rdev->event_work);
cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);

if (rdev->wowlan && rdev->ops->set_wakeup)
rdev_set_wakeup(rdev, false);
Expand Down
Loading

0 comments on commit 04f3904

Please sign in to comment.