Back from a long absence, so we have a number of things:
* a remain-on-channel fix from Avi * hwsim TX power fix from Beni * null-PTR dereference with iTXQ in some rare configurations (Chunho) * 40 MHz custom regdomain fixes (Emmanuel) * look at right place in HT/VHT capability parsing (Igor) * complete A-MPDU teardown properly (Ilan) * Mesh ID Element ordering fix (Liad) * avoid tracing warning in ht_dbg() (Sharon) * fix print of assoc/reassoc (Simon) * fix encrypted VLAN with iTXQ (myself) * fix calling context of TX queue wake (myself) * fix a deadlock with ath10k aggregation (myself) -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEExu3sM/nZ1eRSfR9Ha3t4Rpy0AB0FAlmw78wACgkQa3t4Rpy0 AB1viw/+K2xrwzsKqrNoNM1sV4bPItUTjay64dPVD5CjJ/pAwou6HCu0gCJCh4kt mXhLWHds7Q4sBY+DlN9eIagQLJUaw897FWV+tHHirDGKMsE4tBaIct7PLBpM7r5O H03T5qT9+nDGRAJq6ucLG8v91cTAlBNfEIV73Au9Oi5B0Rq4cs+Tz8xS24EHjfTB zRcLMaE8qoQjIfrwQsYNQBdvYHY5G+Ui5sbPh3HPLDPzAfKAsc75nbikI2QE//s0 cMv5ro39vy0DGyQmdTqNzzzuWWzYvhUD7EiIr7Dfm9ilhljCiVqZg6y7ZVMB/QNq +HRD7ShbTnNMx1fx8w5WO6gKGVSeo0Ga6KKEauTGiWJQTfZQLuIBLylSMVclfvBN 4zOv3vC9EUP5qqPt0cby7VV2D+1Z4Lw2GYZZKHF5numMkgHAoDJ+tJHbBFmz1CEX co/79RFhGLKvZE+8lN40hqvPoYA5NOUO6jyOq384ZbnC190nVqOXvIxi9jmFKBHp rGBE/8e0VPYlc48m6NUFwAvc0HOeN3/ZVaUnoo6SY8fCbru3yhRYzC3pmcepTEbA OVBHirgYtntI2mk4FWd2dkTC6aOfP1o11dwm3deaaEtkwaiKlxI2xfnkbsGaMaOh RW787Y10g0k785ABD/GxynOeqfiXnIxIjMKZiQliR33zxdv4cAI= =QYS4 -----END PGP SIGNATURE----- Merge tag 'mac80211-for-davem-2017-09-07' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211 Johannes Berg says: ==================== Back from a long absence, so we have a number of things: * a remain-on-channel fix from Avi * hwsim TX power fix from Beni * null-PTR dereference with iTXQ in some rare configurations (Chunho) * 40 MHz custom regdomain fixes (Emmanuel) * look at right place in HT/VHT capability parsing (Igor) * complete A-MPDU teardown properly (Ilan) * Mesh ID Element ordering fix (Liad) * avoid tracing warning in ht_dbg() (Sharon) * fix print of assoc/reassoc (Simon) * fix encrypted VLAN with iTXQ (myself) * fix calling context of TX queue wake (myself) * fix a deadlock with ath10k aggregation (myself) ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
0f2be423f1
|
@ -1362,8 +1362,6 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
|
|||
txi->control.rates,
|
||||
ARRAY_SIZE(txi->control.rates));
|
||||
|
||||
txi->rate_driver_data[0] = channel;
|
||||
|
||||
if (skb->len >= 24 + 8 &&
|
||||
ieee80211_is_probe_resp(hdr->frame_control)) {
|
||||
/* fake header transmission time */
|
||||
|
|
|
@ -919,21 +919,10 @@ struct ieee80211_tx_info {
|
|||
unsigned long jiffies;
|
||||
};
|
||||
/* NB: vif can be NULL for injected frames */
|
||||
union {
|
||||
/* NB: vif can be NULL for injected frames */
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
/* When packets are enqueued on txq it's easy
|
||||
* to re-construct the vif pointer. There's no
|
||||
* more space in tx_info so it can be used to
|
||||
* store the necessary enqueue time for packet
|
||||
* sojourn time computation.
|
||||
*/
|
||||
codel_time_t enqueue_time;
|
||||
};
|
||||
struct ieee80211_vif *vif;
|
||||
struct ieee80211_key_conf *hw_key;
|
||||
u32 flags;
|
||||
/* 4 bytes free */
|
||||
codel_time_t enqueue_time;
|
||||
} control;
|
||||
struct {
|
||||
u64 cookie;
|
||||
|
|
|
@ -245,10 +245,10 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
|
|||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
|
||||
void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||
u8 dialog_token, u16 timeout,
|
||||
u16 start_seq_num, u16 ba_policy, u16 tid,
|
||||
u16 buf_size, bool tx, bool auto_seq)
|
||||
void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||
u8 dialog_token, u16 timeout,
|
||||
u16 start_seq_num, u16 ba_policy, u16 tid,
|
||||
u16 buf_size, bool tx, bool auto_seq)
|
||||
{
|
||||
struct ieee80211_local *local = sta->sdata->local;
|
||||
struct tid_ampdu_rx *tid_agg_rx;
|
||||
|
@ -267,7 +267,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
|||
ht_dbg(sta->sdata,
|
||||
"STA %pM requests BA session on unsupported tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
goto end_no_lock;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!sta->sta.ht_cap.ht_supported) {
|
||||
|
@ -275,14 +275,14 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
|||
"STA %pM erroneously requests BA session on tid %d w/o QoS\n",
|
||||
sta->sta.addr, tid);
|
||||
/* send a response anyway, it's an error case if we get here */
|
||||
goto end_no_lock;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
|
||||
ht_dbg(sta->sdata,
|
||||
"Suspend in progress - Denying ADDBA request (%pM tid %d)\n",
|
||||
sta->sta.addr, tid);
|
||||
goto end_no_lock;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* sanity check for incoming parameters:
|
||||
|
@ -296,7 +296,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
|||
ht_dbg_ratelimited(sta->sdata,
|
||||
"AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
|
||||
sta->sta.addr, tid, ba_policy, buf_size);
|
||||
goto end_no_lock;
|
||||
goto end;
|
||||
}
|
||||
/* determine default buffer size */
|
||||
if (buf_size == 0)
|
||||
|
@ -311,7 +311,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
|||
buf_size, sta->sta.addr);
|
||||
|
||||
/* examine state machine */
|
||||
mutex_lock(&sta->ampdu_mlme.mtx);
|
||||
lockdep_assert_held(&sta->ampdu_mlme.mtx);
|
||||
|
||||
if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
|
||||
if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) {
|
||||
|
@ -415,15 +415,25 @@ end:
|
|||
__clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
|
||||
sta->ampdu_mlme.tid_rx_token[tid] = dialog_token;
|
||||
}
|
||||
mutex_unlock(&sta->ampdu_mlme.mtx);
|
||||
|
||||
end_no_lock:
|
||||
if (tx)
|
||||
ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
|
||||
dialog_token, status, 1, buf_size,
|
||||
timeout);
|
||||
}
|
||||
|
||||
void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||
u8 dialog_token, u16 timeout,
|
||||
u16 start_seq_num, u16 ba_policy, u16 tid,
|
||||
u16 buf_size, bool tx, bool auto_seq)
|
||||
{
|
||||
mutex_lock(&sta->ampdu_mlme.mtx);
|
||||
___ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
|
||||
start_seq_num, ba_policy, tid,
|
||||
buf_size, tx, auto_seq);
|
||||
mutex_unlock(&sta->ampdu_mlme.mtx);
|
||||
}
|
||||
|
||||
void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
|
|
|
@ -226,7 +226,11 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
|
|||
clear_bit(IEEE80211_TXQ_AMPDU, &txqi->flags);
|
||||
|
||||
clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
|
||||
local_bh_disable();
|
||||
rcu_read_lock();
|
||||
drv_wake_tx_queue(sta->sdata->local, txqi);
|
||||
rcu_read_unlock();
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -436,7 +440,7 @@ static void sta_addba_resp_timer_expired(unsigned long data)
|
|||
test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
|
||||
rcu_read_unlock();
|
||||
ht_dbg(sta->sdata,
|
||||
"timer expired on %pM tid %d but we are not (or no longer) expecting addBA response there\n",
|
||||
"timer expired on %pM tid %d not expecting addBA response\n",
|
||||
sta->sta.addr, tid);
|
||||
return;
|
||||
}
|
||||
|
@ -639,7 +643,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
|||
time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
|
||||
HT_AGG_RETRIES_PERIOD)) {
|
||||
ht_dbg(sdata,
|
||||
"BA request denied - waiting a grace period after %d failed requests on %pM tid %u\n",
|
||||
"BA request denied - %d failed requests on %pM tid %u\n",
|
||||
sta->ampdu_mlme.addba_req_num[tid], sta->sta.addr, tid);
|
||||
ret = -EBUSY;
|
||||
goto err_unlock_sta;
|
||||
|
|
|
@ -300,6 +300,24 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
|
|||
|
||||
/* stopping might queue the work again - so cancel only afterwards */
|
||||
cancel_work_sync(&sta->ampdu_mlme.work);
|
||||
|
||||
/*
|
||||
* In case the tear down is part of a reconfigure due to HW restart
|
||||
* request, it is possible that the low level driver requested to stop
|
||||
* the BA session, so handle it to properly clean tid_tx data.
|
||||
*/
|
||||
mutex_lock(&sta->ampdu_mlme.mtx);
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||
struct tid_ampdu_tx *tid_tx =
|
||||
rcu_dereference_protected_tid_tx(sta, i);
|
||||
|
||||
if (!tid_tx)
|
||||
continue;
|
||||
|
||||
if (test_and_clear_bit(HT_AGG_STATE_STOP_CB, &tid_tx->state))
|
||||
ieee80211_stop_tx_ba_cb(sta, i, tid_tx);
|
||||
}
|
||||
mutex_unlock(&sta->ampdu_mlme.mtx);
|
||||
}
|
||||
|
||||
void ieee80211_ba_session_work(struct work_struct *work)
|
||||
|
@ -333,9 +351,9 @@ void ieee80211_ba_session_work(struct work_struct *work)
|
|||
|
||||
if (test_and_clear_bit(tid,
|
||||
sta->ampdu_mlme.tid_rx_manage_offl))
|
||||
__ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
|
||||
IEEE80211_MAX_AMPDU_BUF,
|
||||
false, true);
|
||||
___ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
|
||||
IEEE80211_MAX_AMPDU_BUF,
|
||||
false, true);
|
||||
|
||||
if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS,
|
||||
sta->ampdu_mlme.tid_rx_manage_offl))
|
||||
|
|
|
@ -1760,6 +1760,10 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
|||
u8 dialog_token, u16 timeout,
|
||||
u16 start_seq_num, u16 ba_policy, u16 tid,
|
||||
u16 buf_size, bool tx, bool auto_seq);
|
||||
void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||
u8 dialog_token, u16 timeout,
|
||||
u16 start_seq_num, u16 ba_policy, u16 tid,
|
||||
u16 buf_size, bool tx, bool auto_seq);
|
||||
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
|
||||
enum ieee80211_agg_stop_reason reason);
|
||||
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
@ -731,7 +731,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
|||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
||||
local->ops->wake_tx_queue) {
|
||||
/* XXX: for AP_VLAN, actually track AP queues */
|
||||
netif_tx_start_all_queues(dev);
|
||||
if (dev)
|
||||
netif_tx_start_all_queues(dev);
|
||||
} else if (dev) {
|
||||
unsigned long flags;
|
||||
int n_acs = IEEE80211_NUM_ACS;
|
||||
|
@ -792,6 +793,7 @@ static int ieee80211_open(struct net_device *dev)
|
|||
static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
bool going_down)
|
||||
{
|
||||
struct ieee80211_sub_if_data *txq_sdata = sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct fq *fq = &local->fq;
|
||||
unsigned long flags;
|
||||
|
@ -937,6 +939,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
txq_sdata = container_of(sdata->bss,
|
||||
struct ieee80211_sub_if_data, u.ap);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
list_del(&sdata->u.vlan.list);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
@ -1007,8 +1012,17 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
if (sdata->vif.txq) {
|
||||
struct txq_info *txqi = to_txq_info(sdata->vif.txq);
|
||||
if (txq_sdata->vif.txq) {
|
||||
struct txq_info *txqi = to_txq_info(txq_sdata->vif.txq);
|
||||
|
||||
/*
|
||||
* FIXME FIXME
|
||||
*
|
||||
* We really shouldn't purge the *entire* txqi since that
|
||||
* contains frames for the other AP_VLANs (and possibly
|
||||
* the AP itself) as well, but there's no API in FQ now
|
||||
* to be able to filter.
|
||||
*/
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
ieee80211_txq_purge(local, txqi);
|
||||
|
|
|
@ -3155,7 +3155,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
if (len < 24 + 6)
|
||||
return;
|
||||
|
||||
reassoc = ieee80211_is_reassoc_req(mgmt->frame_control);
|
||||
reassoc = ieee80211_is_reassoc_resp(mgmt->frame_control);
|
||||
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
|
||||
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
|
||||
aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
|
||||
|
|
|
@ -707,6 +707,8 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
|
|||
if (!cookie)
|
||||
return -ENOENT;
|
||||
|
||||
flush_work(&local->hw_roc_start);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
|
||||
if (!mgmt_tx && roc->cookie != cookie)
|
||||
|
|
|
@ -1276,11 +1276,6 @@ static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
|
|||
IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
|
||||
}
|
||||
|
||||
static void ieee80211_set_skb_vif(struct sk_buff *skb, struct txq_info *txqi)
|
||||
{
|
||||
IEEE80211_SKB_CB(skb)->control.vif = txqi->txq.vif;
|
||||
}
|
||||
|
||||
static u32 codel_skb_len_func(const struct sk_buff *skb)
|
||||
{
|
||||
return skb->len;
|
||||
|
@ -3414,6 +3409,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
|||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_tx_data tx;
|
||||
ieee80211_tx_result r;
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
|
||||
|
@ -3430,8 +3426,6 @@ begin:
|
|||
if (!skb)
|
||||
goto out;
|
||||
|
||||
ieee80211_set_skb_vif(skb, txqi);
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
|
@ -3488,6 +3482,34 @@ begin:
|
|||
}
|
||||
}
|
||||
|
||||
switch (tx.sdata->vif.type) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
if (tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
|
||||
vif = &tx.sdata->vif;
|
||||
break;
|
||||
}
|
||||
tx.sdata = rcu_dereference(local->monitor_sdata);
|
||||
if (tx.sdata) {
|
||||
vif = &tx.sdata->vif;
|
||||
info->hw_queue =
|
||||
vif->hw_queue[skb_get_queue_mapping(skb)];
|
||||
} else if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) {
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
goto begin;
|
||||
} else {
|
||||
vif = NULL;
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
tx.sdata = container_of(tx.sdata->bss,
|
||||
struct ieee80211_sub_if_data, u.ap);
|
||||
/* fall through */
|
||||
default:
|
||||
vif = &tx.sdata->vif;
|
||||
break;
|
||||
}
|
||||
|
||||
IEEE80211_SKB_CB(skb)->control.vif = vif;
|
||||
out:
|
||||
spin_unlock_bh(&fq->lock);
|
||||
|
||||
|
|
|
@ -1436,7 +1436,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
|
|||
WLAN_EID_SSID_LIST,
|
||||
WLAN_EID_CHANNEL_USAGE,
|
||||
WLAN_EID_INTERWORKING,
|
||||
/* mesh ID can't happen here */
|
||||
WLAN_EID_MESH_ID,
|
||||
/* 60 GHz can't happen here right now */
|
||||
};
|
||||
noffset = ieee80211_ie_split(ie, ie_len,
|
||||
|
|
|
@ -3791,8 +3791,8 @@ static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
|
|||
static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
|
||||
{
|
||||
const struct cfg80211_beacon_data *bcn = ¶ms->beacon;
|
||||
size_t ies_len = bcn->beacon_ies_len;
|
||||
const u8 *ies = bcn->beacon_ies;
|
||||
size_t ies_len = bcn->tail_len;
|
||||
const u8 *ies = bcn->tail;
|
||||
const u8 *rates;
|
||||
const u8 *cap;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2017 Intel Deutschland GmbH
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -1483,7 +1484,9 @@ static void reg_process_ht_flags_channel(struct wiphy *wiphy,
|
|||
{
|
||||
struct ieee80211_supported_band *sband = wiphy->bands[channel->band];
|
||||
struct ieee80211_channel *channel_before = NULL, *channel_after = NULL;
|
||||
const struct ieee80211_regdomain *regd;
|
||||
unsigned int i;
|
||||
u32 flags;
|
||||
|
||||
if (!is_ht40_allowed(channel)) {
|
||||
channel->flags |= IEEE80211_CHAN_NO_HT40;
|
||||
|
@ -1503,17 +1506,30 @@ static void reg_process_ht_flags_channel(struct wiphy *wiphy,
|
|||
channel_after = c;
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
regd = get_wiphy_regdom(wiphy);
|
||||
if (regd) {
|
||||
const struct ieee80211_reg_rule *reg_rule =
|
||||
freq_reg_info_regd(MHZ_TO_KHZ(channel->center_freq),
|
||||
regd, MHZ_TO_KHZ(20));
|
||||
|
||||
if (!IS_ERR(reg_rule))
|
||||
flags = reg_rule->flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Please note that this assumes target bandwidth is 20 MHz,
|
||||
* if that ever changes we also need to change the below logic
|
||||
* to include that as well.
|
||||
*/
|
||||
if (!is_ht40_allowed(channel_before))
|
||||
if (!is_ht40_allowed(channel_before) ||
|
||||
flags & NL80211_RRF_NO_HT40MINUS)
|
||||
channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
|
||||
else
|
||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
|
||||
|
||||
if (!is_ht40_allowed(channel_after))
|
||||
if (!is_ht40_allowed(channel_after) ||
|
||||
flags & NL80211_RRF_NO_HT40PLUS)
|
||||
channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
|
||||
else
|
||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
|
||||
|
|
Loading…
Reference in New Issue