Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 183659
b: refs/heads/master
c: 84920e3
h: refs/heads/master
i:
  183657: 1d6daed
  183655: b21ce5a
v: v3
  • Loading branch information
Luis R. Rodriguez authored and John W. Linville committed Jan 15, 2010
1 parent 11a49ff commit dce7a55
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 21 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: 93895757df4ebe22c98b9128b98ebf8cec972c60
refs/heads/master: 84920e3e47f654a22b540606fb8c1ab90b870942
74 changes: 54 additions & 20 deletions trunk/net/wireless/reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,34 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
#undef ONE_GHZ_IN_KHZ
}

/*
* This is a work around for sanity checking ieee80211_channel_to_frequency()'s
* work. ieee80211_channel_to_frequency() can for example currently provide a
* 2 GHz channel when in fact a 5 GHz channel was desired. An example would be
* an AP providing channel 8 on a country IE triplet when it sent this on the
* 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz
* channel.
*
* This can be removed once ieee80211_channel_to_frequency() takes in a band.
*/
static bool chan_in_band(int chan, enum ieee80211_band band)
{
int center_freq = ieee80211_channel_to_frequency(chan);

switch (band) {
case IEEE80211_BAND_2GHZ:
if (center_freq <= 2484)
return true;
return false;
case IEEE80211_BAND_5GHZ:
if (center_freq >= 5005)
return true;
return false;
default:
return false;
}
}

