* [RFC 0/2] cfg80211/mac80211: help world roaming through beacons reg hints
@ 2009-02-03 5:01 Luis R. Rodriguez
2009-02-03 5:01 ` [RFC 1/2] cfg80211/mac80211: add regulatory_hint_found_beacon() to make help world roaming Luis R. Rodriguez
0 siblings, 1 reply; 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
This adds support to help the wireless core with world roaming
by providing hints to when we receive beacons from APs. Devices
can be world roaming when the world regulatory domain is set or
the device has a custom regulatory domain and no country IEs have
been received.
This should should help users more on 5 GHz which doesn't allow beaconing
or active scanning when world roaming.
We call mac80211's beacon hint from ieee80211_mlme_notify_scan_completed(),
which is called at the end of ieee80211_scan_completed(). This guarantees
that we take advantage of devices which do hw-scanning or sw-scanning.
Review with the locking is appreciated, but I think this is OK.
Luis R. Rodriguez (2):
wireless: add regulatory_hint_found_beacon() to make help world
roaming
ath9k: follow beacon hints on reg_notifier when world roaming
drivers/net/wireless/ath9k/regd.c | 92 ++++++++++++-------
include/net/wireless.h | 20 ++++
net/mac80211/mlme.c | 35 +++++++
net/wireless/reg.c | 181 ++++++++++++++++++++++++++++++++++++-
4 files changed, 295 insertions(+), 33 deletions(-)
^ permalink raw reply [flat|nested] 5+ messages in thread
* [RFC 1/2] cfg80211/mac80211: add regulatory_hint_found_beacon() to make help world roaming
2009-02-03 5:01 [RFC 0/2] cfg80211/mac80211: help world roaming through beacons reg hints Luis R. Rodriguez
@ 2009-02-03 5:01 ` 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 ` [RFC 1/2] cfg80211/mac80211: add regulatory_hint_found_beacon() to make help " Johannes Berg
0 siblings, 2 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
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>
---
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);
}
--
1.6.1.2.253.ga34a
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [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
* Re: [RFC 1/2] cfg80211/mac80211: add regulatory_hint_found_beacon() to make help world roaming
2009-02-03 10:11 ` [RFC 1/2] cfg80211/mac80211: add regulatory_hint_found_beacon() to make help " Johannes Berg
@ 2009-02-03 15:27 ` Luis R. Rodriguez
0 siblings, 0 replies; 5+ messages in thread
From: Luis R. Rodriguez @ 2009-02-03 15:27 UTC (permalink / raw)
To: Johannes Berg; +Cc: linville, linux-wireless
On Tue, Feb 3, 2009 at 2:11 AM, Johannes Berg <johannes@sipsolutions.net> wrote:
> 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.
How's that coming along?
Luis
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-02-03 15:27 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-02-03 5:01 [RFC 0/2] cfg80211/mac80211: help world roaming through beacons reg hints Luis R. Rodriguez
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 ` [RFC 1/2] cfg80211/mac80211: add regulatory_hint_found_beacon() to make help " Johannes Berg
2009-02-03 15:27 ` Luis R. Rodriguez
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox