|
|
@@ -90,7 +90,7 @@ static u8 ath10k_mac_bitrate_to_rate(int bitrate)
|
|
|
}
|
|
|
|
|
|
u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
|
|
|
- u8 hw_rate)
|
|
|
+ u8 hw_rate, bool cck)
|
|
|
{
|
|
|
const struct ieee80211_rate *rate;
|
|
|
int i;
|
|
|
@@ -98,6 +98,9 @@ u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
|
|
|
for (i = 0; i < sband->n_bitrates; i++) {
|
|
|
rate = &sband->bitrates[i];
|
|
|
|
|
|
+ if (ath10k_mac_bitrate_is_cck(rate->bitrate) != cck)
|
|
|
+ continue;
|
|
|
+
|
|
|
if (rate->hw_value == hw_rate)
|
|
|
return i;
|
|
|
else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE &&
|
|
|
@@ -1960,7 +1963,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
|
|
|
ether_addr_copy(arg->addr, sta->addr);
|
|
|
arg->vdev_id = arvif->vdev_id;
|
|
|
arg->peer_aid = aid;
|
|
|
- arg->peer_flags |= WMI_PEER_AUTH;
|
|
|
+ arg->peer_flags |= arvif->ar->wmi.peer_flags->auth;
|
|
|
arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif);
|
|
|
arg->peer_num_spatial_streams = 1;
|
|
|
arg->peer_caps = vif->bss_conf.assoc_capability;
|
|
|
@@ -1968,6 +1971,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
|
|
|
|
|
|
static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
|
|
|
struct ieee80211_vif *vif,
|
|
|
+ struct ieee80211_sta *sta,
|
|
|
struct wmi_peer_assoc_complete_arg *arg)
|
|
|
{
|
|
|
struct ieee80211_bss_conf *info = &vif->bss_conf;
|
|
|
@@ -2002,12 +2006,17 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
|
|
|
/* FIXME: base on RSN IE/WPA IE is a correct idea? */
|
|
|
if (rsnie || wpaie) {
|
|
|
ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
|
|
|
- arg->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
|
|
|
+ arg->peer_flags |= ar->wmi.peer_flags->need_ptk_4_way;
|
|
|
}
|
|
|
|
|
|
if (wpaie) {
|
|
|
ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
|
|
|
- arg->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
|
|
|
+ arg->peer_flags |= ar->wmi.peer_flags->need_gtk_2_way;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sta->mfp &&
|
|
|
+ test_bit(ATH10K_FW_FEATURE_MFP_SUPPORT, ar->fw_features)) {
|
|
|
+ arg->peer_flags |= ar->wmi.peer_flags->pmf;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -2104,7 +2113,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
|
|
|
ath10k_peer_assoc_h_vht_masked(vht_mcs_mask))
|
|
|
return;
|
|
|
|
|
|
- arg->peer_flags |= WMI_PEER_HT;
|
|
|
+ arg->peer_flags |= ar->wmi.peer_flags->ht;
|
|
|
arg->peer_max_mpdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
|
|
|
ht_cap->ampdu_factor)) - 1;
|
|
|
|
|
|
@@ -2115,10 +2124,10 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
|
|
|
arg->peer_rate_caps |= WMI_RC_HT_FLAG;
|
|
|
|
|
|
if (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)
|
|
|
- arg->peer_flags |= WMI_PEER_LDPC;
|
|
|
+ arg->peer_flags |= ar->wmi.peer_flags->ldbc;
|
|
|
|
|
|
if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) {
|
|
|
- arg->peer_flags |= WMI_PEER_40MHZ;
|
|
|
+ arg->peer_flags |= ar->wmi.peer_flags->bw40;
|
|
|
arg->peer_rate_caps |= WMI_RC_CW40_FLAG;
|
|
|
}
|
|
|
|
|
|
@@ -2132,7 +2141,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
|
|
|
|
|
|
if (ht_cap->cap & IEEE80211_HT_CAP_TX_STBC) {
|
|
|
arg->peer_rate_caps |= WMI_RC_TX_STBC_FLAG;
|
|
|
- arg->peer_flags |= WMI_PEER_STBC;
|
|
|
+ arg->peer_flags |= ar->wmi.peer_flags->stbc;
|
|
|
}
|
|
|
|
|
|
if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) {
|
|
|
@@ -2140,7 +2149,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
|
|
|
stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT;
|
|
|
stbc = stbc << WMI_RC_RX_STBC_FLAG_S;
|
|
|
arg->peer_rate_caps |= stbc;
|
|
|
- arg->peer_flags |= WMI_PEER_STBC;
|
|
|
+ arg->peer_flags |= ar->wmi.peer_flags->stbc;
|
|
|
}
|
|
|
|
|
|
if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
|
|
|
@@ -2321,10 +2330,10 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
|
|
|
if (ath10k_peer_assoc_h_vht_masked(vht_mcs_mask))
|
|
|
return;
|
|
|
|
|
|
- arg->peer_flags |= WMI_PEER_VHT;
|
|
|
+ arg->peer_flags |= ar->wmi.peer_flags->vht;
|
|
|
|
|
|
if (def.chan->band == IEEE80211_BAND_2GHZ)
|
|
|
- arg->peer_flags |= WMI_PEER_VHT_2G;
|
|
|
+ arg->peer_flags |= ar->wmi.peer_flags->vht_2g;
|
|
|
|
|
|
arg->peer_vht_caps = vht_cap->cap;
|
|
|
|
|
|
@@ -2341,7 +2350,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
|
|
|
ampdu_factor)) - 1);
|
|
|
|
|
|
if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
|
|
|
- arg->peer_flags |= WMI_PEER_80MHZ;
|
|
|
+ arg->peer_flags |= ar->wmi.peer_flags->bw80;
|
|
|
|
|
|
arg->peer_vht_rates.rx_max_rate =
|
|
|
__le16_to_cpu(vht_cap->vht_mcs.rx_highest);
|
|
|
@@ -2366,27 +2375,28 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
|
|
|
switch (arvif->vdev_type) {
|
|
|
case WMI_VDEV_TYPE_AP:
|
|
|
if (sta->wme)
|
|
|
- arg->peer_flags |= WMI_PEER_QOS;
|
|
|
+ arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
|
|
|
|
|
|
if (sta->wme && sta->uapsd_queues) {
|
|
|
- arg->peer_flags |= WMI_PEER_APSD;
|
|
|
+ arg->peer_flags |= arvif->ar->wmi.peer_flags->apsd;
|
|
|
arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
|
|
|
}
|
|
|
break;
|
|
|
case WMI_VDEV_TYPE_STA:
|
|
|
if (vif->bss_conf.qos)
|
|
|
- arg->peer_flags |= WMI_PEER_QOS;
|
|
|
+ arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
|
|
|
break;
|
|
|
case WMI_VDEV_TYPE_IBSS:
|
|
|
if (sta->wme)
|
|
|
- arg->peer_flags |= WMI_PEER_QOS;
|
|
|
+ arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM qos %d\n",
|
|
|
- sta->addr, !!(arg->peer_flags & WMI_PEER_QOS));
|
|
|
+ sta->addr, !!(arg->peer_flags &
|
|
|
+ arvif->ar->wmi.peer_flags->qos));
|
|
|
}
|
|
|
|
|
|
static bool ath10k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta)
|
|
|
@@ -2479,7 +2489,7 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
|
|
|
memset(arg, 0, sizeof(*arg));
|
|
|
|
|
|
ath10k_peer_assoc_h_basic(ar, vif, sta, arg);
|
|
|
- ath10k_peer_assoc_h_crypto(ar, vif, arg);
|
|
|
+ ath10k_peer_assoc_h_crypto(ar, vif, sta, arg);
|
|
|
ath10k_peer_assoc_h_rates(ar, vif, sta, arg);
|
|
|
ath10k_peer_assoc_h_ht(ar, vif, sta, arg);
|
|
|
ath10k_peer_assoc_h_vht(ar, vif, sta, arg);
|
|
|
@@ -3112,35 +3122,11 @@ void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id,
|
|
|
spin_unlock_bh(&ar->htt.tx_lock);
|
|
|
}
|
|
|
|
|
|
-static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr)
|
|
|
-{
|
|
|
- if (ieee80211_is_mgmt(hdr->frame_control))
|
|
|
- return HTT_DATA_TX_EXT_TID_MGMT;
|
|
|
-
|
|
|
- if (!ieee80211_is_data_qos(hdr->frame_control))
|
|
|
- return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
|
|
|
-
|
|
|
- if (!is_unicast_ether_addr(ieee80211_get_DA(hdr)))
|
|
|
- return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
|
|
|
-
|
|
|
- return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
|
|
|
-}
|
|
|
-
|
|
|
-static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
|
|
|
-{
|
|
|
- if (vif)
|
|
|
- return ath10k_vif_to_arvif(vif)->vdev_id;
|
|
|
-
|
|
|
- if (ar->monitor_started)
|
|
|
- return ar->monitor_vdev_id;
|
|
|
-
|
|
|
- ath10k_warn(ar, "failed to resolve vdev id\n");
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static enum ath10k_hw_txrx_mode
|
|
|
-ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
|
|
|
- struct ieee80211_sta *sta, struct sk_buff *skb)
|
|
|
+ath10k_mac_tx_h_get_txmode(struct ath10k *ar,
|
|
|
+ struct ieee80211_vif *vif,
|
|
|
+ struct ieee80211_sta *sta,
|
|
|
+ struct sk_buff *skb)
|
|
|
{
|
|
|
const struct ieee80211_hdr *hdr = (void *)skb->data;
|
|
|
__le16 fc = hdr->frame_control;
|
|
|
@@ -3190,14 +3176,22 @@ ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
|
|
|
}
|
|
|
|
|
|
static bool ath10k_tx_h_use_hwcrypto(struct ieee80211_vif *vif,
|
|
|
- struct sk_buff *skb) {
|
|
|
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+ const struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
+ const struct ieee80211_hdr *hdr = (void *)skb->data;
|
|
|
const u32 mask = IEEE80211_TX_INTFL_DONT_ENCRYPT |
|
|
|
IEEE80211_TX_CTL_INJECTED;
|
|
|
+
|
|
|
+ if (!ieee80211_has_protected(hdr->frame_control))
|
|
|
+ return false;
|
|
|
+
|
|
|
if ((info->flags & mask) == mask)
|
|
|
return false;
|
|
|
+
|
|
|
if (vif)
|
|
|
return !ath10k_vif_to_arvif(vif)->nohwcrypt;
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -3224,7 +3218,7 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|
|
*/
|
|
|
hdr = (void *)skb->data;
|
|
|
if (ieee80211_is_qos_nullfunc(hdr->frame_control))
|
|
|
- cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
|
|
|
+ cb->flags &= ~ATH10K_SKB_F_QOS;
|
|
|
|
|
|
hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
|
|
}
|
|
|
@@ -3280,7 +3274,7 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
|
|
|
+bool ath10k_mac_tx_frm_has_freq(struct ath10k *ar)
|
|
|
{
|
|
|
/* FIXME: Not really sure since when the behaviour changed. At some
|
|
|
* point new firmware stopped requiring creation of peer entries for
|
|
|
@@ -3288,8 +3282,9 @@ static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
|
|
|
* tx credit replenishment and reliability). Assuming it's at least 3.4
|
|
|
* because that's when the `freq` was introduced to TX_FRM HTT command.
|
|
|
*/
|
|
|
- return !(ar->htt.target_version_major >= 3 &&
|
|
|
- ar->htt.target_version_minor >= 4);
|
|
|
+ return (ar->htt.target_version_major >= 3 &&
|
|
|
+ ar->htt.target_version_minor >= 4 &&
|
|
|
+ ar->htt.op_version == ATH10K_FW_HTT_OP_VERSION_TLV);
|
|
|
}
|
|
|
|
|
|
static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
|
|
|
@@ -3314,24 +3309,24 @@ unlock:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void ath10k_mac_tx(struct ath10k *ar, struct sk_buff *skb)
|
|
|
+static void ath10k_mac_tx(struct ath10k *ar, enum ath10k_hw_txrx_mode txmode,
|
|
|
+ struct sk_buff *skb)
|
|
|
{
|
|
|
- struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
|
|
|
struct ath10k_htt *htt = &ar->htt;
|
|
|
int ret = 0;
|
|
|
|
|
|
- switch (cb->txmode) {
|
|
|
+ switch (txmode) {
|
|
|
case ATH10K_HW_TXRX_RAW:
|
|
|
case ATH10K_HW_TXRX_NATIVE_WIFI:
|
|
|
case ATH10K_HW_TXRX_ETHERNET:
|
|
|
- ret = ath10k_htt_tx(htt, skb);
|
|
|
+ ret = ath10k_htt_tx(htt, txmode, skb);
|
|
|
break;
|
|
|
case ATH10K_HW_TXRX_MGMT:
|
|
|
if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
|
|
|
ar->fw_features))
|
|
|
ret = ath10k_mac_tx_wmi_mgmt(ar, skb);
|
|
|
else if (ar->htt.target_version_major >= 3)
|
|
|
- ret = ath10k_htt_tx(htt, skb);
|
|
|
+ ret = ath10k_htt_tx(htt, txmode, skb);
|
|
|
else
|
|
|
ret = ath10k_htt_mgmt_tx(htt, skb);
|
|
|
break;
|
|
|
@@ -3361,9 +3356,13 @@ void ath10k_offchan_tx_work(struct work_struct *work)
|
|
|
{
|
|
|
struct ath10k *ar = container_of(work, struct ath10k, offchan_tx_work);
|
|
|
struct ath10k_peer *peer;
|
|
|
+ struct ath10k_vif *arvif;
|
|
|
struct ieee80211_hdr *hdr;
|
|
|
+ struct ieee80211_vif *vif;
|
|
|
+ struct ieee80211_sta *sta;
|
|
|
struct sk_buff *skb;
|
|
|
const u8 *peer_addr;
|
|
|
+ enum ath10k_hw_txrx_mode txmode;
|
|
|
int vdev_id;
|
|
|
int ret;
|
|
|
unsigned long time_left;
|
|
|
@@ -3388,9 +3387,9 @@ void ath10k_offchan_tx_work(struct work_struct *work)
|
|
|
|
|
|
hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
peer_addr = ieee80211_get_DA(hdr);
|
|
|
- vdev_id = ATH10K_SKB_CB(skb)->vdev_id;
|
|
|
|
|
|
spin_lock_bh(&ar->data_lock);
|
|
|
+ vdev_id = ar->scan.vdev_id;
|
|
|
peer = ath10k_peer_find(ar, vdev_id, peer_addr);
|
|
|
spin_unlock_bh(&ar->data_lock);
|
|
|
|
|
|
@@ -3413,7 +3412,22 @@ void ath10k_offchan_tx_work(struct work_struct *work)
|
|
|
ar->offchan_tx_skb = skb;
|
|
|
spin_unlock_bh(&ar->data_lock);
|
|
|
|
|
|
- ath10k_mac_tx(ar, skb);
|
|
|
+ /* It's safe to access vif and sta - conf_mutex guarantees that
|
|
|
+ * sta_state() and remove_interface() are locked exclusively
|
|
|
+ * out wrt to this offchannel worker.
|
|
|
+ */
|
|
|
+ arvif = ath10k_get_arvif(ar, vdev_id);
|
|
|
+ if (arvif) {
|
|
|
+ vif = arvif->vif;
|
|
|
+ sta = ieee80211_find_sta(vif, peer_addr);
|
|
|
+ } else {
|
|
|
+ vif = NULL;
|
|
|
+ sta = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
|
|
|
+
|
|
|
+ ath10k_mac_tx(ar, txmode, skb);
|
|
|
|
|
|
time_left =
|
|
|
wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ);
|
|
|
@@ -3488,6 +3502,7 @@ void __ath10k_scan_finish(struct ath10k *ar)
|
|
|
case ATH10K_SCAN_STARTING:
|
|
|
ar->scan.state = ATH10K_SCAN_IDLE;
|
|
|
ar->scan_channel = NULL;
|
|
|
+ ar->scan.roc_freq = 0;
|
|
|
ath10k_offchan_tx_purge(ar);
|
|
|
cancel_delayed_work(&ar->scan.timeout);
|
|
|
complete_all(&ar->scan.completed);
|
|
|
@@ -3631,25 +3646,32 @@ static void ath10k_tx(struct ieee80211_hw *hw,
|
|
|
struct sk_buff *skb)
|
|
|
{
|
|
|
struct ath10k *ar = hw->priv;
|
|
|
+ struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
struct ieee80211_vif *vif = info->control.vif;
|
|
|
struct ieee80211_sta *sta = control->sta;
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
- __le16 fc = hdr->frame_control;
|
|
|
+ enum ath10k_hw_txrx_mode txmode;
|
|
|
|
|
|
/* We should disable CCK RATE due to P2P */
|
|
|
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
|
|
|
ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
|
|
|
|
|
|
- ATH10K_SKB_CB(skb)->htt.is_offchan = false;
|
|
|
- ATH10K_SKB_CB(skb)->htt.freq = 0;
|
|
|
- ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
|
|
|
- ATH10K_SKB_CB(skb)->htt.nohwcrypt = !ath10k_tx_h_use_hwcrypto(vif, skb);
|
|
|
- ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
|
|
|
- ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, sta, skb);
|
|
|
- ATH10K_SKB_CB(skb)->is_protected = ieee80211_has_protected(fc);
|
|
|
+ txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
|
|
|
+
|
|
|
+ skb_cb->flags = 0;
|
|
|
+ if (!ath10k_tx_h_use_hwcrypto(vif, skb))
|
|
|
+ skb_cb->flags |= ATH10K_SKB_F_NO_HWCRYPT;
|
|
|
+
|
|
|
+ if (ieee80211_is_mgmt(hdr->frame_control))
|
|
|
+ skb_cb->flags |= ATH10K_SKB_F_MGMT;
|
|
|
|
|
|
- switch (ATH10K_SKB_CB(skb)->txmode) {
|
|
|
+ if (ieee80211_is_data_qos(hdr->frame_control))
|
|
|
+ skb_cb->flags |= ATH10K_SKB_F_QOS;
|
|
|
+
|
|
|
+ skb_cb->vif = vif;
|
|
|
+
|
|
|
+ switch (txmode) {
|
|
|
case ATH10K_HW_TXRX_MGMT:
|
|
|
case ATH10K_HW_TXRX_NATIVE_WIFI:
|
|
|
ath10k_tx_h_nwifi(hw, skb);
|
|
|
@@ -3668,15 +3690,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
|
|
|
}
|
|
|
|
|
|
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
|
|
|
- spin_lock_bh(&ar->data_lock);
|
|
|
- ATH10K_SKB_CB(skb)->htt.freq = ar->scan.roc_freq;
|
|
|
- ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;
|
|
|
- spin_unlock_bh(&ar->data_lock);
|
|
|
-
|
|
|
- if (ath10k_mac_need_offchan_tx_work(ar)) {
|
|
|
- ATH10K_SKB_CB(skb)->htt.freq = 0;
|
|
|
- ATH10K_SKB_CB(skb)->htt.is_offchan = true;
|
|
|
-
|
|
|
+ if (!ath10k_mac_tx_frm_has_freq(ar)) {
|
|
|
ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
|
|
|
skb);
|
|
|
|
|
|
@@ -3686,7 +3700,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- ath10k_mac_tx(ar, skb);
|
|
|
+ ath10k_mac_tx(ar, txmode, skb);
|
|
|
}
|
|
|
|
|
|
/* Must not be called with conf_mutex held as workers can use that also. */
|
|
|
@@ -4350,7 +4364,9 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|
|
arvif->vdev_type = WMI_VDEV_TYPE_IBSS;
|
|
|
break;
|
|
|
case NL80211_IFTYPE_MESH_POINT:
|
|
|
- if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
|
|
|
+ if (test_bit(WMI_SERVICE_MESH, ar->wmi.svc_map)) {
|
|
|
+ arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH;
|
|
|
+ } else if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
|
|
|
ret = -EINVAL;
|
|
|
ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n");
|
|
|
goto err;
|
|
|
@@ -6907,35 +6923,39 @@ void ath10k_mac_destroy(struct ath10k *ar)
|
|
|
|
|
|
static const struct ieee80211_iface_limit ath10k_if_limits[] = {
|
|
|
{
|
|
|
- .max = 8,
|
|
|
- .types = BIT(NL80211_IFTYPE_STATION)
|
|
|
- | BIT(NL80211_IFTYPE_P2P_CLIENT)
|
|
|
+ .max = 8,
|
|
|
+ .types = BIT(NL80211_IFTYPE_STATION)
|
|
|
+ | BIT(NL80211_IFTYPE_P2P_CLIENT)
|
|
|
},
|
|
|
{
|
|
|
- .max = 3,
|
|
|
- .types = BIT(NL80211_IFTYPE_P2P_GO)
|
|
|
+ .max = 3,
|
|
|
+ .types = BIT(NL80211_IFTYPE_P2P_GO)
|
|
|
},
|
|
|
{
|
|
|
- .max = 1,
|
|
|
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
|
|
|
+ .max = 1,
|
|
|
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
|
|
|
},
|
|
|
{
|
|
|
- .max = 7,
|
|
|
- .types = BIT(NL80211_IFTYPE_AP)
|
|
|
+ .max = 7,
|
|
|
+ .types = BIT(NL80211_IFTYPE_AP)
|
|
|
#ifdef CONFIG_MAC80211_MESH
|
|
|
- | BIT(NL80211_IFTYPE_MESH_POINT)
|
|
|
+ | BIT(NL80211_IFTYPE_MESH_POINT)
|
|
|
#endif
|
|
|
},
|
|
|
};
|
|
|
|
|
|
static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
|
|
|
{
|
|
|
- .max = 8,
|
|
|
- .types = BIT(NL80211_IFTYPE_AP)
|
|
|
+ .max = 8,
|
|
|
+ .types = BIT(NL80211_IFTYPE_AP)
|
|
|
#ifdef CONFIG_MAC80211_MESH
|
|
|
- | BIT(NL80211_IFTYPE_MESH_POINT)
|
|
|
+ | BIT(NL80211_IFTYPE_MESH_POINT)
|
|
|
#endif
|
|
|
},
|
|
|
+ {
|
|
|
+ .max = 1,
|
|
|
+ .types = BIT(NL80211_IFTYPE_STATION)
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static const struct ieee80211_iface_combination ath10k_if_comb[] = {
|