Commit 5cdaed1e authored by Johannes Berg's avatar Johannes Berg

mac80211: ignore HT primary channel while connected

While we're connected, the AP shouldn't change the primary channel
in the HT information. We checked this, and dropped the connection
if it did change it.

Unfortunately, this is causing problems on some APs, e.g. on the
Netgear WRT610NL: the beacons seem to always contain a bad channel
and if we made a connection using a probe response (correct data)
we drop the connection immediately and can basically not connect
properly at all.

Work around this by ignoring the HT primary channel information in
beacons if we're already connected.

Also print out more verbose messages in the other situations to
help diagnose similar bugs quicker in the future.

Cc: stable@vger.kernel.org [3.10]
Acked-by: default avatarAndy Isaacson <adi@hexapodia.org>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent cb236d2d
...@@ -211,8 +211,9 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, ...@@ -211,8 +211,9 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel, struct ieee80211_channel *channel,
const struct ieee80211_ht_operation *ht_oper, const struct ieee80211_ht_operation *ht_oper,
const struct ieee80211_vht_operation *vht_oper, const struct ieee80211_vht_operation *vht_oper,
struct cfg80211_chan_def *chandef, bool verbose) struct cfg80211_chan_def *chandef, bool tracking)
{ {
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct cfg80211_chan_def vht_chandef; struct cfg80211_chan_def vht_chandef;
u32 ht_cfreq, ret; u32 ht_cfreq, ret;
...@@ -231,7 +232,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, ...@@ -231,7 +232,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
channel->band); channel->band);
/* check that channel matches the right operating channel */ /* check that channel matches the right operating channel */
if (channel->center_freq != ht_cfreq) { if (!tracking && channel->center_freq != ht_cfreq) {
/* /*
* It's possible that some APs are confused here; * It's possible that some APs are confused here;
* Netgear WNDR3700 sometimes reports 4 higher than * Netgear WNDR3700 sometimes reports 4 higher than
...@@ -239,11 +240,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, ...@@ -239,11 +240,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
* since we look at probe response/beacon data here * since we look at probe response/beacon data here
* it should be OK. * it should be OK.
*/ */
if (verbose) sdata_info(sdata,
sdata_info(sdata, "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
"Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", channel->center_freq, ht_cfreq,
channel->center_freq, ht_cfreq, ht_oper->primary_chan, channel->band);
ht_oper->primary_chan, channel->band);
ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
goto out; goto out;
} }
...@@ -297,7 +297,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, ...@@ -297,7 +297,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
channel->band); channel->band);
break; break;
default: default:
if (verbose) if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
sdata_info(sdata, sdata_info(sdata,
"AP VHT operation IE has invalid channel width (%d), disable VHT\n", "AP VHT operation IE has invalid channel width (%d), disable VHT\n",
vht_oper->chan_width); vht_oper->chan_width);
...@@ -306,7 +306,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, ...@@ -306,7 +306,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
} }
if (!cfg80211_chandef_valid(&vht_chandef)) { if (!cfg80211_chandef_valid(&vht_chandef)) {
if (verbose) if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
sdata_info(sdata, sdata_info(sdata,
"AP VHT information is invalid, disable VHT\n"); "AP VHT information is invalid, disable VHT\n");
ret = IEEE80211_STA_DISABLE_VHT; ret = IEEE80211_STA_DISABLE_VHT;
...@@ -319,7 +319,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, ...@@ -319,7 +319,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
} }
if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) {
if (verbose) if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
sdata_info(sdata, sdata_info(sdata,
"AP VHT information doesn't match HT, disable VHT\n"); "AP VHT information doesn't match HT, disable VHT\n");
ret = IEEE80211_STA_DISABLE_VHT; ret = IEEE80211_STA_DISABLE_VHT;
...@@ -346,7 +346,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, ...@@ -346,7 +346,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
ret |= chandef_downgrade(chandef); ret |= chandef_downgrade(chandef);
} }
if (chandef->width != vht_chandef.width && verbose) if (chandef->width != vht_chandef.width && !tracking)
sdata_info(sdata, sdata_info(sdata,
"capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n"); "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n");
...@@ -386,7 +386,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, ...@@ -386,7 +386,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
/* calculate new channel (type) based on HT/VHT operation IEs */ /* calculate new channel (type) based on HT/VHT operation IEs */
flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper, flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper,
vht_oper, &chandef, false); vht_oper, &chandef, true);
/* /*
* Downgrade the new channel if we associated with restricted * Downgrade the new channel if we associated with restricted
...@@ -3838,7 +3838,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, ...@@ -3838,7 +3838,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
cbss->channel, cbss->channel,
ht_oper, vht_oper, ht_oper, vht_oper,
&chandef, true); &chandef, false);
sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
local->rx_chains); local->rx_chains);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment