Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 134937
b: refs/heads/master
c: e38f8a7
h: refs/heads/master
i:
  134935: 8c17763
v: v3
  • Loading branch information
Luis R. Rodriguez authored and John W. Linville committed Feb 27, 2009
1 parent ab61d42 commit e1a2776
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3fc71f775af677f640f0f0780b16f1b0958f6d9d
refs/heads/master: e38f8a7a8bebbab9d97f204e2cf05ef58b048a1d
5 changes: 4 additions & 1 deletion trunk/include/net/wireless.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -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;
};
Expand Down Expand Up @@ -425,7 +429,6 @@ extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
extern void regulatory_hint_11d(struct wiphy *wiphy,
u8 *country_ie,
u8 country_ie_len);

/**
* wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
* @wiphy: the wireless device we want to process the regulatory domain on
Expand Down
5 changes: 3 additions & 2 deletions trunk/net/wireless/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ MODULE_DESCRIPTION("wireless configuration support");
LIST_HEAD(cfg80211_drv_list);

/*
* This is used to protect the cfg80211_drv_list, cfg80211_regdomain, and
* the last reguluatory request receipt in regd.c
* This is used to protect the cfg80211_drv_list, cfg80211_regdomain,
* country_ie_regdomain, the reg_beacon_list and the the last regulatory
* request receipt (last_request).
*/
DEFINE_MUTEX(cfg80211_mutex);

Expand Down
224 changes: 223 additions & 1 deletion trunk/net/wireless/reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,22 @@ const struct ieee80211_regdomain *cfg80211_regdomain;
*/
static const struct ieee80211_regdomain *country_ie_regdomain;

/* Used to queue up regulatory hints */
static LIST_HEAD(reg_requests_list);
static spinlock_t reg_requests_lock;

/* Used to queue up beacon hints for review */
static LIST_HEAD(reg_pending_beacons);
static spinlock_t reg_pending_beacons_lock;

/* Used to keep track of processed beacon hints */
static LIST_HEAD(reg_beacon_list);

struct reg_beacon {
struct list_head list;
struct ieee80211_channel chan;
};

/* We keep a static world regulatory domain in case of the absence of CRDA */
static const struct ieee80211_regdomain world_regdom = {
.n_reg_rules = 3,
Expand Down Expand Up @@ -1011,16 +1024,120 @@ static void update_all_wiphy_regulatory(enum reg_set_by setby)
wiphy_update_regulatory(&drv->wiphy, setby);
}

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;

assert_cfg80211_lock();

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;

assert_cfg80211_lock();

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;

assert_cfg80211_lock();

if (list_empty(&reg_beacon_list))
return;

list_for_each_entry(reg_beacon, &reg_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 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);
}
Expand Down Expand Up @@ -1314,6 +1431,7 @@ static int reg_process_hint(struct regulatory_request *reg_request)
return r;
}

/* Processes regulatory hints, this is all the REGDOM_SET_BY_* */
static void reg_process_pending_hints(void)
{
struct regulatory_request *reg_request;
Expand Down Expand Up @@ -1344,9 +1462,44 @@ static void reg_process_pending_hints(void)
spin_unlock(&reg_requests_lock);
}

/* Processes beacon hints -- this has nothing to do with country IEs */
static void reg_process_pending_beacon_hints(void)
{
struct cfg80211_registered_device *drv;
struct reg_beacon *pending_beacon, *tmp;

mutex_lock(&cfg80211_mutex);

/* This goes through the _pending_ beacon list */
spin_lock_bh(&reg_pending_beacons_lock);

if (list_empty(&reg_pending_beacons)) {
spin_unlock_bh(&reg_pending_beacons_lock);
goto out;
}

list_for_each_entry_safe(pending_beacon, tmp,
&reg_pending_beacons, list) {

list_del_init(&pending_beacon->list);

/* Applies the beacon hint to current wiphys */
list_for_each_entry(drv, &cfg80211_drv_list, list)
wiphy_update_new_beacon(&drv->wiphy, pending_beacon);

/* Remembers the beacon hint for new wiphys or reg changes */
list_add_tail(&pending_beacon->list, &reg_beacon_list);
}

spin_unlock_bh(&reg_pending_beacons_lock);
out:
mutex_unlock(&cfg80211_mutex);
}

