Commit e3c9b1ef authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-davem-2015-12-02' of...

Merge tag 'mac80211-for-davem-2015-12-02' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211

Johannes Berg says:

====================
A small set of fixes for 4.4:
 * fix scanning in mac80211 to not actively scan radar
   channels (from Antonio)
 * fix uninitialized variable in remain-on-channel that
   could lead to treating frame TX as remain-on-channel
   and not sending the frame at all
 * remove NL80211_FEATURE_FULL_AP_CLIENT_STATE again, it
   was broken and needs more work, we'll enable it later
 * fix call_rcu() induced use-after-reset/free in mesh
   (that was suddenly causing issues in certain tests)
 * always request block-ack window size 64 as we found
   some APs will otherwise crash (really ...)
 * fix P2P-Device teardown sequence to avoid restarting
   with uninitialized data
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cf18b778 c1df932c
...@@ -2003,8 +2003,10 @@ enum ieee80211_hw_flags { ...@@ -2003,8 +2003,10 @@ enum ieee80211_hw_flags {
* it shouldn't be set. * it shouldn't be set.
* *
* @max_tx_aggregation_subframes: maximum number of subframes in an * @max_tx_aggregation_subframes: maximum number of subframes in an
* aggregate an HT driver will transmit, used by the peer as a * aggregate an HT driver will transmit. Though ADDBA will advertise
* hint to size its reorder buffer. * a constant value of 64 as some older APs can crash if the window
* size is smaller (an example is LinkSys WRT120N with FW v1.0.07
* build 002 Jun 18 2012).
* *
* @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX
* (if %IEEE80211_HW_QUEUE_CONTROL is set) * (if %IEEE80211_HW_QUEUE_CONTROL is set)
......
...@@ -500,7 +500,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) ...@@ -500,7 +500,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
/* send AddBA request */ /* send AddBA request */
ieee80211_send_addba_request(sdata, sta->sta.addr, tid, ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
tid_tx->dialog_token, start_seq_num, tid_tx->dialog_token, start_seq_num,
local->hw.max_tx_aggregation_subframes, IEEE80211_MAX_AMPDU_BUF,
tid_tx->timeout); tid_tx->timeout);
} }
...@@ -926,6 +926,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, ...@@ -926,6 +926,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK; amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK;
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes);
mutex_lock(&sta->ampdu_mlme.mtx); mutex_lock(&sta->ampdu_mlme.mtx);
......
...@@ -3454,8 +3454,12 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, ...@@ -3454,8 +3454,12 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
goto out_unlock; goto out_unlock;
} }
} else { } else {
/* for cookie below */ /* Assign a dummy non-zero cookie, it's not sent to
ack_skb = skb; * userspace in this case but we rely on its value
* internally in the need_offchan case to distinguish
* mgmt-tx from remain-on-channel.
*/
*cookie = 0xffffffff;
} }
if (!need_offchan) { if (!need_offchan) {
......
...@@ -76,7 +76,8 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) ...@@ -76,7 +76,8 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata, void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
bool update_bss) bool update_bss)
{ {
if (__ieee80211_recalc_txpower(sdata) || update_bss) if (__ieee80211_recalc_txpower(sdata) ||
(update_bss && ieee80211_sdata_running(sdata)))
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
} }
...@@ -1861,6 +1862,7 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) ...@@ -1861,6 +1862,7 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
unregister_netdevice(sdata->dev); unregister_netdevice(sdata->dev);
} else { } else {
cfg80211_unregister_wdev(&sdata->wdev); cfg80211_unregister_wdev(&sdata->wdev);
ieee80211_teardown_sdata(sdata);
kfree(sdata); kfree(sdata);
} }
} }
...@@ -1870,7 +1872,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata) ...@@ -1870,7 +1872,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata)
if (WARN_ON_ONCE(!test_bit(SDATA_STATE_RUNNING, &sdata->state))) if (WARN_ON_ONCE(!test_bit(SDATA_STATE_RUNNING, &sdata->state)))
return; return;
ieee80211_do_stop(sdata, true); ieee80211_do_stop(sdata, true);
ieee80211_teardown_sdata(sdata);
} }
void ieee80211_remove_interfaces(struct ieee80211_local *local) void ieee80211_remove_interfaces(struct ieee80211_local *local)
......
...@@ -541,8 +541,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, ...@@ -541,8 +541,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
NL80211_FEATURE_HT_IBSS | NL80211_FEATURE_HT_IBSS |
NL80211_FEATURE_VIF_TXPOWER | NL80211_FEATURE_VIF_TXPOWER |
NL80211_FEATURE_MAC_ON_CREATE | NL80211_FEATURE_MAC_ON_CREATE |
NL80211_FEATURE_USERSPACE_MPM | NL80211_FEATURE_USERSPACE_MPM;
NL80211_FEATURE_FULL_AP_CLIENT_STATE;
if (!ops->hw_scan) if (!ops->hw_scan)
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
......
...@@ -779,10 +779,8 @@ void mesh_plink_broken(struct sta_info *sta) ...@@ -779,10 +779,8 @@ void mesh_plink_broken(struct sta_info *sta)
static void mesh_path_node_reclaim(struct rcu_head *rp) static void mesh_path_node_reclaim(struct rcu_head *rp)
{ {
struct mpath_node *node = container_of(rp, struct mpath_node, rcu); struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
struct ieee80211_sub_if_data *sdata = node->mpath->sdata;
del_timer_sync(&node->mpath->timer); del_timer_sync(&node->mpath->timer);
atomic_dec(&sdata->u.mesh.mpaths);
kfree(node->mpath); kfree(node->mpath);
kfree(node); kfree(node);
} }
...@@ -790,8 +788,9 @@ static void mesh_path_node_reclaim(struct rcu_head *rp) ...@@ -790,8 +788,9 @@ static void mesh_path_node_reclaim(struct rcu_head *rp)
/* needs to be called with the corresponding hashwlock taken */ /* needs to be called with the corresponding hashwlock taken */
static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node) static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node)
{ {
struct mesh_path *mpath; struct mesh_path *mpath = node->mpath;
mpath = node->mpath; struct ieee80211_sub_if_data *sdata = node->mpath->sdata;
spin_lock(&mpath->state_lock); spin_lock(&mpath->state_lock);
mpath->flags |= MESH_PATH_RESOLVING; mpath->flags |= MESH_PATH_RESOLVING;
if (mpath->is_gate) if (mpath->is_gate)
...@@ -799,6 +798,7 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node) ...@@ -799,6 +798,7 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node)
hlist_del_rcu(&node->list); hlist_del_rcu(&node->list);
call_rcu(&node->rcu, mesh_path_node_reclaim); call_rcu(&node->rcu, mesh_path_node_reclaim);
spin_unlock(&mpath->state_lock); spin_unlock(&mpath->state_lock);
atomic_dec(&sdata->u.mesh.mpaths);
atomic_dec(&tbl->entries); atomic_dec(&tbl->entries);
} }
......
...@@ -597,8 +597,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ...@@ -597,8 +597,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
/* We need to ensure power level is at max for scanning. */ /* We need to ensure power level is at max for scanning. */
ieee80211_hw_config(local, 0); ieee80211_hw_config(local, 0);
if ((req->channels[0]->flags & if ((req->channels[0]->flags & (IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_NO_IR) || IEEE80211_CHAN_RADAR)) ||
!req->n_ssids) { !req->n_ssids) {
next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
} else { } else {
...@@ -645,7 +645,7 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan) ...@@ -645,7 +645,7 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
* TODO: channel switching also consumes quite some time, * TODO: channel switching also consumes quite some time,
* add that delay as well to get a better estimation * add that delay as well to get a better estimation
*/ */
if (chan->flags & IEEE80211_CHAN_NO_IR) if (chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))
return IEEE80211_PASSIVE_CHANNEL_TIME; return IEEE80211_PASSIVE_CHANNEL_TIME;
return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
} }
...@@ -777,7 +777,8 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, ...@@ -777,7 +777,8 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
* *
* In any case, it is not necessary for a passive scan. * In any case, it is not necessary for a passive scan.
*/ */
if (chan->flags & IEEE80211_CHAN_NO_IR || !scan_req->n_ssids) { if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) ||
!scan_req->n_ssids) {
*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
local->next_scan_state = SCAN_DECISION; local->next_scan_state = SCAN_DECISION;
return; return;
......
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