In order to give the usermode an ability to configure scan channel times, and as it required for the beacon reports in the 802.11k standard. Add to the scan command min/max channel times. Add min/max passive channel times, since a single scan can contain both passive and active channels due to regulatory constraints. Signed-off-by: Victor Goldenshtein <victorg@xxxxxx> --- v4: 1. Use the scan time attributes only if NL80211_FEATURE_SCAN_TIMES is set. 2. Use only a pair of both min and max scan times, otherwise return -EINVAL. 3. Updated documentation for the scan time attributes. include/linux/ieee80211.h | 9 +++++++++ include/linux/nl80211.h | 27 +++++++++++++++++++++++++++ include/net/cfg80211.h | 11 +++++++++++ net/wireless/core.h | 1 + net/wireless/nl80211.c | 32 +++++++++++++++++++++++++++++++- net/wireless/scan.c | 38 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 117 insertions(+), 1 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index ce9af89..9522b7e 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1856,6 +1856,15 @@ static inline unsigned long ieee80211_tu_to_usec(unsigned long tu) } /** + * ieee80211_msec_to_tu - convert milliseconds to time units (TU) + * @msec: the milliseconds + */ +static inline unsigned long ieee80211_msec_to_tu(unsigned long msec) +{ + return msec * 1000 / 1024; +} + +/** * ieee80211_check_tim - check if AID bit is set in TIM * @tim: the TIM IE * @tim_len: length of the TIM IE diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 970afdf..bee74ba 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1224,6 +1224,25 @@ enum nl80211_commands { * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds * or 0 to disable background scan. * + * @NL80211_ATTR_SCAN_MIN_CH_TIME: Minimum active scan time (in msec), + * u32 attribute to setup minimum time to wait on each channel, if received + * at least one probe_resp/beacon during this period will continue waiting + * @NL80211_ATTR_SCAN_MAX_CH_TIME, otherwise will move to next channel. + * @NL80211_ATTR_SCAN_MAX_CH_TIME: Maximum active scan time (in msec), + * u32 attribute to setup maximum time to wait on the channel. + * @NL80211_ATTR_SCAN_PSV_MIN_CH_TIME: Minimum passive scan time (in msec), + * u32 attribute (similar to @NL80211_ATTR_SCAN_MIN_CH_TIME). + * @NL80211_ATTR_SCAN_PSV_MAX_CH_TIME: Maximum passive scan time (in msec), + * u32 attribute (similar to @NL80211_ATTR_SCAN_MAX_CH_TIME). + * Note: + * The above channel time attributes are for the %NL80211_CMD_TRIGGER_SCAN + * command. The attributes are optional, the driver will use default + * channel time values if the attributes are not in use. When using the + * attributes, the driver must support @NL80211_FEATURE_SCAN_TIMES and a + * pair of both min and max scan times must be set, moreover if one of the + * min times will be greater than max or set to zero, -EINVAL will be + * returned. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1475,6 +1494,11 @@ enum nl80211_attrs { NL80211_ATTR_BG_SCAN_PERIOD, + NL80211_ATTR_SCAN_MIN_CH_TIME, + NL80211_ATTR_SCAN_MAX_CH_TIME, + NL80211_ATTR_SCAN_PSV_MIN_CH_TIME, + NL80211_ATTR_SCAN_PSV_MAX_CH_TIME, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2875,11 +2899,14 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates. * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up * the connected inactive stations in AP mode. + * @NL80211_FEATURE_SCAN_TIMES: This driver supports min/max scan times + * configuration for the %NL80211_CMD_TRIGGER_SCAN command. */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, NL80211_FEATURE_HT_IBSS = 1 << 1, NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, + NL80211_FEATURE_SCAN_TIMES = 1 << 3, }; /** diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7319f25..4cc3a69 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -929,6 +929,12 @@ struct cfg80211_ssid { * @dev: the interface * @aborted: (internal) scan request was notified as aborted * @no_cck: used to send probe requests at non CCK rate in 2GHz band + * @min_ch_time: minimum time to wait on each channel for active scans + * @max_ch_time: maximum time to wait on each channel for active scans + * @min_passive_ch_time: minimum time to wait on each channel for passive scans + * @max_passive_ch_time: maximum time to wait on each channel for passive scans + * Note: If the above channel times are not set, the default channel times + * will be used. The channel times are in TUs. */ struct cfg80211_scan_request { struct cfg80211_ssid *ssids; @@ -945,6 +951,11 @@ struct cfg80211_scan_request { bool aborted; bool no_cck; + u32 min_ch_time; + u32 max_ch_time; + u32 min_passive_ch_time; + u32 max_passive_ch_time; + /* keep last */ struct ieee80211_channel *channels[0]; }; diff --git a/net/wireless/core.h b/net/wireless/core.h index 9348a47..95e2107 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -419,6 +419,7 @@ void cfg80211_sme_scan_done(struct net_device *dev); void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); void cfg80211_sme_disassoc(struct net_device *dev, struct cfg80211_internal_bss *bss); +int cfg80211_trigger_scan(struct cfg80211_registered_device *rdev); void __cfg80211_scan_done(struct work_struct *wk); void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); void __cfg80211_sched_scan_results(struct work_struct *wk); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7ae54b8..8dd8979 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -206,6 +206,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, + [NL80211_ATTR_SCAN_MIN_CH_TIME] = { .type = NLA_U32 }, + [NL80211_ATTR_SCAN_MAX_CH_TIME] = { .type = NLA_U32 }, + [NL80211_ATTR_SCAN_PSV_MIN_CH_TIME] = { .type = NLA_U32 }, + [NL80211_ATTR_SCAN_PSV_MAX_CH_TIME] = { .type = NLA_U32 }, }; /* policy for the key attributes */ @@ -4020,6 +4024,32 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) request->ie_len); } + if ((wiphy->features & NL80211_FEATURE_SCAN_TIMES) && + info->attrs[NL80211_ATTR_SCAN_MIN_CH_TIME] && + info->attrs[NL80211_ATTR_SCAN_MAX_CH_TIME]) { + request->min_ch_time = + nla_get_u32(info->attrs[NL80211_ATTR_SCAN_MIN_CH_TIME]); + request->max_ch_time = + nla_get_u32(info->attrs[NL80211_ATTR_SCAN_MAX_CH_TIME]); + if (!request->min_ch_time || !request->max_ch_time || + (request->min_ch_time > request->max_ch_time)) + return -EINVAL; + } + + if ((wiphy->features & NL80211_FEATURE_SCAN_TIMES) && + info->attrs[NL80211_ATTR_SCAN_PSV_MIN_CH_TIME] && + info->attrs[NL80211_ATTR_SCAN_PSV_MAX_CH_TIME]) { + request->min_passive_ch_time = + nla_get_u32(info->attrs[NL80211_ATTR_SCAN_PSV_MIN_CH_TIME]); + request->max_passive_ch_time = + nla_get_u32(info->attrs[NL80211_ATTR_SCAN_PSV_MAX_CH_TIME]); + if (!request->min_passive_ch_time || + !request->max_passive_ch_time || + (request->min_passive_ch_time > + request->max_passive_ch_time)) + return -EINVAL; + } + for (i = 0; i < IEEE80211_NUM_BANDS; i++) if (wiphy->bands[i]) request->rates[i] = @@ -4051,7 +4081,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) request->wiphy = &rdev->wiphy; rdev->scan_req = request; - err = rdev->ops->scan(&rdev->wiphy, dev, request); + err = cfg80211_trigger_scan(rdev); if (!err) { nl80211_send_scan_start(rdev, dev); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index af2b1ca..4229efb 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -20,6 +20,30 @@ #define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ) +#define IEEE80211_CH_TIME_MSEC 30 +#define IEEE80211_PSV_CH_TIME_MSEC 125 + +int cfg80211_trigger_scan(struct cfg80211_registered_device *rdev) +{ + struct cfg80211_scan_request *request; + + ASSERT_RDEV_LOCK(rdev); + + request = rdev->scan_req; + + if (!request) + return -EINVAL; + + if (!request->min_passive_ch_time) + request->min_passive_ch_time = + ieee80211_msec_to_tu(IEEE80211_PSV_CH_TIME_MSEC); + if (!request->min_ch_time) + request->min_ch_time = + ieee80211_msec_to_tu(IEEE80211_CH_TIME_MSEC); + + return rdev->ops->scan(&rdev->wiphy, request->dev, request); +} + void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) { struct cfg80211_scan_request *request; @@ -1023,6 +1047,20 @@ int cfg80211_wext_siwscan(struct net_device *dev, if (wiphy->bands[i]) creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; + if (wreq->min_channel_time) { + creq->min_ch_time = wreq->min_channel_time; + if (wreq->scan_type == IW_SCAN_TYPE_ACTIVE) + creq->min_passive_ch_time = + ieee80211_msec_to_tu(IEEE80211_PSV_CH_TIME_MSEC); + else + creq->min_passive_ch_time = wreq->min_channel_time; + } else { + creq->min_ch_time = + ieee80211_msec_to_tu(IEEE80211_CH_TIME_MSEC); + creq->min_passive_ch_time = + ieee80211_msec_to_tu(IEEE80211_PSV_CH_TIME_MSEC); + } + rdev->scan_req = creq; err = rdev->ops->scan(wiphy, dev, creq); if (err) { -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html