summaryrefslogtreecommitdiffstats
path: root/package/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'package/kernel')
-rw-r--r--package/kernel/mac80211/patches/300-pending_work.patch591
-rw-r--r--package/kernel/mac80211/patches/310-ap_scan.patch2
-rw-r--r--package/kernel/mac80211/patches/520-mac80211_cur_txpower.patch2
-rw-r--r--package/kernel/mac80211/patches/523-mac80211_configure_antenna_gain.patch20
4 files changed, 584 insertions, 31 deletions
diff --git a/package/kernel/mac80211/patches/300-pending_work.patch b/package/kernel/mac80211/patches/300-pending_work.patch
index 962c5e848b..951fe90d05 100644
--- a/package/kernel/mac80211/patches/300-pending_work.patch
+++ b/package/kernel/mac80211/patches/300-pending_work.patch
@@ -2967,28 +2967,42 @@
enum nl80211_radar_event event, gfp_t gfp);
+@@ -4282,7 +4283,8 @@ bool cfg80211_reg_can_beacon(struct wiph
+ * @dev: the device which switched channels
+ * @chandef: the new channel definition
+ *
+- * Acquires wdev_lock, so must only be called from sleepable driver context!
++ * Caller must acquire wdev_lock, therefore must only be called from sleepable
++ * driver context!
+ */
+ void cfg80211_ch_switch_notify(struct net_device *dev,
+ struct cfg80211_chan_def *chandef);
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
-@@ -1508,6 +1508,9 @@ enum nl80211_commands {
+@@ -1508,6 +1508,12 @@ enum nl80211_commands {
* to react to radar events, e.g. initiate a channel switch or leave the
* IBSS network.
*
-+ * @NL80211_ATTR_SUPPORT_5_10_MHZ: A flag indicating that the device supports
-+ * 5 MHz and 10 MHz channel bandwidth.
++ * @NL80211_ATTR_SUPPORT_5_MHZ: A flag indicating that the device supports
++ * 5 MHz channel bandwidth.
++ *
++ * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports
++ * 10 MHz channel bandwidth.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
-@@ -1824,6 +1827,8 @@ enum nl80211_attrs {
+@@ -1824,6 +1830,9 @@ enum nl80211_attrs {
NL80211_ATTR_HANDLE_DFS,
-+ NL80211_ATTR_SUPPORT_5_10_MHZ,
++ NL80211_ATTR_SUPPORT_5_MHZ,
++ NL80211_ATTR_SUPPORT_10_MHZ,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
-@@ -2224,10 +2229,9 @@ enum nl80211_band_attr {
+@@ -2224,10 +2233,9 @@ enum nl80211_band_attr {
* @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
* @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
* regulatory domain.
@@ -3002,7 +3016,7 @@
* @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
-@@ -2254,8 +2258,8 @@ enum nl80211_frequency_attr {
+@@ -2254,8 +2262,8 @@ enum nl80211_frequency_attr {
__NL80211_FREQUENCY_ATTR_INVALID,
NL80211_FREQUENCY_ATTR_FREQ,
NL80211_FREQUENCY_ATTR_DISABLED,
@@ -3013,7 +3027,7 @@
NL80211_FREQUENCY_ATTR_RADAR,
NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
NL80211_FREQUENCY_ATTR_DFS_STATE,
-@@ -2271,6 +2275,9 @@ enum nl80211_frequency_attr {
+@@ -2271,6 +2279,9 @@ enum nl80211_frequency_attr {
};
#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
@@ -3023,7 +3037,7 @@
/**
* enum nl80211_bitrate_attr - bitrate attributes
-@@ -2413,8 +2420,9 @@ enum nl80211_sched_scan_match_attr {
+@@ -2413,8 +2424,9 @@ enum nl80211_sched_scan_match_attr {
* @NL80211_RRF_DFS: DFS support is required to be used
* @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
* @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
@@ -3035,7 +3049,7 @@
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
-@@ -2424,10 +2432,17 @@ enum nl80211_reg_rule_flags {
+@@ -2424,10 +2436,17 @@ enum nl80211_reg_rule_flags {
NL80211_RRF_DFS = 1<<4,
NL80211_RRF_PTP_ONLY = 1<<5,
NL80211_RRF_PTMP_ONLY = 1<<6,
@@ -3057,15 +3071,76 @@
*
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -1050,6 +1050,7 @@ static int ieee80211_stop_ap(struct wiph
+@@ -846,7 +846,7 @@ static int ieee80211_set_probe_resp(stru
+ if (!resp || !resp_len)
+ return 1;
+
+- old = rtnl_dereference(sdata->u.ap.probe_resp);
++ old = sdata_dereference(sdata->u.ap.probe_resp, sdata);
+
+ new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL);
+ if (!new)
+@@ -870,7 +870,8 @@ int ieee80211_assign_beacon(struct ieee8
+ int size, err;
+ u32 changed = BSS_CHANGED_BEACON;
+
+- old = rtnl_dereference(sdata->u.ap.beacon);
++ old = sdata_dereference(sdata->u.ap.beacon, sdata);
++
+
+ /* Need to have a beacon head if we don't have one yet */
+ if (!params->head && !old)
+@@ -947,7 +948,7 @@ static int ieee80211_start_ap(struct wip
+ BSS_CHANGED_P2P_PS;
+ int err;
+
+- old = rtnl_dereference(sdata->u.ap.beacon);
++ old = sdata_dereference(sdata->u.ap.beacon, sdata);
+ if (old)
+ return -EALREADY;
+
+@@ -1001,7 +1002,8 @@ static int ieee80211_start_ap(struct wip
+
+ err = drv_start_ap(sdata->local, sdata);
+ if (err) {
+- old = rtnl_dereference(sdata->u.ap.beacon);
++ old = sdata_dereference(sdata->u.ap.beacon, sdata);
++
+ if (old)
+ kfree_rcu(old, rcu_head);
+ RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
+@@ -1032,7 +1034,7 @@ static int ieee80211_change_beacon(struc
+ if (sdata->vif.csa_active)
+ return -EBUSY;
+
+- old = rtnl_dereference(sdata->u.ap.beacon);
++ old = sdata_dereference(sdata->u.ap.beacon, sdata);
+ if (!old)
+ return -ENOENT;
+
+@@ -1050,15 +1052,18 @@ static int ieee80211_stop_ap(struct wiph
struct ieee80211_local *local = sdata->local;
struct beacon_data *old_beacon;
struct probe_resp *old_probe_resp;
+ struct cfg80211_chan_def chandef;
- old_beacon = rtnl_dereference(sdata->u.ap.beacon);
+- old_beacon = rtnl_dereference(sdata->u.ap.beacon);
++ old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata);
if (!old_beacon)
-@@ -1091,8 +1092,10 @@ static int ieee80211_stop_ap(struct wiph
+ return -ENOENT;
+- old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp);
++ old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata);
+
+ /* abort any running channel switch */
+ sdata->vif.csa_active = false;
+- cancel_work_sync(&sdata->csa_finalize_work);
++ kfree(sdata->u.ap.next_beacon);
++ sdata->u.ap.next_beacon = NULL;
++
+ cancel_work_sync(&sdata->u.ap.request_smps_work);
+
+ /* turn off carrier for this interface and dependent VLANs */
+@@ -1091,8 +1096,10 @@ static int ieee80211_stop_ap(struct wiph
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
if (sdata->wdev.cac_started) {
@@ -3077,6 +3152,128 @@
GFP_KERNEL);
}
+@@ -1368,7 +1375,7 @@ static int sta_apply_parameters(struct i
+ changed |=
+ ieee80211_mps_set_sta_local_pm(sta,
+ params->local_pm);
+- ieee80211_bss_info_change_notify(sdata, changed);
++ ieee80211_mbss_info_change_notify(sdata, changed);
+ #endif
+ }
+
+@@ -1953,7 +1960,7 @@ static int ieee80211_change_bss(struct w
+ enum ieee80211_band band;
+ u32 changed = 0;
+
+- if (!rtnl_dereference(sdata->u.ap.beacon))
++ if (!sdata_dereference(sdata->u.ap.beacon, sdata))
+ return -ENOENT;
+
+ band = ieee80211_get_sdata_band(sdata);
+@@ -2964,27 +2971,33 @@ void ieee80211_csa_finalize_work(struct
+ struct ieee80211_local *local = sdata->local;
+ int err, changed = 0;
+
++ sdata_lock(sdata);
++ /* AP might have been stopped while waiting for the lock. */
++ if (!sdata->vif.csa_active)
++ goto unlock;
++
+ if (!ieee80211_sdata_running(sdata))
+- return;
++ goto unlock;
+
+ sdata->radar_required = sdata->csa_radar_required;
+- err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
+- &changed);
++ err = ieee80211_vif_change_channel(sdata, &changed);
+ if (WARN_ON(err < 0))
+- return;
++ goto unlock;
+
+ if (!local->use_chanctx) {
+- local->_oper_chandef = local->csa_chandef;
++ local->_oper_chandef = sdata->csa_chandef;
+ ieee80211_hw_config(local, 0);
+ }
+
+ ieee80211_bss_info_change_notify(sdata, changed);
+
++ sdata->vif.csa_active = false;
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
+ if (err < 0)
+- return;
++ goto unlock;
++
+ changed |= err;
+ kfree(sdata->u.ap.next_beacon);
+ sdata->u.ap.next_beacon = NULL;
+@@ -2998,20 +3011,22 @@ void ieee80211_csa_finalize_work(struct
+ case NL80211_IFTYPE_MESH_POINT:
+ err = ieee80211_mesh_finish_csa(sdata);
+ if (err < 0)
+- return;
++ goto unlock;
+ break;
+ #endif
+ default:
+ WARN_ON(1);
+- return;
++ goto unlock;
+ }
+- sdata->vif.csa_active = false;
+
+ ieee80211_wake_queues_by_reason(&sdata->local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+
+- cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);
++ cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
++
++unlock:
++ sdata_unlock(sdata);
+ }
+
+ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+@@ -3024,6 +3039,8 @@ static int ieee80211_channel_switch(stru
+ struct ieee80211_if_mesh __maybe_unused *ifmsh;
+ int err, num_chanctx;
+
++ lockdep_assert_held(&sdata->wdev.mtx);
++
+ if (!list_empty(&local->roc_list) || local->scanning)
+ return -EBUSY;
+
+@@ -3120,9 +3137,17 @@ static int ieee80211_channel_switch(stru
+ params->chandef.chan->band)
+ return -EINVAL;
+
++ ifmsh->chsw_init = true;
++ if (!ifmsh->pre_value)
++ ifmsh->pre_value = 1;
++ else
++ ifmsh->pre_value++;
++
+ err = ieee80211_mesh_csa_beacon(sdata, params, true);
+- if (err < 0)
++ if (err < 0) {
++ ifmsh->chsw_init = false;
+ return err;
++ }
+ break;
+ #endif
+ default:
+@@ -3136,7 +3161,7 @@ static int ieee80211_channel_switch(stru
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+
+- local->csa_chandef = params->chandef;
++ sdata->csa_chandef = params->chandef;
+ sdata->vif.csa_active = true;
+
+ ieee80211_bss_info_change_notify(sdata, err);
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -749,6 +749,7 @@ static void ieee80211_do_stop(struct iee
@@ -3112,7 +3309,44 @@
break;
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
-@@ -1398,10 +1398,12 @@ void ieee80211_dfs_cac_timer_work(struct
+@@ -886,8 +886,7 @@ static void ieee80211_chswitch_work(stru
+ if (!ifmgd->associated)
+ goto out;
+
+- ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
+- &changed);
++ ret = ieee80211_vif_change_channel(sdata, &changed);
+ if (ret) {
+ sdata_info(sdata,
+ "vif channel switch failed, disconnecting\n");
+@@ -897,7 +896,7 @@ static void ieee80211_chswitch_work(stru
+ }
+
+ if (!local->use_chanctx) {
+- local->_oper_chandef = local->csa_chandef;
++ local->_oper_chandef = sdata->csa_chandef;
+ /* Call "hw_config" only if doing sw channel switch.
+ * Otherwise update the channel directly
+ */
+@@ -908,7 +907,7 @@ static void ieee80211_chswitch_work(stru
+ }
+
+ /* XXX: shouldn't really modify cfg80211-owned data! */
+- ifmgd->associated->channel = local->csa_chandef.chan;
++ ifmgd->associated->channel = sdata->csa_chandef.chan;
+
+ /* XXX: wait for a beacon first? */
+ ieee80211_wake_queues_by_reason(&local->hw,
+@@ -1035,7 +1034,7 @@ ieee80211_sta_process_chanswitch(struct
+ }
+ mutex_unlock(&local->chanctx_mtx);
+
+- local->csa_chandef = csa_ie.chandef;
++ sdata->csa_chandef = csa_ie.chandef;
+
+ if (csa_ie.mode)
+ ieee80211_stop_queues_by_reason(&local->hw,
+@@ -1398,10 +1397,12 @@ void ieee80211_dfs_cac_timer_work(struct
struct ieee80211_sub_if_data *sdata =
container_of(delayed_work, struct ieee80211_sub_if_data,
dfs_cac_timer_work);
@@ -3267,6 +3501,21 @@
NL80211_RADAR_CAC_ABORTED,
GFP_KERNEL);
}
+@@ -2459,14 +2462,9 @@ int ieee80211_send_action_csa(struct iee
+ WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
+ put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */
+ pos += 2;
+- if (!ifmsh->pre_value)
+- ifmsh->pre_value = 1;
+- else
+- ifmsh->pre_value++;
+ pre_value = cpu_to_le16(ifmsh->pre_value);
+ memcpy(pos, &pre_value, 2); /* Precedence Value */
+ pos += 2;
+- ifmsh->chsw_init = true;
+ }
+
+ ieee80211_tx_skb(sdata, skb);
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -277,6 +277,32 @@ void cfg80211_set_dfs_state(struct wiphy
@@ -3649,16 +3898,17 @@
if (chan->flags & IEEE80211_CHAN_RADAR) {
if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
goto nla_put_failure;
-@@ -1229,7 +1229,7 @@ static int nl80211_send_wiphy(struct cfg
+@@ -1229,7 +1229,8 @@ static int nl80211_send_wiphy(struct cfg
nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
goto nla_put_failure;
if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
- nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ))
-+ nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_10_MHZ))
++ (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
++ nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
goto nla_put_failure;
state->split_start++;
-@@ -2170,7 +2170,7 @@ static inline u64 wdev_id(struct wireles
+@@ -2170,7 +2171,7 @@ static inline u64 wdev_id(struct wireles
}
static int nl80211_send_chandef(struct sk_buff *msg,
@@ -3667,7 +3917,59 @@
{
WARN_ON(!cfg80211_chandef_valid(chandef));
-@@ -5653,7 +5653,7 @@ static int nl80211_start_radar_detection
+@@ -3219,6 +3220,7 @@ static int nl80211_start_ap(struct sk_bu
+ return PTR_ERR(params.acl);
+ }
+
++ wdev_lock(wdev);
+ err = rdev_start_ap(rdev, dev, &params);
+ if (!err) {
+ wdev->preset_chandef = params.chandef;
+@@ -3227,6 +3229,7 @@ static int nl80211_start_ap(struct sk_bu
+ wdev->ssid_len = params.ssid_len;
+ memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
+ }
++ wdev_unlock(wdev);
+
+ kfree(params.acl);
+
+@@ -3255,7 +3258,11 @@ static int nl80211_set_beacon(struct sk_
+ if (err)
+ return err;
+
+- return rdev_change_beacon(rdev, dev, &params);
++ wdev_lock(wdev);
++ err = rdev_change_beacon(rdev, dev, &params);
++ wdev_unlock(wdev);
++
++ return err;
+ }
+
+ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
+@@ -4461,7 +4468,9 @@ static int nl80211_set_bss(struct sk_buf
+ {
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
++ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct bss_parameters params;
++ int err;
+
+ memset(&params, 0, sizeof(params));
+ /* default to not changing parameters */
+@@ -4527,7 +4536,11 @@ static int nl80211_set_bss(struct sk_buf
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
+
+- return rdev_change_bss(rdev, dev, &params);
++ wdev_lock(wdev);
++ err = rdev_change_bss(rdev, dev, &params);
++ wdev_unlock(wdev);
++
++ return err;
+ }
+
+ static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
+@@ -5653,7 +5666,7 @@ static int nl80211_start_radar_detection
if (err == 0)
return -EINVAL;
@@ -3676,7 +3978,45 @@
return -EINVAL;
if (!rdev->ops->start_radar_detection)
-@@ -10882,7 +10882,7 @@ EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
+@@ -5793,7 +5806,11 @@ skip_beacons:
+ if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
+ params.block_tx = true;
+
+- return rdev_channel_switch(rdev, dev, &params);
++ wdev_lock(wdev);
++ err = rdev_channel_switch(rdev, dev, &params);
++ wdev_unlock(wdev);
++
++ return err;
+ }
+
+ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
+@@ -10809,21 +10826,18 @@ void cfg80211_ch_switch_notify(struct ne
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+- trace_cfg80211_ch_switch_notify(dev, chandef);
++ ASSERT_WDEV_LOCK(wdev);
+
+- wdev_lock(wdev);
++ trace_cfg80211_ch_switch_notify(dev, chandef);
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+ wdev->iftype != NL80211_IFTYPE_P2P_GO &&
+ wdev->iftype != NL80211_IFTYPE_ADHOC &&
+ wdev->iftype != NL80211_IFTYPE_MESH_POINT))
+- goto out;
++ return;
+
+ wdev->channel = chandef->chan;
+ nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
+-out:
+- wdev_unlock(wdev);
+- return;
+ }
+ EXPORT_SYMBOL(cfg80211_ch_switch_notify);
+
+@@ -10882,7 +10896,7 @@ EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
void
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
@@ -4772,3 +5112,216 @@
mr->cur_tp = MINSTREL_TRUNC(tp);
}
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+@@ -3984,18 +3984,20 @@ static void ar9003_hw_quick_drop_apply(s
+ int quick_drop;
+ s32 t[3], f[3] = {5180, 5500, 5785};
+
+- if (!(pBase->miscConfiguration & BIT(1)))
++ if (!(pBase->miscConfiguration & BIT(4)))
+ return;
+
+- if (freq < 4000)
+- quick_drop = eep->modalHeader2G.quick_drop;
+- else {
+- t[0] = eep->base_ext1.quick_drop_low;
+- t[1] = eep->modalHeader5G.quick_drop;
+- t[2] = eep->base_ext1.quick_drop_high;
+- quick_drop = ar9003_hw_power_interpolate(freq, f, t, 3);
++ if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9340(ah)) {
++ if (freq < 4000) {
++ quick_drop = eep->modalHeader2G.quick_drop;
++ } else {
++ t[0] = eep->base_ext1.quick_drop_low;
++ t[1] = eep->modalHeader5G.quick_drop;
++ t[2] = eep->base_ext1.quick_drop_high;
++ quick_drop = ar9003_hw_power_interpolate(freq, f, t, 3);
++ }
++ REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, quick_drop);
+ }
+- REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, quick_drop);
+ }
+
+ static void ar9003_hw_txend_to_xpa_off_apply(struct ath_hw *ah, bool is2ghz)
+@@ -4035,7 +4037,7 @@ static void ar9003_hw_xlna_bias_strength
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+ u8 bias;
+
+- if (!(eep->baseEepHeader.featureEnable & 0x40))
++ if (!(eep->baseEepHeader.miscConfiguration & 0x40))
+ return;
+
+ if (!AR_SREV_9300(ah))
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -735,6 +735,7 @@ struct ieee80211_sub_if_data {
+ int csa_counter_offset_beacon;
+ int csa_counter_offset_presp;
+ bool csa_radar_required;
++ struct cfg80211_chan_def csa_chandef;
+
+ /* used to reconfigure hardware SM PS */
+ struct work_struct recalc_smps;
+@@ -811,6 +812,9 @@ static inline void sdata_unlock(struct i
+ __release(&sdata->wdev.mtx);
+ }
+
++#define sdata_dereference(p, sdata) \
++ rcu_dereference_protected(p, lockdep_is_held(&sdata->wdev.mtx))
++
+ static inline void
+ sdata_assert_lock(struct ieee80211_sub_if_data *sdata)
+ {
+@@ -1098,7 +1102,6 @@ struct ieee80211_local {
+ enum mac80211_scan_state next_scan_state;
+ struct delayed_work scan_work;
+ struct ieee80211_sub_if_data __rcu *scan_sdata;
+- struct cfg80211_chan_def csa_chandef;
+ /* For backward compatibility only -- do not use */
+ struct cfg80211_chan_def _oper_chandef;
+
+@@ -1236,6 +1239,7 @@ struct ieee80211_csa_ie {
+ u8 mode;
+ u8 count;
+ u8 ttl;
++ u16 pre_value;
+ };
+
+ /* Parsed Information Elements */
+@@ -1738,7 +1742,6 @@ ieee80211_vif_change_bandwidth(struct ie
+ /* NOTE: only use ieee80211_vif_change_channel() for channel switch */
+ int __must_check
+ ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
+- const struct cfg80211_chan_def *chandef,
+ 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);
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -411,12 +411,12 @@ int ieee80211_vif_use_channel(struct iee
+ }
+
+ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
+- const struct cfg80211_chan_def *chandef,
+ u32 *changed)
+ {
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx_conf *conf;
+ struct ieee80211_chanctx *ctx;
++ const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
+ int ret;
+ u32 chanctx_changed = 0;
+
+--- a/net/mac80211/ibss.c
++++ b/net/mac80211/ibss.c
+@@ -550,12 +550,12 @@ int ieee80211_ibss_finish_csa(struct iee
+ capability);
+ /* XXX: should not really modify cfg80211 data */
+ if (cbss) {
+- cbss->channel = sdata->local->csa_chandef.chan;
++ cbss->channel = sdata->csa_chandef.chan;
+ cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
+ }
+ }
+
+- ifibss->chandef = sdata->local->csa_chandef;
++ ifibss->chandef = sdata->csa_chandef;
+
+ /* generate the beacon */
+ err = ieee80211_ibss_csa_beacon(sdata, NULL);
+@@ -922,7 +922,7 @@ ieee80211_ibss_process_chanswitch(struct
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+
+- sdata->local->csa_chandef = params.chandef;
++ sdata->csa_chandef = params.chandef;
+ sdata->vif.csa_active = true;
+
+ ieee80211_bss_info_change_notify(sdata, err);
+--- a/net/mac80211/mesh.c
++++ b/net/mac80211/mesh.c
+@@ -943,14 +943,19 @@ ieee80211_mesh_process_chnswitch(struct
+ params.chandef.chan->center_freq);
+
+ params.block_tx = csa_ie.mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
+- if (beacon)
++ if (beacon) {
+ ifmsh->chsw_ttl = csa_ie.ttl - 1;
+- else
+- ifmsh->chsw_ttl = 0;
++ if (ifmsh->pre_value >= csa_ie.pre_value)
++ return false;
++ ifmsh->pre_value = csa_ie.pre_value;
++ }
+
+- if (ifmsh->chsw_ttl > 0)
++ if (ifmsh->chsw_ttl < ifmsh->mshcfg.dot11MeshTTL) {
+ if (ieee80211_mesh_csa_beacon(sdata, &params, false) < 0)
+ return false;
++ } else {
++ return false;
++ }
+
+ sdata->csa_radar_required = params.radar_required;
+
+@@ -959,7 +964,7 @@ ieee80211_mesh_process_chnswitch(struct
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+
+- sdata->local->csa_chandef = params.chandef;
++ sdata->csa_chandef = params.chandef;
+ sdata->vif.csa_active = true;
+
+ ieee80211_bss_info_change_notify(sdata, err);
+@@ -1163,7 +1168,6 @@ static int mesh_fwd_csa_frame(struct iee
+ offset_ttl = (len < 42) ? 7 : 10;
+ *(pos + offset_ttl) -= 1;
+ *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+- sdata->u.mesh.chsw_ttl = *(pos + offset_ttl);
+
+ memcpy(mgmt_fwd, mgmt, len);
+ eth_broadcast_addr(mgmt_fwd->da);
+@@ -1182,7 +1186,7 @@ static void mesh_rx_csa_frame(struct iee
+ u16 pre_value;
+ bool fwd_csa = true;
+ size_t baselen;
+- u8 *pos, ttl;
++ u8 *pos;
+
+ if (mgmt->u.action.u.measurement.action_code !=
+ WLAN_ACTION_SPCT_CHL_SWITCH)
+@@ -1193,8 +1197,8 @@ static void mesh_rx_csa_frame(struct iee
+ u.action.u.chan_switch.variable);
+ ieee802_11_parse_elems(pos, len - baselen, false, &elems);
+
+- ttl = elems.mesh_chansw_params_ie->mesh_ttl;
+- if (!--ttl)
++ ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
++ if (!--ifmsh->chsw_ttl)
+ fwd_csa = false;
+
+ pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
+--- a/net/mac80211/spectmgmt.c
++++ b/net/mac80211/spectmgmt.c
+@@ -78,6 +78,8 @@ int ieee80211_parse_ch_switch_ie(struct
+ if (elems->mesh_chansw_params_ie) {
+ csa_ie->ttl = elems->mesh_chansw_params_ie->mesh_ttl;
+ csa_ie->mode = elems->mesh_chansw_params_ie->mesh_flags;
++ csa_ie->pre_value = le16_to_cpu(
++ elems->mesh_chansw_params_ie->mesh_pre_value);
+ }
+
+ new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
+--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
++++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
+@@ -1109,7 +1109,9 @@ void ath6kl_cfg80211_ch_switch_notify(st
+ (mode == WMI_11G_HT20) ?
+ NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
+
++ mutex_lock(vif->wdev->mtx);
+ cfg80211_ch_switch_notify(vif->ndev, &chandef);
++ mutex_unlock(vif->wdev->mtx);
+ }
+
+ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
diff --git a/package/kernel/mac80211/patches/310-ap_scan.patch b/package/kernel/mac80211/patches/310-ap_scan.patch
index 869bff7b63..928963ee34 100644
--- a/package/kernel/mac80211/patches/310-ap_scan.patch
+++ b/package/kernel/mac80211/patches/310-ap_scan.patch
@@ -1,6 +1,6 @@
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -2113,7 +2113,7 @@ static int ieee80211_scan(struct wiphy *
+@@ -2117,7 +2117,7 @@ static int ieee80211_scan(struct wiphy *
* the frames sent while scanning on other channel will be
* lost)
*/
diff --git a/package/kernel/mac80211/patches/520-mac80211_cur_txpower.patch b/package/kernel/mac80211/patches/520-mac80211_cur_txpower.patch
index f2b87f2edd..9361365642 100644
--- a/package/kernel/mac80211/patches/520-mac80211_cur_txpower.patch
+++ b/package/kernel/mac80211/patches/520-mac80211_cur_txpower.patch
@@ -10,7 +10,7 @@
u8 uapsd_queues;
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -2294,7 +2294,9 @@ static int ieee80211_get_tx_power(struct
+@@ -2298,7 +2298,9 @@ static int ieee80211_get_tx_power(struct
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
diff --git a/package/kernel/mac80211/patches/523-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/523-mac80211_configure_antenna_gain.patch
index 12937e6eb1..00265e9e0e 100644
--- a/package/kernel/mac80211/patches/523-mac80211_configure_antenna_gain.patch
+++ b/package/kernel/mac80211/patches/523-mac80211_configure_antenna_gain.patch
@@ -36,9 +36,9 @@
u8 ps_dtim_period;
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
-@@ -1511,6 +1511,9 @@ enum nl80211_commands {
- * @NL80211_ATTR_SUPPORT_5_10_MHZ: A flag indicating that the device supports
- * 5 MHz and 10 MHz channel bandwidth.
+@@ -1514,6 +1514,9 @@ enum nl80211_commands {
+ * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports
+ * 10 MHz channel bandwidth.
*
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
+ * transmit power to stay within regulatory limits. u32, dBi.
@@ -46,9 +46,9 @@
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
-@@ -1829,6 +1832,8 @@ enum nl80211_attrs {
-
- NL80211_ATTR_SUPPORT_5_10_MHZ,
+@@ -1833,6 +1836,8 @@ enum nl80211_attrs {
+ NL80211_ATTR_SUPPORT_5_MHZ,
+ NL80211_ATTR_SUPPORT_10_MHZ,
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
+
@@ -57,7 +57,7 @@
__NL80211_ATTR_AFTER_LAST,
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -2304,6 +2304,19 @@ static int ieee80211_get_tx_power(struct
+@@ -2308,6 +2308,19 @@ static int ieee80211_get_tx_power(struct
return 0;
}
@@ -77,7 +77,7 @@
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
const u8 *addr)
{
-@@ -3839,6 +3852,7 @@ struct cfg80211_ops mac80211_config_ops
+@@ -3861,6 +3874,7 @@ struct cfg80211_ops mac80211_config_ops
.set_wiphy_params = ieee80211_set_wiphy_params,
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
@@ -87,7 +87,7 @@
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
-@@ -1182,6 +1182,7 @@ struct ieee80211_local {
+@@ -1185,6 +1185,7 @@ struct ieee80211_local {
int dynamic_ps_forced_timeout;
int user_power_level; /* in dBm, for all interfaces */
@@ -147,7 +147,7 @@
};
/* policy for the key attributes */
-@@ -2038,6 +2039,22 @@ static int nl80211_set_wiphy(struct sk_b
+@@ -2039,6 +2040,22 @@ static int nl80211_set_wiphy(struct sk_b
goto bad_res;
}