Commit 0f2be423 authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-davem-2017-09-07' of...

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 8e0deed9 bde59c47
...@@ -1362,8 +1362,6 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, ...@@ -1362,8 +1362,6 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
txi->control.rates, txi->control.rates,
ARRAY_SIZE(txi->control.rates)); ARRAY_SIZE(txi->control.rates));
txi->rate_driver_data[0] = channel;
if (skb->len >= 24 + 8 && if (skb->len >= 24 + 8 &&
ieee80211_is_probe_resp(hdr->frame_control)) { ieee80211_is_probe_resp(hdr->frame_control)) {
/* fake header transmission time */ /* fake header transmission time */
......
...@@ -919,21 +919,10 @@ struct ieee80211_tx_info { ...@@ -919,21 +919,10 @@ struct ieee80211_tx_info {
unsigned long jiffies; unsigned long jiffies;
}; };
/* NB: vif can be NULL for injected frames */ /* NB: vif can be NULL for injected frames */
union { struct ieee80211_vif *vif;
/* 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_key_conf *hw_key; struct ieee80211_key_conf *hw_key;
u32 flags; u32 flags;
/* 4 bytes free */ codel_time_t enqueue_time;
} control; } control;
struct { struct {
u64 cookie; u64 cookie;
......
...@@ -245,10 +245,10 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d ...@@ -245,10 +245,10 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
ieee80211_tx_skb(sdata, skb); ieee80211_tx_skb(sdata, skb);
} }
void __ieee80211_start_rx_ba_session(struct sta_info *sta, void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
u8 dialog_token, u16 timeout, u8 dialog_token, u16 timeout,
u16 start_seq_num, u16 ba_policy, u16 tid, u16 start_seq_num, u16 ba_policy, u16 tid,
u16 buf_size, bool tx, bool auto_seq) u16 buf_size, bool tx, bool auto_seq)
{ {
struct ieee80211_local *local = sta->sdata->local; struct ieee80211_local *local = sta->sdata->local;
struct tid_ampdu_rx *tid_agg_rx; struct tid_ampdu_rx *tid_agg_rx;
...@@ -267,7 +267,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, ...@@ -267,7 +267,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
ht_dbg(sta->sdata, ht_dbg(sta->sdata,
"STA %pM requests BA session on unsupported tid %d\n", "STA %pM requests BA session on unsupported tid %d\n",
sta->sta.addr, tid); sta->sta.addr, tid);
goto end_no_lock; goto end;
} }
if (!sta->sta.ht_cap.ht_supported) { if (!sta->sta.ht_cap.ht_supported) {
...@@ -275,14 +275,14 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, ...@@ -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 %pM erroneously requests BA session on tid %d w/o QoS\n",
sta->sta.addr, tid); sta->sta.addr, tid);
/* send a response anyway, it's an error case if we get here */ /* 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)) { if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
ht_dbg(sta->sdata, ht_dbg(sta->sdata,
"Suspend in progress - Denying ADDBA request (%pM tid %d)\n", "Suspend in progress - Denying ADDBA request (%pM tid %d)\n",
sta->sta.addr, tid); sta->sta.addr, tid);
goto end_no_lock; goto end;
} }
/* sanity check for incoming parameters: /* sanity check for incoming parameters:
...@@ -296,7 +296,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, ...@@ -296,7 +296,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
ht_dbg_ratelimited(sta->sdata, ht_dbg_ratelimited(sta->sdata,
"AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
sta->sta.addr, tid, ba_policy, buf_size); sta->sta.addr, tid, ba_policy, buf_size);
goto end_no_lock; goto end;
} }
/* determine default buffer size */ /* determine default buffer size */
if (buf_size == 0) if (buf_size == 0)
...@@ -311,7 +311,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, ...@@ -311,7 +311,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
buf_size, sta->sta.addr); buf_size, sta->sta.addr);
/* examine state machine */ /* 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 (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) { if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) {
...@@ -415,15 +415,25 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, ...@@ -415,15 +415,25 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
__clear_bit(tid, sta->ampdu_mlme.unexpected_agg); __clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
sta->ampdu_mlme.tid_rx_token[tid] = dialog_token; sta->ampdu_mlme.tid_rx_token[tid] = dialog_token;
} }
mutex_unlock(&sta->ampdu_mlme.mtx);
end_no_lock:
if (tx) if (tx)
ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
dialog_token, status, 1, buf_size, dialog_token, status, 1, buf_size,
timeout); 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, void ieee80211_process_addba_request(struct ieee80211_local *local,
struct sta_info *sta, struct sta_info *sta,
struct ieee80211_mgmt *mgmt, struct ieee80211_mgmt *mgmt,
......
...@@ -226,7 +226,11 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable) ...@@ -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_AMPDU, &txqi->flags);
clear_bit(IEEE80211_TXQ_STOP, &txqi->flags); clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
local_bh_disable();
rcu_read_lock();
drv_wake_tx_queue(sta->sdata->local, txqi); 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) ...@@ -436,7 +440,7 @@ static void sta_addba_resp_timer_expired(unsigned long data)
test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) { test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
rcu_read_unlock(); rcu_read_unlock();
ht_dbg(sta->sdata, 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); sta->sta.addr, tid);
return; return;
} }
...@@ -639,7 +643,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, ...@@ -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] + time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
HT_AGG_RETRIES_PERIOD)) { HT_AGG_RETRIES_PERIOD)) {
ht_dbg(sdata, 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); sta->ampdu_mlme.addba_req_num[tid], sta->sta.addr, tid);
ret = -EBUSY; ret = -EBUSY;
goto err_unlock_sta; goto err_unlock_sta;
......
...@@ -300,6 +300,24 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *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 */ /* stopping might queue the work again - so cancel only afterwards */
cancel_work_sync(&sta->ampdu_mlme.work); 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) void ieee80211_ba_session_work(struct work_struct *work)
...@@ -333,9 +351,9 @@ 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, if (test_and_clear_bit(tid,
sta->ampdu_mlme.tid_rx_manage_offl)) sta->ampdu_mlme.tid_rx_manage_offl))
__ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid, ___ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
IEEE80211_MAX_AMPDU_BUF, IEEE80211_MAX_AMPDU_BUF,
false, true); false, true);
if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS, if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS,
sta->ampdu_mlme.tid_rx_manage_offl)) sta->ampdu_mlme.tid_rx_manage_offl))
......
...@@ -1760,6 +1760,10 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, ...@@ -1760,6 +1760,10 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
u8 dialog_token, u16 timeout, u8 dialog_token, u16 timeout,
u16 start_seq_num, u16 ba_policy, u16 tid, u16 start_seq_num, u16 ba_policy, u16 tid,
u16 buf_size, bool tx, bool auto_seq); 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, void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
enum ieee80211_agg_stop_reason reason); enum ieee80211_agg_stop_reason reason);
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, 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) ...@@ -731,7 +731,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
sdata->vif.type == NL80211_IFTYPE_AP_VLAN || sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
local->ops->wake_tx_queue) { local->ops->wake_tx_queue) {
/* XXX: for AP_VLAN, actually track AP queues */ /* 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) { } else if (dev) {
unsigned long flags; unsigned long flags;
int n_acs = IEEE80211_NUM_ACS; int n_acs = IEEE80211_NUM_ACS;
...@@ -792,6 +793,7 @@ static int ieee80211_open(struct net_device *dev) ...@@ -792,6 +793,7 @@ static int ieee80211_open(struct net_device *dev)
static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
bool going_down) bool going_down)
{ {
struct ieee80211_sub_if_data *txq_sdata = sdata;
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct fq *fq = &local->fq; struct fq *fq = &local->fq;
unsigned long flags; unsigned long flags;
...@@ -937,6 +939,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ...@@ -937,6 +939,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
switch (sdata->vif.type) { switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_AP_VLAN:
txq_sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data, u.ap);
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
list_del(&sdata->u.vlan.list); list_del(&sdata->u.vlan.list);
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
...@@ -1007,8 +1012,17 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ...@@ -1007,8 +1012,17 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
} }
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
if (sdata->vif.txq) { if (txq_sdata->vif.txq) {
struct txq_info *txqi = to_txq_info(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); spin_lock_bh(&fq->lock);
ieee80211_txq_purge(local, txqi); ieee80211_txq_purge(local, txqi);
......
...@@ -3155,7 +3155,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ...@@ -3155,7 +3155,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
if (len < 24 + 6) if (len < 24 + 6)
return; 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); capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
aid = le16_to_cpu(mgmt->u.assoc_resp.aid); aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
......
...@@ -707,6 +707,8 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, ...@@ -707,6 +707,8 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
if (!cookie) if (!cookie)
return -ENOENT; return -ENOENT;
flush_work(&local->hw_roc_start);
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
list_for_each_entry_safe(roc, tmp, &local->roc_list, list) { list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
if (!mgmt_tx && roc->cookie != cookie) if (!mgmt_tx && roc->cookie != cookie)
......
...@@ -1276,11 +1276,6 @@ static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb) ...@@ -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(); 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) static u32 codel_skb_len_func(const struct sk_buff *skb)
{ {
return skb->len; return skb->len;
...@@ -3414,6 +3409,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, ...@@ -3414,6 +3409,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
struct ieee80211_tx_data tx; struct ieee80211_tx_data tx;
ieee80211_tx_result r; ieee80211_tx_result r;
struct ieee80211_vif *vif;
spin_lock_bh(&fq->lock); spin_lock_bh(&fq->lock);
...@@ -3430,8 +3426,6 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, ...@@ -3430,8 +3426,6 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
if (!skb) if (!skb)
goto out; goto out;
ieee80211_set_skb_vif(skb, txqi);
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
...@@ -3488,6 +3482,34 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, ...@@ -3488,6 +3482,34 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
} }
} }
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: out:
spin_unlock_bh(&fq->lock); spin_unlock_bh(&fq->lock);
......
...@@ -1436,7 +1436,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, ...@@ -1436,7 +1436,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
WLAN_EID_SSID_LIST, WLAN_EID_SSID_LIST,
WLAN_EID_CHANNEL_USAGE, WLAN_EID_CHANNEL_USAGE,
WLAN_EID_INTERWORKING, WLAN_EID_INTERWORKING,
/* mesh ID can't happen here */ WLAN_EID_MESH_ID,
/* 60 GHz can't happen here right now */ /* 60 GHz can't happen here right now */
}; };
noffset = ieee80211_ie_split(ie, ie_len, noffset = ieee80211_ie_split(ie, ie_len,
......
...@@ -3791,8 +3791,8 @@ static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params, ...@@ -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) static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
{ {
const struct cfg80211_beacon_data *bcn = &params->beacon; const struct cfg80211_beacon_data *bcn = &params->beacon;
size_t ies_len = bcn->beacon_ies_len; size_t ies_len = bcn->tail_len;
const u8 *ies = bcn->beacon_ies; const u8 *ies = bcn->tail;
const u8 *rates; const u8 *rates;
const u8 *cap; const u8 *cap;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net> * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com> * Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2017 Intel Deutschland GmbH
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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, ...@@ -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_supported_band *sband = wiphy->bands[channel->band];
struct ieee80211_channel *channel_before = NULL, *channel_after = NULL; struct ieee80211_channel *channel_before = NULL, *channel_after = NULL;
const struct ieee80211_regdomain *regd;
unsigned int i; unsigned int i;
u32 flags;
if (!is_ht40_allowed(channel)) { if (!is_ht40_allowed(channel)) {
channel->flags |= IEEE80211_CHAN_NO_HT40; channel->flags |= IEEE80211_CHAN_NO_HT40;
...@@ -1503,17 +1506,30 @@ static void reg_process_ht_flags_channel(struct wiphy *wiphy, ...@@ -1503,17 +1506,30 @@ static void reg_process_ht_flags_channel(struct wiphy *wiphy,
channel_after = c; 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, * Please note that this assumes target bandwidth is 20 MHz,
* if that ever changes we also need to change the below logic * if that ever changes we also need to change the below logic
* to include that as well. * 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; channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
else else
channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; 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; channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
else else
channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
......
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