From cca07b00a56d6ddd339e457dfd1a229222b9acf5 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 13 Jun 2014 16:30:05 +0300 Subject: mac80211: introduce refcount for queue_stop_reasons Sometimes different vifs may be stopping the queues for the same reason (e.g. when several interfaces are performing a channel switch). Instead of using a bitmask for the reasons, use an integer that holds a refcount instead. In order to keep it backwards compatible, introduce a boolean in some functions that tell us whether the queue stopping should be refcounted or not. For now, use not refcounted for all calls to keep it functionally the same as before. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'net/mac80211/mlme.c') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3345401be1b3..1ab1884eddbf 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -983,7 +983,8 @@ static void ieee80211_chswitch_work(struct work_struct *work) if (!ieee80211_csa_needs_block_tx(local)) ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); + IEEE80211_QUEUE_STOP_REASON_CSA, + false); mutex_unlock(&local->mtx); ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; @@ -1115,7 +1116,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, if (sdata->csa_block_tx) ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); + IEEE80211_QUEUE_STOP_REASON_CSA, + false); mutex_unlock(&local->mtx); if (local->ops->channel_switch) { @@ -1385,7 +1387,8 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work) ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_PS); + IEEE80211_QUEUE_STOP_REASON_PS, + false); } void ieee80211_dynamic_ps_enable_work(struct work_struct *work) @@ -1833,7 +1836,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, if (!ieee80211_csa_needs_block_tx(local)) ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); + IEEE80211_QUEUE_STOP_REASON_CSA, + false); mutex_unlock(&local->mtx); sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; @@ -2082,7 +2086,8 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) if (!ieee80211_csa_needs_block_tx(local)) ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); + IEEE80211_QUEUE_STOP_REASON_CSA, + false); mutex_unlock(&local->mtx); cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, -- cgit v1.2.3 From a46992b441f097a971cca39f49d07a0d16a1c0d8 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 13 Jun 2014 16:30:07 +0300 Subject: mac80211: stop only the queues assigned to the vif during channel switch Instead of stopping all the hardware queues during channel switch, which is especially bad when we have large CSA counts, stop only the queues that are assigned to the vif that is performing the channel switch. Additionally, check for (sdata->csa_block_tx) instead of calling ieee80211_csa_needs_block_tx(), which can now be removed. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 52 ++++++++++++---------------------------------- net/mac80211/ieee80211_i.h | 1 - net/mac80211/iface.c | 10 ++++----- net/mac80211/mlme.c | 36 +++++++++++++++----------------- 4 files changed, 35 insertions(+), 64 deletions(-) (limited to 'net/mac80211/mlme.c') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e920d48f0209..a0d7a0362f1f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -790,31 +790,6 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, return 0; } -bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local) -{ - struct ieee80211_sub_if_data *sdata; - - lockdep_assert_held(&local->mtx); - - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - - if (!sdata->vif.csa_active) - continue; - - if (!sdata->csa_block_tx) - continue; - - rcu_read_unlock(); - return true; - } - rcu_read_unlock(); - - return false; -} - static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -834,11 +809,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) /* abort any running channel switch */ mutex_lock(&local->mtx); sdata->vif.csa_active = false; - if (!ieee80211_csa_needs_block_tx(local)) - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + if (sdata->csa_block_tx) { + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_block_tx = false; + } + mutex_unlock(&local->mtx); kfree(sdata->u.ap.next_beacon); @@ -2826,11 +2802,11 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) ieee80211_bss_info_change_notify(sdata, changed); cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); - if (!ieee80211_csa_needs_block_tx(local)) - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + if (sdata->csa_block_tx) { + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_block_tx = false; + } return 0; } @@ -3060,10 +3036,8 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, sdata->vif.csa_active = true; if (sdata->csa_block_tx) - ieee80211_stop_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + ieee80211_stop_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); if (changed) { ieee80211_bss_info_change_notify(sdata, changed); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b202df2aebe8..1fd50f173653 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1489,7 +1489,6 @@ void ieee80211_sw_roc_work(struct work_struct *work); void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); /* channel switch handling */ -bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local); void ieee80211_csa_finalize_work(struct work_struct *work); int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_csa_settings *params); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 1971d2418d44..2a12b8aa6aad 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -841,11 +841,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, sdata_lock(sdata); mutex_lock(&local->mtx); sdata->vif.csa_active = false; - if (!ieee80211_csa_needs_block_tx(local)) - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + if (sdata->csa_block_tx) { + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_block_tx = false; + } mutex_unlock(&local->mtx); sdata_unlock(sdata); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1ab1884eddbf..eccc8492a59c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -980,11 +980,11 @@ static void ieee80211_chswitch_work(struct work_struct *work) mutex_lock(&local->mtx); sdata->vif.csa_active = false; /* XXX: wait for a beacon first? */ - if (!ieee80211_csa_needs_block_tx(local)) - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + if (sdata->csa_block_tx) { + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_block_tx = false; + } mutex_unlock(&local->mtx); ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; @@ -1114,10 +1114,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, sdata->csa_block_tx = csa_ie.mode; if (sdata->csa_block_tx) - ieee80211_stop_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + ieee80211_stop_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); mutex_unlock(&local->mtx); if (local->ops->channel_switch) { @@ -1833,11 +1831,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ieee80211_vif_release_channel(sdata); sdata->vif.csa_active = false; - if (!ieee80211_csa_needs_block_tx(local)) - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + if (sdata->csa_block_tx) { + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_block_tx = false; + } mutex_unlock(&local->mtx); sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; @@ -2083,11 +2081,11 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->mtx); sdata->vif.csa_active = false; - if (!ieee80211_csa_needs_block_tx(local)) - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + if (sdata->csa_block_tx) { + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_block_tx = false; + } mutex_unlock(&local->mtx); cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, -- cgit v1.2.3 From 4c3ebc56d7561526524ec62c61aa3e2040b71f6e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 25 Jun 2014 12:35:09 +0200 Subject: mac80211: use chanctx reservation for STA CSA Channel switch finalization is now 2-step. First step is when driver calls chswitch_done(), the other is when reservation is actually finalized (which be defered for in-place reservation). It is now safe to call ieee80211_chswitch_done() more than once. Also remove the ieee80211_vif_change_channel() because it is no longer used. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 69 ++------------------------------ net/mac80211/ieee80211_i.h | 5 --- net/mac80211/mlme.c | 99 ++++++++++++++++++++++++++++++---------------- 3 files changed, 69 insertions(+), 104 deletions(-) (limited to 'net/mac80211/mlme.c') diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index ea4db2f0db87..c3fd4d275bf4 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -819,70 +819,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, return ret; } -static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, - struct ieee80211_chanctx *ctx, - u32 *changed) -{ - struct ieee80211_local *local = sdata->local; - const struct cfg80211_chan_def *chandef = &sdata->csa_chandef; - u32 chanctx_changed = 0; - - if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, - IEEE80211_CHAN_DISABLED)) - return -EINVAL; - - if (ieee80211_chanctx_refcount(local, ctx) != 1) - return -EINVAL; - - if (sdata->vif.bss_conf.chandef.width != chandef->width) { - chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH; - *changed |= BSS_CHANGED_BANDWIDTH; - } - - sdata->vif.bss_conf.chandef = *chandef; - ctx->conf.def = *chandef; - - chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; - drv_change_chanctx(local, ctx, chanctx_changed); - - ieee80211_recalc_chanctx_chantype(local, ctx); - ieee80211_recalc_smps_chanctx(local, ctx); - ieee80211_recalc_radar_chanctx(local, ctx); - ieee80211_recalc_chanctx_min_def(local, ctx); - - return 0; -} - -int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, - u32 *changed) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_chanctx_conf *conf; - struct ieee80211_chanctx *ctx; - int ret; - - lockdep_assert_held(&local->mtx); - - /* should never be called if not performing a channel switch. */ - if (WARN_ON(!sdata->vif.csa_active)) - return -EINVAL; - - mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, - lockdep_is_held(&local->chanctx_mtx)); - if (!conf) { - ret = -EINVAL; - goto out; - } - - ctx = container_of(conf, struct ieee80211_chanctx, conf); - - ret = __ieee80211_vif_change_channel(sdata, ctx, changed); - out: - mutex_unlock(&local->chanctx_mtx); - return ret; -} - static void __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, bool clear) @@ -1066,8 +1002,11 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) ieee80211_queue_work(&sdata->local->hw, &sdata->csa_finalize_work); break; - case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: + ieee80211_queue_work(&sdata->local->hw, + &sdata->u.mgd.chswitch_work); + break; + case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_MONITOR: diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c26955f6c14d..9e025e1184cc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -788,7 +788,6 @@ struct ieee80211_sub_if_data { struct mac80211_qos_map __rcu *qos_map; struct work_struct csa_finalize_work; - bool csa_radar_required; bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ struct cfg80211_chan_def csa_chandef; @@ -1850,10 +1849,6 @@ int __must_check ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, const struct cfg80211_chan_def *chandef, u32 *changed); -/* NOTE: only use ieee80211_vif_change_channel() for channel switch */ -int __must_check -ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, - u32 *changed); void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index eccc8492a59c..931330bbe00c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -940,52 +940,70 @@ static void ieee80211_chswitch_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - u32 changed = 0; int ret; if (!ieee80211_sdata_running(sdata)) return; sdata_lock(sdata); + mutex_lock(&local->mtx); + mutex_lock(&local->chanctx_mtx); + if (!ifmgd->associated) goto out; - mutex_lock(&local->mtx); - ret = ieee80211_vif_change_channel(sdata, &changed); - mutex_unlock(&local->mtx); - if (ret) { + if (!sdata->vif.csa_active) + goto out; + + /* + * using reservation isn't immediate as it may be deferred until later + * with multi-vif. once reservation is complete it will re-schedule the + * work with no reserved_chanctx so verify chandef to check if it + * completed successfully + */ + + if (sdata->reserved_chanctx) { + /* + * with multi-vif csa driver may call ieee80211_csa_finish() + * many times while waiting for other interfaces to use their + * reservations + */ + if (sdata->reserved_ready) + goto out; + + ret = ieee80211_vif_use_reserved_context(sdata); + if (ret) { + sdata_info(sdata, + "failed to use reserved channel context, disconnecting (err=%d)\n", + ret); + ieee80211_queue_work(&sdata->local->hw, + &ifmgd->csa_connection_drop_work); + goto out; + } + + goto out; + } + + if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, + &sdata->csa_chandef)) { sdata_info(sdata, - "vif channel switch failed, disconnecting\n"); + "failed to finalize channel switch, disconnecting\n"); ieee80211_queue_work(&sdata->local->hw, &ifmgd->csa_connection_drop_work); goto out; } - if (!local->use_chanctx) { - local->_oper_chandef = sdata->csa_chandef; - /* Call "hw_config" only if doing sw channel switch. - * Otherwise update the channel directly - */ - if (!local->ops->channel_switch) - ieee80211_hw_config(local, 0); - else - local->hw.conf.chandef = local->_oper_chandef; - } - /* XXX: shouldn't really modify cfg80211-owned data! */ ifmgd->associated->channel = sdata->csa_chandef.chan; - ieee80211_bss_info_change_notify(sdata, changed); - - mutex_lock(&local->mtx); sdata->vif.csa_active = false; + /* XXX: wait for a beacon first? */ if (sdata->csa_block_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); sdata->csa_block_tx = false; } - mutex_unlock(&local->mtx); ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; @@ -993,6 +1011,8 @@ static void ieee80211_chswitch_work(struct work_struct *work) ieee80211_sta_reset_conn_monitor(sdata); out: + mutex_unlock(&local->chanctx_mtx); + mutex_unlock(&local->mtx); sdata_unlock(sdata); } @@ -1029,6 +1049,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct cfg80211_bss *cbss = ifmgd->associated; + struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *chanctx; enum ieee80211_band current_band; struct ieee80211_csa_ie csa_ie; @@ -1072,7 +1093,22 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; + mutex_lock(&local->mtx); mutex_lock(&local->chanctx_mtx); + conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (!conf) { + sdata_info(sdata, + "no channel context assigned to vif?, disconnecting\n"); + ieee80211_queue_work(&local->hw, + &ifmgd->csa_connection_drop_work); + mutex_unlock(&local->chanctx_mtx); + mutex_unlock(&local->mtx); + return; + } + + chanctx = container_of(conf, struct ieee80211_chanctx, conf); + if (local->use_chanctx) { u32 num_chanctx = 0; list_for_each_entry(chanctx, &local->chanctx_list, list) @@ -1085,32 +1121,27 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); mutex_unlock(&local->chanctx_mtx); + mutex_unlock(&local->mtx); return; } } - if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { - ieee80211_queue_work(&local->hw, - &ifmgd->csa_connection_drop_work); - mutex_unlock(&local->chanctx_mtx); - return; - } - chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), - struct ieee80211_chanctx, conf); - if (ieee80211_chanctx_refcount(local, chanctx) > 1) { + res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, + chanctx->mode, false); + if (res) { sdata_info(sdata, - "channel switch with multiple interfaces on the same channel, disconnecting\n"); + "failed to reserve channel context for channel switch, disconnecting (err=%d)\n", + res); ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); mutex_unlock(&local->chanctx_mtx); + mutex_unlock(&local->mtx); return; } mutex_unlock(&local->chanctx_mtx); - sdata->csa_chandef = csa_ie.chandef; - - mutex_lock(&local->mtx); sdata->vif.csa_active = true; + sdata->csa_chandef = csa_ie.chandef; sdata->csa_block_tx = csa_ie.mode; if (sdata->csa_block_tx) -- cgit v1.2.3 From 40b861a0eeb06bbfa472b456482ebf89b6886926 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:23 +0300 Subject: mac80211: add QoS IE during TDLS setup start If QoS is supported by the card, add an appropriate IE to TDLS setup- request and setup-response frames. Consolidate the setting of the WMM info IE across mac80211. Signed-off-by: Arik Nemtsov Reviewed-by: Liad Kaufman Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 13 ++----------- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 11 +---------- net/mac80211/tdls.c | 7 +++++++ net/mac80211/util.c | 15 +++++++++++++++ 5 files changed, 26 insertions(+), 21 deletions(-) (limited to 'net/mac80211/mlme.c') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 713485f9effc..9713dc54ea4b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -189,17 +189,8 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, chandef, 0); } - if (local->hw.queues >= IEEE80211_NUM_ACS) { - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = 7; /* len */ - *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ - *pos++ = 0x50; - *pos++ = 0xf2; - *pos++ = 2; /* WME */ - *pos++ = 0; /* WME info */ - *pos++ = 1; /* WME ver */ - *pos++ = 0; /* U-APSD no in use */ - } + if (local->hw.queues >= IEEE80211_NUM_ACS) + pos = ieee80211_add_wmm_info_ie(pos, 0); /* U-APSD not in use */ presp->head_len = pos - presp->head; if (WARN_ON(presp->head_len > frame_len)) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9e025e1184cc..cb874760e99f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1824,6 +1824,7 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, bool need_basic, enum ieee80211_band band); +u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo); /* channel management */ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 931330bbe00c..d863ff8b6e41 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -830,16 +830,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) qos_info = 0; } - pos = skb_put(skb, 9); - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = 7; /* len */ - *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ - *pos++ = 0x50; - *pos++ = 0xf2; - *pos++ = 2; /* WME */ - *pos++ = 0; /* WME info */ - *pos++ = 1; /* WME ver */ - *pos++ = qos_info; + pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info); } /* add any remaining custom (i.e. vendor specific here) IEs */ diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 398a41302972..bfd8fc4a6b2f 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -100,6 +100,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, const u8 *extra_ies, size_t extra_ies_len) { enum ieee80211_band band = ieee80211_get_sdata_band(sdata); + struct ieee80211_local *local = sdata->local; size_t offset = 0, noffset; u8 *pos; @@ -126,6 +127,11 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, ieee80211_tdls_add_ext_capab(skb); + /* add the QoS element if we support it */ + if (local->hw.queues >= IEEE80211_NUM_ACS && + action_code != WLAN_PUB_ACTION_TDLS_DISCOVER_RES) + ieee80211_add_wmm_info_ie(skb_put(skb, 9), 0); /* no U-APSD */ + /* add any custom IEs that go before HT capabilities */ if (extra_ies_len) { static const u8 before_ht_cap[] = { @@ -310,6 +316,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, sizeof(struct ieee80211_tdls_data)) + 50 + /* supported rates */ 7 + /* ext capab */ + 26 + /* max(WMM-info, WMM-param) */ extra_ies_len + sizeof(struct ieee80211_tdls_lnkie)); if (!skb) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ea79668c2e5f..08ce77664082 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3082,3 +3082,18 @@ int ieee80211_max_num_channels(struct ieee80211_local *local) return max_num_different_channels; } + +u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo) +{ + *buf++ = WLAN_EID_VENDOR_SPECIFIC; + *buf++ = 7; /* len */ + *buf++ = 0x00; /* Microsoft OUI 00:50:F2 */ + *buf++ = 0x50; + *buf++ = 0xf2; + *buf++ = 2; /* WME */ + *buf++ = 0; /* WME info */ + *buf++ = 1; /* WME ver */ + *buf++ = qosinfo; /* U-APSD no in use */ + + return buf; +} -- cgit v1.2.3 From 81dd2b8822410e56048b927be779d95a2b6dc186 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:25 +0300 Subject: mac80211: move TDLS data to mgd private part We can only be a station for TDLS connections. Also fix a bug where a delayed work could be left scheduled if the station interface was brought down during TDLS setup. Signed-off-by: Arik Nemtsov Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 6 +++--- net/mac80211/iface.c | 2 -- net/mac80211/mlme.c | 3 +++ net/mac80211/tdls.c | 28 ++++++++++++++-------------- 4 files changed, 20 insertions(+), 19 deletions(-) (limited to 'net/mac80211/mlme.c') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cb874760e99f..0d8539caebca 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -503,6 +503,9 @@ struct ieee80211_if_managed { struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ + + u8 tdls_peer[ETH_ALEN] __aligned(2); + struct delayed_work tdls_peer_del_work; }; struct ieee80211_if_ibss { @@ -815,9 +818,6 @@ struct ieee80211_sub_if_data { bool radar_required; struct delayed_work dfs_cac_timer_work; - u8 tdls_peer[ETH_ALEN] __aligned(2); - struct delayed_work tdls_peer_del_work; - /* * AP this belongs to: self in AP mode and * corresponding AP in VLAN mode, NULL for diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bbf51b2f0651..2a12b8aa6aad 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1672,8 +1672,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, ieee80211_dfs_cac_timer_work); INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, ieee80211_delayed_tailroom_dec); - INIT_DELAYED_WORK(&sdata->tdls_peer_del_work, - ieee80211_tdls_peer_del_work); for (i = 0; i < IEEE80211_NUM_BANDS; i++) { struct ieee80211_supported_band *sband; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d863ff8b6e41..fcc074871d51 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3713,6 +3713,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) INIT_WORK(&ifmgd->csa_connection_drop_work, ieee80211_csa_connection_drop_work); INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work); + INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work, + ieee80211_tdls_peer_del_work); setup_timer(&ifmgd->timer, ieee80211_sta_timer, (unsigned long) sdata); setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, @@ -4576,6 +4578,7 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) cancel_work_sync(&ifmgd->request_smps_work); cancel_work_sync(&ifmgd->csa_connection_drop_work); cancel_work_sync(&ifmgd->chswitch_work); + cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work); sdata_lock(sdata); if (ifmgd->assoc_data) { diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 72eebea7e60a..c59b8f460eb9 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -22,14 +22,14 @@ void ieee80211_tdls_peer_del_work(struct work_struct *wk) struct ieee80211_local *local; sdata = container_of(wk, struct ieee80211_sub_if_data, - tdls_peer_del_work.work); + u.mgd.tdls_peer_del_work.work); local = sdata->local; mutex_lock(&local->mtx); - if (!is_zero_ether_addr(sdata->tdls_peer)) { - tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->tdls_peer); - sta_info_destroy_addr(sdata, sdata->tdls_peer); - eth_zero_addr(sdata->tdls_peer); + if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer)) { + tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->u.mgd.tdls_peer); + sta_info_destroy_addr(sdata, sdata->u.mgd.tdls_peer); + eth_zero_addr(sdata->u.mgd.tdls_peer); } mutex_unlock(&local->mtx); } @@ -561,8 +561,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, mutex_lock(&local->mtx); /* we don't support concurrent TDLS peer setups */ - if (!is_zero_ether_addr(sdata->tdls_peer) && - !ether_addr_equal(sdata->tdls_peer, peer)) { + if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer) && + !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { ret = -EBUSY; goto exit; } @@ -593,9 +593,9 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, if (ret < 0) goto exit; - memcpy(sdata->tdls_peer, peer, ETH_ALEN); + memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN); ieee80211_queue_delayed_work(&sdata->local->hw, - &sdata->tdls_peer_del_work, + &sdata->u.mgd.tdls_peer_del_work, TDLS_PEER_SETUP_TIMEOUT); exit: @@ -751,8 +751,8 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); rcu_read_unlock(); - WARN_ON_ONCE(is_zero_ether_addr(sdata->tdls_peer) || - !ether_addr_equal(sdata->tdls_peer, peer)); + WARN_ON_ONCE(is_zero_ether_addr(sdata->u.mgd.tdls_peer) || + !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)); ret = 0; break; case NL80211_TDLS_DISABLE_LINK: @@ -766,9 +766,9 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, break; } - if (ret == 0 && ether_addr_equal(sdata->tdls_peer, peer)) { - cancel_delayed_work(&sdata->tdls_peer_del_work); - eth_zero_addr(sdata->tdls_peer); + if (ret == 0 && ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { + cancel_delayed_work(&sdata->u.mgd.tdls_peer_del_work); + eth_zero_addr(sdata->u.mgd.tdls_peer); } mutex_unlock(&local->mtx); -- cgit v1.2.3 From 3e2a0226c624066943259eaa5e1261da9d8a25fc Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Sat, 5 Jul 2014 11:43:01 +0300 Subject: mac80211: remove redundant IEEE80211_STA_CSA_RECEIVED flag The csa_active flag was added in sdata a while ago and made IEEE80211_STA_CSA_RECEIVED redundant. The new flag is also used to mark when CSA is ongoing on other iftypes and took over the old one as the preferred method for checking whether we're in the middle of a channel switch. Remove the old, redundant flag. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 - net/mac80211/mlme.c | 8 +------- 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'net/mac80211/mlme.c') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0d8539caebca..49731dd044bb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -345,7 +345,6 @@ enum ieee80211_sta_flags { IEEE80211_STA_CONNECTION_POLL = BIT(1), IEEE80211_STA_CONTROL_PORT = BIT(2), IEEE80211_STA_DISABLE_HT = BIT(4), - IEEE80211_STA_CSA_RECEIVED = BIT(5), IEEE80211_STA_MFP_ENABLED = BIT(6), IEEE80211_STA_UAPSD_ENABLED = BIT(7), IEEE80211_STA_NULLFUNC_ACKED = BIT(8), diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fcc074871d51..31a8afaf7332 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -996,8 +996,6 @@ static void ieee80211_chswitch_work(struct work_struct *work) sdata->csa_block_tx = false; } - ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; - ieee80211_sta_reset_beacon_monitor(sdata); ieee80211_sta_reset_conn_monitor(sdata); @@ -1055,7 +1053,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, return; /* disregard subsequent announcements if we are already processing */ - if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) + if (sdata->vif.csa_active) return; current_band = cbss->channel->band; @@ -1082,8 +1080,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, return; } - ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; - mutex_lock(&local->mtx); mutex_lock(&local->chanctx_mtx); conf = rcu_dereference_protected(sdata->vif.chanctx_conf, @@ -2099,8 +2095,6 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, true, frame_buf); - ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; - mutex_lock(&local->mtx); sdata->vif.csa_active = false; if (sdata->csa_block_tx) { -- cgit v1.2.3 From bb512ad0732232f1d2693bb68f31a76bed8f22ae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Aug 2014 12:08:09 +0200 Subject: Revert "mac80211: disable uAPSD if all ACs are under ACM" This reverts commit 24aa11ab8ae03292d38ec0dbd9bc2ac49fe8a6dd. That commit was wrong since it uses data that hasn't even been set up yet, but might be a hold-over from a previous connection. Additionally, it seems like a driver-specific workaround that shouldn't have been in mac80211 to start with. Cc: stable@vger.kernel.org Fixes: 24aa11ab8ae0 ("mac80211: disable uAPSD if all ACs are under ACM") Reviewed-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/mac80211/mlme.c') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 31a8afaf7332..b82a12a9f0f1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4376,8 +4376,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); if (bss->wmm_used && bss->uapsd_supported && - (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) && - sdata->wmm_acm != 0xff) { + (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { assoc_data->uapsd = true; ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; } else { -- cgit v1.2.3