From 3d7ad2f681391157d64636ce364786201b42fe9d Mon Sep 17 00:00:00 2001 From: Chaitanya T K Date: Fri, 21 Feb 2014 14:42:18 +0100 Subject: [PATCH] hostapd: Configure spectrum management capability Add configuration of Spectrum Management subfield in the Capability Information of Beacon, Probe Response, and Association Response frames. Spectrum Management bit is set when directly requested by new configuration option spectrum_mgmt_required=1 or when AP is running on DFS channels. In the future, also TPC shall require this bit to be set. Signed-hostap: Srinivasan Signed-hostap: Chaitanya T K Signed-hostap: Marek Puzyniak --- hostapd/config_file.c | 2 ++ hostapd/hostapd.conf | 7 +++++++ src/ap/ap_config.c | 6 ++++++ src/ap/ap_config.h | 3 +++ src/ap/beacon.c | 41 ++++++++++++++++++++++++++++++++++++++--- src/ap/dfs.c | 20 ++++++++++++++++++++ src/ap/dfs.h | 1 + src/ap/ieee802_11.c | 21 +++++++++++++++++++++ 8 files changed, 98 insertions(+), 3 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 0ec170131..2beb34c05 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2915,6 +2915,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, return 1; } conf->local_pwr_constraint = val; + } else if (os_strcmp(buf, "spectrum_mgmt_required") == 0) { + conf->spectrum_mgmt_required = atoi(pos); } else { wpa_printf(MSG_ERROR, "Line %d: unknown configuration " "item '%s'", line, buf); diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 63232d750..3733a32c4 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -115,6 +115,13 @@ ssid=test # Valid values are 0..255. #local_pwr_constraint=3 +# Set Spectrum Management subfield in the Capability Information field. +# This config option forces the Spectrum Management bit to be set. When this +# option is not set, the value of the Spectrum Management bit depends on whether +# DFS or TPC is required by regulatory authorities. This can be used only with +# ieee80211d=1 and local_pwr_constraint configured. +#spectrum_mgmt_required=1 + # Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g, # ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to # specify band) diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index a9e8bfac1..f5014a5cc 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -837,6 +837,12 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config) return -1; } + if (full_config && conf->spectrum_mgmt_required && + conf->local_pwr_constraint == -1) { + wpa_printf(MSG_ERROR, "Cannot set Spectrum Management bit without Country and Power Constraint elements"); + return -1; + } + for (i = 0; i < conf->num_bss; i++) { if (hostapd_config_check_bss(conf->bss[i], conf, full_config)) return -1; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 26a0ef6c9..eda193b33 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -526,6 +526,9 @@ struct hostapd_config { */ int local_pwr_constraint; + /* Control Spectrum Management bit */ + int spectrum_mgmt_required; + struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES]; /* diff --git a/src/ap/beacon.c b/src/ap/beacon.c index d84af9534..33320bd48 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -27,6 +27,7 @@ #include "ap_drv_ops.h" #include "beacon.h" #include "hs20.h" +#include "dfs.h" #ifdef NEED_AP_MLME @@ -105,12 +106,43 @@ static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid) static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid) { u8 *pos = eid; + u8 local_pwr_constraint = 0; + int dfs; - if (hapd->iconf->local_pwr_constraint == -1 || - hapd->iface->current_mode == NULL || + if (hapd->iface->current_mode == NULL || hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) return eid; + /* + * There is no DFS support and power constraint was not directly + * requested by config option. + */ + if (!hapd->iconf->ieee80211h && + hapd->iconf->local_pwr_constraint == -1) + return eid; + + /* Check if DFS is required by regulatory. */ + dfs = hostapd_is_dfs_required(hapd->iface); + if (dfs < 0) { + wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d", + dfs); + dfs = 0; + } + + if (dfs == 0 && hapd->iconf->local_pwr_constraint == -1) + return eid; + + /* + * ieee80211h (DFS) is enabled so Power Constraint element shall + * be added when running on DFS channel whenever local_pwr_constraint + * is configured or not. In order to meet regulations when TPC is not + * implemented using a transmit power that is below the legal maximum + * (including any mitigation factor) should help. In this case, + * indicate 3 dB below maximum allowed transmit power. + */ + if (hapd->iconf->local_pwr_constraint == -1) + local_pwr_constraint = 3; + /* * A STA that is not an AP shall use a transmit power less than or * equal to the local maximum transmit power level for the channel. @@ -126,7 +158,10 @@ static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid) /* Length */ *pos++ = 1; /* Local Power Constraint */ - *pos++ = hapd->iconf->local_pwr_constraint; + if (local_pwr_constraint) + *pos++ = local_pwr_constraint; + else + *pos++ = hapd->iconf->local_pwr_constraint; return pos; } diff --git a/src/ap/dfs.c b/src/ap/dfs.c index ec691db3a..47e5002a1 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -801,3 +801,23 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); return 0; } + + +int hostapd_is_dfs_required(struct hostapd_iface *iface) +{ + int n_chans, start_chan_idx; + + if (!iface->current_mode) + return -1; + + /* Get start (first) channel for current configuration */ + start_chan_idx = dfs_get_start_chan_idx(iface); + if (start_chan_idx == -1) + return -1; + + /* Get number of used channels, depend on width */ + n_chans = dfs_get_used_n_chans(iface); + + /* Check if any of configured channels require DFS */ + return dfs_check_chans_radar(iface, start_chan_idx, n_chans); +} diff --git a/src/ap/dfs.h b/src/ap/dfs.h index 859ff7915..a619c55c2 100644 --- a/src/ap/dfs.h +++ b/src/ap/dfs.h @@ -21,5 +21,6 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, int ht_enabled, int chan_offset, int chan_width, int cf1, int cf2); +int hostapd_is_dfs_required(struct hostapd_iface *iface); #endif /* DFS_H */ diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 9251ac3a5..f3e0df313 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -38,6 +38,7 @@ #include "ap_drv_ops.h" #include "wnm_ap.h" #include "ieee802_11.h" +#include "dfs.h" u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) @@ -137,6 +138,15 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, { int capab = WLAN_CAPABILITY_ESS; int privacy; + int dfs; + + /* Check if any of configured channels require DFS */ + dfs = hostapd_is_dfs_required(hapd->iface); + if (dfs < 0) { + wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d", + dfs); + dfs = 0; + } if (hapd->iface->num_sta_no_short_preamble == 0 && hapd->iconf->preamble == SHORT_PREAMBLE) @@ -174,6 +184,17 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, hapd->iface->num_sta_no_short_slot_time == 0) capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; + /* + * Currently, Spectrum Management capability bit is set when directly + * requested in configuration by spectrum_mgmt_required or when AP is + * running on DFS channel. + * TODO: Also consider driver support for TPC to set Spectrum Mgmt bit + */ + if (hapd->iface->current_mode && + hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && + (hapd->iconf->spectrum_mgmt_required || dfs)) + capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; + return capab; }