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@xxxxxxxxxxx> 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:
signature.asc
Description: This is a digitally signed message part