static void reg_todo(struct work_struct *work)
{
reg_process_pending_hints();
reg_process_pending_beacon_hints();
}

static DECLARE_WORK(reg_work, reg_todo);
Expand Down Expand Up @@ -1587,6 +1740,55 @@ void regulatory_hint_11d(struct wiphy *wiphy,
}
EXPORT_SYMBOL(regulatory_hint_11d);

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,
gfp_t gfp)
{
struct reg_beacon *reg_beacon;

if (likely((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);
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(&reg_beacon->chan, beacon_chan,
sizeof(struct ieee80211_channel));


/*
* Since we can be called from BH or and non-BH context
* we must use spin_lock_bh()
*/
spin_lock_bh(&reg_pending_beacons_lock);
list_add_tail(&reg_beacon->list, &reg_pending_beacons);
spin_unlock_bh(&reg_pending_beacons_lock);

schedule_work(&reg_work);

return 0;
}

static void print_rd_rules(const struct ieee80211_regdomain *rd)
{
unsigned int i;
Expand Down Expand Up @@ -1908,6 +2110,7 @@ int regulatory_init(void)
return PTR_ERR(reg_pdev);

spin_lock_init(&reg_requests_lock);
spin_lock_init(&reg_pending_beacons_lock);

#ifdef CONFIG_WIRELESS_OLD_REGULATORY
cfg80211_regdomain = static_regdom(ieee80211_regdom);
Expand Down Expand Up @@ -1951,6 +2154,7 @@ int regulatory_init(void)
void regulatory_exit(void)
{
struct regulatory_request *reg_request, *tmp;
struct reg_beacon *reg_beacon, *btmp;

cancel_work_sync(&reg_work);

Expand All @@ -1965,6 +2169,24 @@ void regulatory_exit(void)

platform_device_unregister(reg_pdev);

spin_lock_bh(&reg_pending_beacons_lock);
if (!list_empty(&reg_pending_beacons)) {
list_for_each_entry_safe(reg_beacon, btmp,
&reg_pending_beacons, list) {
list_del(&reg_beacon->list);
kfree(reg_beacon);
}
}
spin_unlock_bh(&reg_pending_beacons_lock);

if (!list_empty(&reg_beacon_list)) {
list_for_each_entry_safe(reg_beacon, btmp,
&reg_beacon_list, list) {
list_del(&reg_beacon->list);
kfree(reg_beacon);
}
}

spin_lock(&reg_requests_lock);
if (!list_empty(&reg_requests_list)) {
list_for_each_entry_safe(reg_request, tmp,
Expand Down
21 changes: 21 additions & 0 deletions trunk/net/wireless/reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,25 @@ extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
const char *alpha2, u32 country_ie_checksum,
enum environment_cap country_ie_env);

/**
* 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
* @gfp: context flags
*
* 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 channels
* 1-11 are already enabled by the world regulatory domain; and on
* non-radar 5 GHz channels.
*
* Drivers do not need to call this, cfg80211 will do it for after a scan
* on a newly found BSS.
*/
int regulatory_hint_found_beacon(struct wiphy *wiphy,
struct ieee80211_channel *beacon_chan,
gfp_t gfp);

#endif /* __NET_WIRELESS_REG_H */
3 changes: 3 additions & 0 deletions trunk/net/wireless/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,9 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
if (!res)
return NULL;

if (res->pub.capability & WLAN_CAPABILITY_ESS)
regulatory_hint_found_beacon(wiphy, channel, gfp);

/* cfg80211_bss_update gives us a referenced result */
return &res->pub;
}
Expand Down

0 comments on commit e1a2776

Please sign in to comment.