Commit 6bb7aabf authored by John W. Linville's avatar John W. Linville
parents 8c8d2017 795d855d
...@@ -1057,6 +1057,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) ...@@ -1057,6 +1057,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
if (sdata->wdev.cac_started) {
cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED,
GFP_KERNEL);
}
drv_stop_ap(sdata->local, sdata); drv_stop_ap(sdata->local, sdata);
/* free all potentially still buffered bcast frames */ /* free all potentially still buffered bcast frames */
......
...@@ -1497,10 +1497,11 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, ...@@ -1497,10 +1497,11 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
ieee80211_tx_skb_tid(sdata, skb, 7); ieee80211_tx_skb_tid(sdata, skb, 7);
} }
u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action, u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
struct ieee802_11_elems *elems, struct ieee802_11_elems *elems,
u64 filter, u32 crc); u64 filter, u32 crc);
static inline void ieee802_11_parse_elems(u8 *start, size_t len, bool action, static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
bool action,
struct ieee802_11_elems *elems) struct ieee802_11_elems *elems)
{ {
ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0);
......
...@@ -2522,8 +2522,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ...@@ -2522,8 +2522,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
u16 capab_info, aid; u16 capab_info, aid;
struct ieee802_11_elems elems; struct ieee802_11_elems elems;
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
const struct cfg80211_bss_ies *bss_ies = NULL;
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
u32 changed = 0; u32 changed = 0;
int err; int err;
bool ret;
/* AssocResp and ReassocResp have identical structure */ /* AssocResp and ReassocResp have identical structure */
...@@ -2554,6 +2557,69 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ...@@ -2554,6 +2557,69 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
ifmgd->aid = aid; ifmgd->aid = aid;
/*
* Some APs are erroneously not including some information in their
* (re)association response frames. Try to recover by using the data
* from the beacon or probe response. This seems to afflict mobile
* 2G/3G/4G wifi routers, reported models include the "Onda PN51T",
* "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device.
*/
if ((assoc_data->wmm && !elems.wmm_param) ||
(!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
(!elems.ht_cap_elem || !elems.ht_operation)) ||
(!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
(!elems.vht_cap_elem || !elems.vht_operation))) {
const struct cfg80211_bss_ies *ies;
struct ieee802_11_elems bss_elems;
rcu_read_lock();
ies = rcu_dereference(cbss->ies);
if (ies)
bss_ies = kmemdup(ies, sizeof(*ies) + ies->len,
GFP_ATOMIC);
rcu_read_unlock();
if (!bss_ies)
return false;
ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
false, &bss_elems);
if (assoc_data->wmm &&
!elems.wmm_param && bss_elems.wmm_param) {
elems.wmm_param = bss_elems.wmm_param;
sdata_info(sdata,
"AP bug: WMM param missing from AssocResp\n");
}
/*
* Also check if we requested HT/VHT, otherwise the AP doesn't
* have to include the IEs in the (re)association response.
*/
if (!elems.ht_cap_elem && bss_elems.ht_cap_elem &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
elems.ht_cap_elem = bss_elems.ht_cap_elem;
sdata_info(sdata,
"AP bug: HT capability missing from AssocResp\n");
}
if (!elems.ht_operation && bss_elems.ht_operation &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
elems.ht_operation = bss_elems.ht_operation;
sdata_info(sdata,
"AP bug: HT operation missing from AssocResp\n");
}
if (!elems.vht_cap_elem && bss_elems.vht_cap_elem &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
elems.vht_cap_elem = bss_elems.vht_cap_elem;
sdata_info(sdata,
"AP bug: VHT capa missing from AssocResp\n");
}
if (!elems.vht_operation && bss_elems.vht_operation &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
elems.vht_operation = bss_elems.vht_operation;
sdata_info(sdata,
"AP bug: VHT operation missing from AssocResp\n");
}
}
/* /*
* We previously checked these in the beacon/probe response, so * We previously checked these in the beacon/probe response, so
* they should be present here. This is just a safety net. * they should be present here. This is just a safety net.
...@@ -2561,15 +2627,17 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ...@@ -2561,15 +2627,17 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
(!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) { (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) {
sdata_info(sdata, sdata_info(sdata,
"HT AP is missing WMM params or HT capability/operation in AssocResp\n"); "HT AP is missing WMM params or HT capability/operation\n");
return false; ret = false;
goto out;
} }
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
(!elems.vht_cap_elem || !elems.vht_operation)) { (!elems.vht_cap_elem || !elems.vht_operation)) {
sdata_info(sdata, sdata_info(sdata,
"VHT AP is missing VHT capability/operation in AssocResp\n"); "VHT AP is missing VHT capability/operation\n");
return false; ret = false;
goto out;
} }
mutex_lock(&sdata->local->sta_mtx); mutex_lock(&sdata->local->sta_mtx);
...@@ -2580,7 +2648,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ...@@ -2580,7 +2648,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
sta = sta_info_get(sdata, cbss->bssid); sta = sta_info_get(sdata, cbss->bssid);
if (WARN_ON(!sta)) { if (WARN_ON(!sta)) {
mutex_unlock(&sdata->local->sta_mtx); mutex_unlock(&sdata->local->sta_mtx);
return false; ret = false;
goto out;
} }
sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)];
...@@ -2633,7 +2702,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ...@@ -2633,7 +2702,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
sta->sta.addr); sta->sta.addr);
WARN_ON(__sta_info_destroy(sta)); WARN_ON(__sta_info_destroy(sta));
mutex_unlock(&sdata->local->sta_mtx); mutex_unlock(&sdata->local->sta_mtx);
return false; ret = false;
goto out;
} }
mutex_unlock(&sdata->local->sta_mtx); mutex_unlock(&sdata->local->sta_mtx);
...@@ -2673,7 +2743,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ...@@ -2673,7 +2743,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
ieee80211_sta_reset_beacon_monitor(sdata); ieee80211_sta_reset_beacon_monitor(sdata);
return true; ret = true;
out:
kfree(bss_ies);
return ret;
} }
static enum rx_mgmt_action __must_check static enum rx_mgmt_action __must_check
......
...@@ -615,7 +615,7 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata, ...@@ -615,7 +615,7 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata,
if (rates[i].idx < 0) if (rates[i].idx < 0)
break; break;
rate_idx_match_mask(&rates[i], sband, mask, chan_width, rate_idx_match_mask(&rates[i], sband, chan_width, mask,
mcs_mask); mcs_mask);
} }
} }
......
...@@ -661,12 +661,12 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, ...@@ -661,12 +661,12 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
} }
EXPORT_SYMBOL(ieee80211_queue_delayed_work); EXPORT_SYMBOL(ieee80211_queue_delayed_work);
u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action, u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
struct ieee802_11_elems *elems, struct ieee802_11_elems *elems,
u64 filter, u32 crc) u64 filter, u32 crc)
{ {
size_t left = len; size_t left = len;
u8 *pos = start; const u8 *pos = start;
bool calc_crc = filter != 0; bool calc_crc = filter != 0;
DECLARE_BITMAP(seen_elems, 256); DECLARE_BITMAP(seen_elems, 256);
const u8 *ie; const u8 *ie;
......
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