/*
* Some APs may send a country IE triplet for each channel they
* support and while this is completely overkill and silly we still
Expand Down Expand Up @@ -532,7 +560,8 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
* Returns 0 if the IE has been found to be invalid in the middle
* somewhere.
*/
static int max_subband_chan(int orig_cur_chan,
static int max_subband_chan(enum ieee80211_band band,
int orig_cur_chan,
int orig_end_channel,
s8 orig_max_power,
u8 **country_ie,
Expand All @@ -541,7 +570,6 @@ static int max_subband_chan(int orig_cur_chan,
u8 *triplets_start = *country_ie;
u8 len_at_triplet = *country_ie_len;
int end_subband_chan = orig_end_channel;
enum ieee80211_band band;

/*
* We'll deal with padding for the caller unless
Expand All @@ -557,17 +585,14 @@ static int max_subband_chan(int orig_cur_chan,
*country_ie += 3;
*country_ie_len -= 3;

if (orig_cur_chan <= 14)
band = IEEE80211_BAND_2GHZ;
else
band = IEEE80211_BAND_5GHZ;
if (!chan_in_band(orig_cur_chan, band))
return 0;

while (*country_ie_len >= 3) {
int end_channel = 0;
struct ieee80211_country_ie_triplet *triplet =
(struct ieee80211_country_ie_triplet *) *country_ie;
int cur_channel = 0, next_expected_chan;
enum ieee80211_band next_band = IEEE80211_BAND_2GHZ;

/* means last triplet is completely unrelated to this one */
if (triplet->ext.reg_extension_id >=
Expand All @@ -592,6 +617,9 @@ static int max_subband_chan(int orig_cur_chan,
if (triplet->chans.first_channel <= end_subband_chan)
return 0;

if (!chan_in_band(triplet->chans.first_channel, band))
return 0;

/* 2 GHz */
if (triplet->chans.first_channel <= 14) {
end_channel = triplet->chans.first_channel +
Expand All @@ -600,14 +628,10 @@ static int max_subband_chan(int orig_cur_chan,
else {
end_channel = triplet->chans.first_channel +
(4 * (triplet->chans.num_channels - 1));
next_band = IEEE80211_BAND_5GHZ;
}

if (band != next_band) {
*country_ie -= 3;
*country_ie_len += 3;
break;
}
if (!chan_in_band(end_channel, band))
return 0;

if (orig_max_power != triplet->chans.max_power) {
*country_ie -= 3;
Expand Down Expand Up @@ -666,6 +690,7 @@ static int max_subband_chan(int orig_cur_chan,
* with our userspace regulatory agent to get lower bounds.
*/
static struct ieee80211_regdomain *country_ie_2_rd(
enum ieee80211_band band,
u8 *country_ie,
u8 country_ie_len,
u32 *checksum)
Expand Down Expand Up @@ -743,8 +768,11 @@ static struct ieee80211_regdomain *country_ie_2_rd(
if (triplet->chans.num_channels == 0)
return NULL;

if (!chan_in_band(triplet->chans.first_channel, band))
return NULL;

/* 2 GHz */
if (triplet->chans.first_channel <= 14)
if (band == IEEE80211_BAND_2GHZ)
end_channel = triplet->chans.first_channel +
triplet->chans.num_channels - 1;
else
Expand All @@ -767,14 +795,18 @@ static struct ieee80211_regdomain *country_ie_2_rd(
* or for whatever reason sends triplets with multiple channels
* separated when in fact they should be together.
*/
end_channel = max_subband_chan(cur_channel,
end_channel = max_subband_chan(band,
cur_channel,
end_channel,
triplet->chans.max_power,
&country_ie,
&country_ie_len);
if (!end_channel)
return NULL;

if (!chan_in_band(end_channel, band))
return NULL;

cur_sub_max_channel = end_channel;

/* Basic sanity check */
Expand Down Expand Up @@ -867,14 +899,15 @@ static struct ieee80211_regdomain *country_ie_2_rd(
reg_rule->flags = flags;

/* 2 GHz */
if (triplet->chans.first_channel <= 14)
if (band == IEEE80211_BAND_2GHZ)
end_channel = triplet->chans.first_channel +
triplet->chans.num_channels -1;
else
end_channel = triplet->chans.first_channel +
(4 * (triplet->chans.num_channels - 1));

end_channel = max_subband_chan(triplet->chans.first_channel,
end_channel = max_subband_chan(band,
triplet->chans.first_channel,
end_channel,
triplet->chans.max_power,
&country_ie,
Expand Down Expand Up @@ -1981,8 +2014,9 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy,
* therefore cannot iterate over the rdev list here.
*/
void regulatory_hint_11d(struct wiphy *wiphy,
u8 *country_ie,
u8 country_ie_len)
enum ieee80211_band band,
u8 *country_ie,
u8 country_ie_len)
{
struct ieee80211_regdomain *rd = NULL;
char alpha2[2];
Expand Down Expand Up @@ -2028,7 +2062,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
wiphy_idx_valid(last_request->wiphy_idx)))
goto out;

rd = country_ie_2_rd(country_ie, country_ie_len, &checksum);
rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum);
if (!rd) {
REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n");
goto out;
Expand Down
11 changes: 11 additions & 0 deletions trunk/net/wireless/reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,25 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
* regulatory_hint_11d - hints a country IE as a regulatory domain
* @wiphy: the wireless device giving the hint (used only for reporting
* conflicts)
* @band: the band on which the country IE was received on. This determines
* the band we'll process the country IE channel triplets for.
* @country_ie: pointer to the country IE
* @country_ie_len: length of the country IE
*
* We will intersect the rd with the what CRDA tells us should apply
* for the alpha2 this country IE belongs to, this prevents APs from
* sending us incorrect or outdated information against a country.
*
* The AP is expected to provide Country IE channel triplets for the
* band it is on. It is technically possible for APs to send channel
* country IE triplets even for channels outside of the band they are
* in but for that they would have to use the regulatory extension
* in combination with a triplet but this behaviour is currently
* not observed. For this reason if a triplet is seen with channel
* information for a band the BSS is not present in it will be ignored.
*/
void regulatory_hint_11d(struct wiphy *wiphy,
enum ieee80211_band band,
u8 *country_ie,
u8 country_ie_len);

Expand Down
1 change: 1 addition & 0 deletions trunk/net/wireless/sme.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
* - and country_ie[1] which is the IE length
*/
regulatory_hint_11d(wdev->wiphy,
bss->channel->band,
country_ie + 2,
country_ie[1]);
}
Expand Down

0 comments on commit dce7a55

Please sign in to comment.