* [RFC 2/2] ath9k: follow beacon hints on reg_notifier when world roaming
2009-02-03 5:01 ` [RFC 1/2] cfg80211/mac80211: add regulatory_hint_found_beacon() to make help world roaming Luis R. Rodriguez
@ 2009-02-03 5:01 ` Luis R. Rodriguez
2009-02-03 10:11 ` [RFC 1/2] cfg80211/mac80211: add regulatory_hint_found_beacon() to make help " Johannes Berg
1 sibling, 0 replies; 5+ messages in thread
From: Luis R. Rodriguez @ 2009-02-03 5:01 UTC (permalink / raw)
To: johannes, johannes, linville; +Cc: Luis R. Rodriguez, linux-wireless
If we are roaming we allow to follow beacon hints.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
drivers/net/wireless/ath9k/regd.c | 92 ++++++++++++++++++++++++-------------
1 files changed, 60 insertions(+), 32 deletions(-)
diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c
index fe08a4f..f01ca7f 100644
--- a/drivers/net/wireless/ath9k/regd.c
+++ b/drivers/net/wireless/ath9k/regd.c
@@ -161,13 +161,18 @@ static bool ath9k_is_radar_freq(u16 center_freq)
}
/*
- * Enable adhoc on 5 GHz if allowed by 11d.
- * Remove passive scan if channel is allowed by 11d,
- * except when on radar frequencies.
+ * N.B: These exception rules do not apply radar freqs.
+ *
+ * - We enable adhoc (or beaconing) if allowed by 11d
+ * - We enable active scan if the channel is allowed by 11d
+ * - If no country IE has been processed and a we determine we have
+ * received a beacon on a channel we can enable active scan and
+ * adhoc (or beaconing).
*/
-static void ath9k_reg_apply_5ghz_beaconing_flags(struct wiphy *wiphy,
+static void ath9k_reg_apply_beaconing_flags(struct wiphy *wiphy,
enum reg_set_by setby)
{
+ enum ieee80211_band band;
struct ieee80211_supported_band *sband;
const struct ieee80211_reg_rule *reg_rule;
struct ieee80211_channel *ch;
@@ -175,29 +180,49 @@ static void ath9k_reg_apply_5ghz_beaconing_flags(struct wiphy *wiphy,
u32 bandwidth = 0;
int r;
- if (setby != REGDOM_SET_BY_COUNTRY_IE)
- return;
- if (!wiphy->bands[IEEE80211_BAND_5GHZ])
- return;
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
- sband = wiphy->bands[IEEE80211_BAND_5GHZ];
- for (i = 0; i < sband->n_channels; i++) {
- ch = &sband->channels[i];
- r = freq_reg_info(wiphy, ch->center_freq,
- &bandwidth, ®_rule);
- if (r)
+ if (!wiphy->bands[band])
continue;
- /* If 11d had a rule for this channel ensure we enable adhoc
- * if it allows us to use it. Note that we would have disabled
- * it by applying our static world regdomain by default during
- * probe */
- if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
- ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
- if (!ath9k_is_radar_freq(ch->center_freq))
- continue;
- if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
- ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+
+ sband = wiphy->bands[band];
+
+ for (i = 0; i < sband->n_channels; i++) {
+
+ ch = &sband->channels[i];
+
+ if (ath9k_is_radar_freq(ch->center_freq))
+ continue;
+
+ if (setby == REGDOM_SET_BY_COUNTRY_IE) {
+ r = freq_reg_info(wiphy, ch->center_freq,
+ &bandwidth, ®_rule);
+ if (r)
+ continue;
+ /*
+ * If 11d had a rule for this channel ensure
+ * we enable adhoc/beaconing if it allows us to
+ * use it. Note that we would have disabled it
+ * by applying our static world regdomain by
+ * default during init, prior to calling our
+ * regulatory_hint().
+ */
+ if (!(reg_rule->flags &
+ NL80211_RRF_NO_IBSS))
+ ch->flags &=
+ ~IEEE80211_CHAN_NO_IBSS;
+ if (!(reg_rule->flags &
+ NL80211_RRF_PASSIVE_SCAN))
+ ch->flags &=
+ ~IEEE80211_CHAN_PASSIVE_SCAN;
+ } else {
+ if (ch->beacon_found)
+ ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN);
+ }
+ }
}
+
}
/* Allows active scan scan on Ch 12 and 13 */
@@ -210,11 +235,12 @@ static void ath9k_reg_apply_active_scan_flags(struct wiphy *wiphy,
u32 bandwidth = 0;
int r;
- /* Force passive scan on Channels 12-13 */
sband = wiphy->bands[IEEE80211_BAND_2GHZ];
- /* If no country IE has been received always enable active scan
- * on these channels */
+ /*
+ * If no country IE has been received always enable active scan
+ * on these channels. This is only done for specific regulatory SKUs
+ */
if (setby != REGDOM_SET_BY_COUNTRY_IE) {
ch = &sband->channels[11]; /* CH 12 */
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
@@ -225,10 +251,12 @@ static void ath9k_reg_apply_active_scan_flags(struct wiphy *wiphy,
return;
}
- /* If a country IE has been recieved check its rule for this
+ /*
+ * If a country IE has been recieved check its rule for this
* channel first before enabling active scan. The passive scan
- * would have been enforced by the initial probe processing on
- * our custom regulatory domain. */
+ * would have been enforced by the initial processing of our
+ * custom regulatory domain.
+ */
ch = &sband->channels[11]; /* CH 12 */
r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule);
@@ -291,10 +319,10 @@ void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby)
case 0x63:
case 0x66:
case 0x67:
- ath9k_reg_apply_5ghz_beaconing_flags(wiphy, setby);
+ ath9k_reg_apply_beaconing_flags(wiphy, setby);
break;
case 0x68:
- ath9k_reg_apply_5ghz_beaconing_flags(wiphy, setby);
+ ath9k_reg_apply_beaconing_flags(wiphy, setby);
ath9k_reg_apply_active_scan_flags(wiphy, setby);
break;
}
--
1.6.1.2.253.ga34a
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [RFC 1/2] cfg80211/mac80211: add regulatory_hint_found_beacon() to make help world roaming
2009-02-03 5:01 ` [RFC 1/2] cfg80211/mac80211: add regulatory_hint_found_beacon() to make help world roaming Luis R. Rodriguez
2009-02-03 5:01 ` [RFC 2/2] ath9k: follow beacon hints on reg_notifier when " Luis R. Rodriguez
@ 2009-02-03 10:11 ` Johannes Berg
2009-02-03 15:27 ` Luis R. Rodriguez
1 sibling, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2009-02-03 10:11 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linville, linux-wireless
[-- Attachment #1: Type: text/plain, Size: 11708 bytes --]
On Mon, 2009-02-02 at 21:01 -0800, Luis R. Rodriguez wrote:
> This adds some initial intelligence to help world roaming. When we
> are world roaming we have no idea what country we are in yet and
> because of this our regulatory domain will be pretty restrictive.
> Country information elements help and we have code to handle that already,
> however, not many APs enable country IEs. We can help the situation
> by adding checks on ours scans for beacons from APs, if we are world roaming
> and an AP beacon is found on a channel we will make the bet that we can
> also beacon and do active scanning -- when not on radar channels.
>
> Since this goes in as part of cfg80211 all devices present will benefit
> from any device's found beacons, this includes new devices connected or
> when you disconnect and reconnect the same device.
>
> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
NACK. If we do this _after_ cfg80211 scanning it becomes so much
simpler.
> ---
> include/net/wireless.h | 20 +++++
> net/mac80211/mlme.c | 35 +++++++++
> net/wireless/reg.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++-
> 3 files changed, 235 insertions(+), 1 deletions(-)
>
> diff --git a/include/net/wireless.h b/include/net/wireless.h
> index a42c156..74b0352 100644
> --- a/include/net/wireless.h
> +++ b/include/net/wireless.h
> @@ -69,6 +69,9 @@ enum ieee80211_channel_flags {
> * @band: band this channel belongs to.
> * @max_antenna_gain: maximum antenna gain in dBi
> * @max_power: maximum transmission power (in dBm)
> + * @beacon_found: helper to regulatory code to indicate when a beacon
> + * has been found on this channel. Use regulatory_hint_found_beacon()
> + * to enable this, this is is useful only on 5 GHz band.
> * @orig_mag: internal use
> * @orig_mpwr: internal use
> */
> @@ -80,6 +83,7 @@ struct ieee80211_channel {
> u32 flags;
> int max_antenna_gain;
> int max_power;
> + bool beacon_found;
> u32 orig_flags;
> int orig_mag, orig_mpwr;
> };
> @@ -414,6 +418,22 @@ extern void regulatory_hint_11d(struct wiphy *wiphy,
> u8 country_ie_len);
>
> /**
> + * regulatory_hint_found_beacon - hints a beacon was found on a channel
> + * @wiphy: the wireless device where the beacon was found on
> + * @beacon_chan: the channel on which the beacon was found on
> + *
> + * This informs the wireless core that a beacon from an AP was found on
> + * the channel provided. This allows the wireless core to make educated
> + * guesses on regulatory to help with world roaming. This is only used for
> + * world roaming -- when we do not know our current location. This is
> + * only useful on channels 12, 13 and 14 on the 2 GHz band as all other
> + * channels are already enabled by the world regulatory domain; and on
> + * non-radar 5 GHz channels.
> + */
> +extern int regulatory_hint_found_beacon(struct wiphy *wiphy,
> + struct ieee80211_channel *beacon_chan);
> +
> +/**
> * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
> * @wiphy: the wireless device we want to process the regulatory domain on
> * @regd: the custom regulatory domain to use for this wiphy
> diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
> index 9d51e27..45905dc 100644
> --- a/net/mac80211/mlme.c
> +++ b/net/mac80211/mlme.c
> @@ -2717,6 +2717,7 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
> {
> struct ieee80211_sub_if_data *sdata = local->scan_sdata;
> struct ieee80211_if_sta *ifsta;
> + struct ieee80211_bss *bss;
>
> if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) {
> ifsta = &sdata->u.sta;
> @@ -2731,6 +2732,40 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
> list_for_each_entry_rcu(sdata, &local->interfaces, list)
> ieee80211_restart_sta_timer(sdata);
> rcu_read_unlock();
> +
> + /* Send off hints to the wireless core about beacons found */
> + spin_lock_bh(&local->bss_lock);
> +
> + sdata = local->scan_sdata;
> +
> + list_for_each_entry(bss, &local->bss_list, list) {
> + struct wiphy *wiphy;
> + struct ieee80211_supported_band *sband;
> + struct ieee80211_channel *chan;
> + unsigned int i;
> +
> + if (!(bss->capability & WLAN_CAPABILITY_ESS))
> + continue;
> +
> + wiphy = sdata->local->hw.wiphy;
> +
> + if (WARN_ON(!wiphy->bands[bss->band]))
> + continue;
> +
> + sband = wiphy->bands[bss->band];
> +
> + for (i = 0; i < sband->n_channels; i++) {
> + chan = &sband->channels[i];
> +
> + if (chan->center_freq != bss->freq)
> + continue;
> + if (regulatory_hint_found_beacon(wiphy, chan))
> + goto unlock_and_exit;
> + }
> + }
> +
> +unlock_and_exit:
> + spin_unlock_bh(&local->bss_lock);
> }
>
> void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
> diff --git a/net/wireless/reg.c b/net/wireless/reg.c
> index 2323644..656cad7 100644
> --- a/net/wireless/reg.c
> +++ b/net/wireless/reg.c
> @@ -54,6 +54,18 @@ static u32 supported_bandwidths[] = {
> MHZ_TO_KHZ(20),
> };
>
> +/*
> + * This list is used to help regulatory when devices are still
> + * world roaming.
> + */
> +static LIST_HEAD(reg_beacon_list);
> +
> +/* Used to help world roaming, used on found beacons */
> +struct reg_beacon {
> + struct list_head list;
> + struct ieee80211_channel chan;
> +};
> +
> /* Central wireless core regulatory domains, we only need two,
> * the current one and a world regulatory domain in case we have no
> * information to give us an alpha2 */
> @@ -758,6 +770,141 @@ static u32 map_regdom_flags(u32 rd_flags)
> return channel_flags;
> }
>
> +static void handle_reg_beacon(struct wiphy *wiphy,
> + unsigned int chan_idx,
> + struct reg_beacon *reg_beacon)
> +{
> +#ifdef CONFIG_CFG80211_REG_DEBUG
> +#define REG_DEBUG_BEACON_FLAG(desc) \
> + printk(KERN_DEBUG "cfg80211: Enabling " desc " on " \
> + "frequency: %d MHz (Ch %d) on %s\n", \
> + reg_beacon->chan.center_freq, \
> + ieee80211_frequency_to_channel(reg_beacon->chan.center_freq), \
> + wiphy_name(wiphy));
> +#else
> +#define REG_DEBUG_BEACON_FLAG(desc) do {} while (0)
> +#endif
> + struct ieee80211_supported_band *sband;
> + struct ieee80211_channel *chan;
> +
> + sband = wiphy->bands[reg_beacon->chan.band];
> + chan = &sband->channels[chan_idx];
> +
> + if (likely(chan->center_freq != reg_beacon->chan.center_freq))
> + return;
> +
> + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) {
> + chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
> + REG_DEBUG_BEACON_FLAG("active scanning");
> + }
> +
> + if (chan->flags & IEEE80211_CHAN_NO_IBSS) {
> + chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
> + REG_DEBUG_BEACON_FLAG("beaconing");
> + }
> +
> + chan->beacon_found = true;
> +#undef REG_DEBUG_BEACON_FLAG
> +}
> +
> +/*
> + * Called when a scan on a wiphy finds a beacon on
> + * new channel
> + */
> +static void wiphy_update_new_beacon(struct wiphy *wiphy,
> + struct reg_beacon *reg_beacon)
> +{
> + unsigned int i;
> + struct ieee80211_supported_band *sband;
> +
> + if (!wiphy->bands[reg_beacon->chan.band])
> + return;
> +
> + sband = wiphy->bands[reg_beacon->chan.band];
> +
> + for (i = 0; i < sband->n_channels; i++)
> + handle_reg_beacon(wiphy, i, reg_beacon);
> +}
> +
> +/*
> + * Called upon reg changes or a new wiphy is added
> + */
> +static void wiphy_update_beacon_reg(struct wiphy *wiphy)
> +{
> + unsigned int i;
> + struct ieee80211_supported_band *sband;
> + struct reg_beacon *reg_beacon;
> +
> + if (list_empty(®_beacon_list))
> + return;
> +
> + list_for_each_entry(reg_beacon, ®_beacon_list, list) {
> + if (!wiphy->bands[reg_beacon->chan.band])
> + continue;
> + sband = wiphy->bands[reg_beacon->chan.band];
> + for (i = 0; i < sband->n_channels; i++)
> + handle_reg_beacon(wiphy, i, reg_beacon);
> + }
> +}
> +
> +static bool freq_is_chan_12_13_14(u16 freq)
> +{
> + if (freq == ieee80211_channel_to_frequency(12) ||
> + freq == ieee80211_channel_to_frequency(13) ||
> + freq == ieee80211_channel_to_frequency(14))
> + return true;
> + return false;
> +}
> +
> +int regulatory_hint_found_beacon(struct wiphy *wiphy,
> + struct ieee80211_channel *beacon_chan)
> +{
> + struct cfg80211_registered_device *drv;
> + struct reg_beacon *reg_beacon, *beacon;
> +
> + if (beacon_chan->beacon_found ||
> + (beacon_chan->flags & IEEE80211_CHAN_RADAR) ||
> + (beacon_chan->band == IEEE80211_BAND_2GHZ &&
> + !freq_is_chan_12_13_14(beacon_chan->center_freq)))
> + return 0;
> +
> + reg_beacon = kzalloc(sizeof(struct reg_beacon), GFP_KERNEL);
> + if (!reg_beacon)
> + return -ENOMEM;
> +
> +#ifdef CONFIG_CFG80211_REG_DEBUG
> + printk(KERN_DEBUG "cfg80211: Found new beacon on "
> + "frequency: %d MHz (Ch %d) on %s\n",
> + beacon_chan->center_freq,
> + ieee80211_frequency_to_channel(beacon_chan->center_freq),
> + wiphy_name(wiphy));
> +#endif
> + memcpy(®_beacon->chan, beacon_chan,
> + sizeof(struct ieee80211_channel));
> +
> + mutex_lock(&cfg80211_drv_mutex);
> +
> + list_for_each_entry(drv, &cfg80211_drv_list, list)
> + wiphy_update_new_beacon(&drv->wiphy, reg_beacon);
> +
> + /*
> + * If this happens it means our beacon_found flag isn't
> + * working as intended.
> + */
> + list_for_each_entry(beacon, ®_beacon_list, list) {
> + if (WARN_ON(beacon->chan.center_freq ==
> + reg_beacon->chan.center_freq))
> + goto unlock;
> + }
> +
> + list_add_tail(®_beacon->list, ®_beacon_list);
> +
> +unlock:
> + mutex_unlock(&cfg80211_drv_mutex);
> + return 0;
> +}
> +EXPORT_SYMBOL(regulatory_hint_found_beacon);
> +
> static int freq_reg_info_regd(struct wiphy *wiphy,
> u32 center_freq,
> u32 *bandwidth,
> @@ -938,16 +1085,38 @@ static void update_all_wiphy_regulatory(enum reg_set_by setby)
> wiphy_update_regulatory(&drv->wiphy, setby);
> }
>
> +static bool reg_is_world_roaming(struct wiphy *wiphy)
> +{
> + if (is_world_regdom(cfg80211_regdomain->alpha2) ||
> + (wiphy->regd && is_world_regdom(wiphy->regd->alpha2)))
> + return true;
> + if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE &&
> + wiphy->custom_regulatory)
> + return true;
> + return false;
> +}
> +
> +/* Reap the advantages of previously found beacons */
> +static void reg_process_beacons(struct wiphy *wiphy)
> +{
> + if (!reg_is_world_roaming(wiphy))
> + return;
> + wiphy_update_beacon_reg(wiphy);
> +}
> +
> void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
> {
> enum ieee80211_band band;
>
> if (ignore_reg_update(wiphy, setby))
> - return;
> + goto out;
> for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
> if (wiphy->bands[band])
> handle_band(wiphy, band);
> }
> +
> +out:
> + reg_process_beacons(wiphy);
> if (wiphy->reg_notifier)
> wiphy->reg_notifier(wiphy, last_request);
> }
> @@ -1633,6 +1802,8 @@ int regulatory_init(void)
>
> void regulatory_exit(void)
> {
> + struct reg_beacon *reg_beacon, *reg_tmp;
> +
> mutex_lock(&cfg80211_drv_mutex);
>
> reset_regdomains();
> @@ -1644,5 +1815,13 @@ void regulatory_exit(void)
>
> platform_device_unregister(reg_pdev);
>
> + if (!list_empty(®_beacon_list)) {
> + list_for_each_entry_safe(reg_beacon, reg_tmp,
> + ®_beacon_list, list) {
> + list_del(®_beacon->list);
> + kfree(reg_beacon);
> + }
> + }
> +
> mutex_unlock(&cfg80211_drv_mutex);
> }
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread