#include "wmi.h"
#include "htt.h"
#include "txrx.h"
+#include "testmode.h"
/**********/
/* Crypto */
list_for_each_entry(peer, &ar->peers, list) {
for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
if (peer->keys[i] == key) {
- memcpy(addr, peer->addr, ETH_ALEN);
+ ether_addr_copy(addr, peer->addr);
peer->keys[i] = NULL;
break;
}
return first_errno;
}
-
/*********************/
/* General utilities */
/*********************/
/* Interface management */
/************************/
+void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ if (!arvif->beacon)
+ return;
+
+ if (!arvif->beacon_buf)
+ dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr,
+ arvif->beacon->len, DMA_TO_DEVICE);
+
+ dev_kfree_skb_any(arvif->beacon);
+
+ arvif->beacon = NULL;
+ arvif->beacon_sent = false;
+}
+
+static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ ath10k_mac_vif_beacon_free(arvif);
+
+ if (arvif->beacon_buf) {
+ dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+ arvif->beacon_buf, arvif->beacon_paddr);
+ arvif->beacon_buf = NULL;
+ }
+}
+
static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
{
int ret;
return 0;
}
-static bool ath10k_monitor_is_enabled(struct ath10k *ar)
-{
- lockdep_assert_held(&ar->conf_mutex);
-
- ath10k_dbg(ar, ATH10K_DBG_MAC,
- "mac monitor refs: promisc %d monitor %d cac %d\n",
- ar->promisc, ar->monitor,
- test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags));
-
- return ar->promisc || ar->monitor ||
- test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
-}
-
static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
{
struct cfg80211_chan_def *chandef = &ar->chandef;
return -ENOMEM;
}
- bit = ffs(ar->free_vdev_map);
+ bit = __ffs64(ar->free_vdev_map);
- ar->monitor_vdev_id = bit - 1;
+ ar->monitor_vdev_id = bit;
ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id,
WMI_VDEV_TYPE_MONITOR,
return ret;
}
- ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
+ ar->free_vdev_map &= ~(1LL << ar->monitor_vdev_id);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
ar->monitor_vdev_id);
return ret;
}
- ar->free_vdev_map |= 1 << ar->monitor_vdev_id;
+ ar->free_vdev_map |= 1LL << ar->monitor_vdev_id;
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
ar->monitor_vdev_id);
lockdep_assert_held(&ar->conf_mutex);
- if (!ath10k_monitor_is_enabled(ar)) {
- ath10k_warn(ar, "trying to start monitor with no references\n");
- return 0;
- }
-
- if (ar->monitor_started) {
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor already started\n");
- return 0;
- }
-
ret = ath10k_monitor_vdev_create(ar);
if (ret) {
ath10k_warn(ar, "failed to create monitor vdev: %d\n", ret);
return 0;
}
-static void ath10k_monitor_stop(struct ath10k *ar)
+static int ath10k_monitor_stop(struct ath10k *ar)
{
int ret;
lockdep_assert_held(&ar->conf_mutex);
- if (ath10k_monitor_is_enabled(ar)) {
- ath10k_dbg(ar, ATH10K_DBG_MAC,
- "mac monitor will be stopped later\n");
- return;
- }
-
- if (!ar->monitor_started) {
- ath10k_dbg(ar, ATH10K_DBG_MAC,
- "mac monitor probably failed to start earlier\n");
- return;
- }
-
ret = ath10k_monitor_vdev_stop(ar);
- if (ret)
+ if (ret) {
ath10k_warn(ar, "failed to stop monitor vdev: %d\n", ret);
+ return ret;
+ }
ret = ath10k_monitor_vdev_delete(ar);
- if (ret)
+ if (ret) {
ath10k_warn(ar, "failed to delete monitor vdev: %d\n", ret);
+ return ret;
+ }
ar->monitor_started = false;
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopped\n");
+
+ return 0;
+}
+
+static int ath10k_monitor_recalc(struct ath10k *ar)
+{
+ bool should_start;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ should_start = ar->monitor ||
+ ar->filter_flags & FIF_PROMISC_IN_BSS ||
+ test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac monitor recalc started? %d should? %d\n",
+ ar->monitor_started, should_start);
+
+ if (should_start == ar->monitor_started)
+ return 0;
+
+ if (should_start)
+ return ath10k_monitor_start(ar);
+
+ return ath10k_monitor_stop(ar);
}
static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
- ret = ath10k_monitor_start(ar);
+ ret = ath10k_monitor_recalc(ar);
if (ret) {
ath10k_warn(ar, "failed to start monitor (cac): %d\n", ret);
clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
}
static void ath10k_control_beaconing(struct ath10k_vif *arvif,
- struct ieee80211_bss_conf *info)
+ struct ieee80211_bss_conf *info)
{
struct ath10k *ar = arvif->ar;
int ret = 0;
arvif->is_up = false;
spin_lock_bh(&arvif->ar->data_lock);
- if (arvif->beacon) {
- dma_unmap_single(arvif->ar->dev,
- ATH10K_SKB_CB(arvif->beacon)->paddr,
- arvif->beacon->len, DMA_TO_DEVICE);
- dev_kfree_skb_any(arvif->beacon);
-
- arvif->beacon = NULL;
- arvif->beacon_sent = false;
- }
+ ath10k_mac_vif_beacon_free(arvif);
spin_unlock_bh(&arvif->ar->data_lock);
return;
return;
arvif->aid = 0;
- memcpy(arvif->bssid, info->bssid, ETH_ALEN);
+ ether_addr_copy(arvif->bssid, info->bssid);
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid);
if (is_zero_ether_addr(arvif->bssid))
return;
- ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
- arvif->bssid);
- if (ret) {
- ath10k_warn(ar, "failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
- arvif->bssid, arvif->vdev_id, ret);
- return;
- }
-
memset(arvif->bssid, 0, ETH_ALEN);
return;
/* Station management */
/**********************/
+static u32 ath10k_peer_assoc_h_listen_intval(struct ath10k *ar,
+ struct ieee80211_vif *vif)
+{
+ /* Some firmware revisions have unstable STA powersave when listen
+ * interval is set too high (e.g. 5). The symptoms are firmware doesn't
+ * generate NullFunc frames properly even if buffered frames have been
+ * indicated in Beacon TIM. Firmware would seldom wake up to pull
+ * buffered frames. Often pinging the device from AP would simply fail.
+ *
+ * As a workaround set it to 1.
+ */
+ if (vif->type == NL80211_IFTYPE_STATION)
+ return 1;
+
+ return ar->hw->conf.listen_interval;
+}
+
static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
- struct ath10k_vif *arvif,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct ieee80211_bss_conf *bss_conf,
struct wmi_peer_assoc_complete_arg *arg)
{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
lockdep_assert_held(&ar->conf_mutex);
- memcpy(arg->addr, sta->addr, ETH_ALEN);
+ ether_addr_copy(arg->addr, sta->addr);
arg->vdev_id = arvif->vdev_id;
arg->peer_aid = sta->aid;
arg->peer_flags |= WMI_PEER_AUTH;
-
- if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
- /*
- * Seems FW have problems with Power Save in STA
- * mode when we setup this parameter to high (eg. 5).
- * Often we see that FW don't send NULL (with clean P flags)
- * frame even there is info about buffered frames in beacons.
- * Sometimes we have to wait more than 10 seconds before FW
- * will wakeup. Often sending one ping from AP to our device
- * just fail (more than 50%).
- *
- * Seems setting this FW parameter to 1 couse FW
- * will check every beacon and will wakup immediately
- * after detection buffered data.
- */
- arg->peer_listen_intval = 1;
- else
- arg->peer_listen_intval = ar->hw->conf.listen_interval;
-
+ arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif);
arg->peer_num_spatial_streams = 1;
-
- /*
- * The assoc capabilities are available only in managed mode.
- */
- if (arvif->vdev_type == WMI_VDEV_TYPE_STA && bss_conf)
- arg->peer_caps = bss_conf->assoc_capability;
+ arg->peer_caps = vif->bss_conf.assoc_capability;
}
static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
- struct ath10k_vif *arvif,
+ struct ieee80211_vif *vif,
struct wmi_peer_assoc_complete_arg *arg)
{
- struct ieee80211_vif *vif = arvif->vif;
struct ieee80211_bss_conf *info = &vif->bss_conf;
struct cfg80211_bss *bss;
const u8 *rsnie = NULL;
ies = rcu_dereference(bss->ies);
wpaie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
- WLAN_OUI_TYPE_MICROSOFT_WPA,
- ies->data,
- ies->len);
+ WLAN_OUI_TYPE_MICROSOFT_WPA,
+ ies->data,
+ ies->len);
rcu_read_unlock();
cfg80211_put_bss(ar->hw->wiphy, bss);
}
{
const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
int i, n;
+ u32 stbc;
lockdep_assert_held(&ar->conf_mutex);
}
if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) {
- u32 stbc;
stbc = ht_cap->cap & IEEE80211_HT_CAP_RX_STBC;
stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT;
stbc = stbc << WMI_RC_RX_STBC_FLAG_S;
uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN |
WMI_AP_PS_UAPSD_AC0_TRIGGER_EN;
-
if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)
max_sp = sta->max_sp;
sta->listen_interval - mac80211 patch required.
Currently use 10 seconds */
ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr,
- WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10);
+ WMI_AP_PS_PEER_PARAM_AGEOUT_TIME,
+ 10);
if (ret) {
ath10k_warn(ar, "failed to set ap ps peer param ageout time for vdev %i: %d\n",
arvif->vdev_id, ret);
arg->peer_flags |= WMI_PEER_VHT;
arg->peer_vht_caps = vht_cap->cap;
-
ampdu_factor = (vht_cap->cap &
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
}
static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
- struct ath10k_vif *arvif,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct ieee80211_bss_conf *bss_conf,
struct wmi_peer_assoc_complete_arg *arg)
{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
switch (arvif->vdev_type) {
case WMI_VDEV_TYPE_AP:
if (sta->wme)
}
break;
case WMI_VDEV_TYPE_STA:
- if (bss_conf->qos)
+ if (vif->bss_conf.qos)
arg->peer_flags |= WMI_PEER_QOS;
break;
default:
}
static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
- struct ath10k_vif *arvif,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg)
{
}
static int ath10k_peer_assoc_prepare(struct ath10k *ar,
- struct ath10k_vif *arvif,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct ieee80211_bss_conf *bss_conf,
struct wmi_peer_assoc_complete_arg *arg)
{
lockdep_assert_held(&ar->conf_mutex);
memset(arg, 0, sizeof(*arg));
- ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, arg);
- ath10k_peer_assoc_h_crypto(ar, arvif, arg);
+ ath10k_peer_assoc_h_basic(ar, vif, sta, arg);
+ ath10k_peer_assoc_h_crypto(ar, vif, arg);
ath10k_peer_assoc_h_rates(ar, sta, arg);
ath10k_peer_assoc_h_ht(ar, sta, arg);
ath10k_peer_assoc_h_vht(ar, sta, arg);
- ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, arg);
- ath10k_peer_assoc_h_phymode(ar, arvif, sta, arg);
+ ath10k_peer_assoc_h_qos(ar, vif, sta, arg);
+ ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
return 0;
}
* before calling ath10k_setup_peer_smps() which might sleep. */
ht_cap = ap_sta->ht_cap;
- ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
- bss_conf, &peer_arg);
+ ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg);
if (ret) {
ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n",
bss_conf->bssid, arvif->vdev_id, ret);
arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
arvif->aid = bss_conf->aid;
- memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN);
+ ether_addr_copy(arvif->bssid, bss_conf->bssid);
ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
if (ret) {
arvif->is_up = false;
}
-static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
- struct ieee80211_sta *sta, bool reassoc)
+static int ath10k_station_assoc(struct ath10k *ar,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ bool reassoc)
{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct wmi_peer_assoc_complete_arg peer_arg;
int ret = 0;
lockdep_assert_held(&ar->conf_mutex);
- ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
+ ret = ath10k_peer_assoc_prepare(ar, vif, sta, &peer_arg);
if (ret) {
ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
return ret;
}
-static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
+static int ath10k_station_disassoc(struct ath10k *ar,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
int ret = 0;
lockdep_assert_held(&ar->conf_mutex);
ch->passive = passive;
ch->freq = channel->center_freq;
+ ch->band_center_freq1 = channel->center_freq;
ch->min_power = 0;
ch->max_power = channel->max_power * 2;
ch->max_reg_power = channel->max_reg_power * 2;
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_tx_info *info)
+static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
{
- if (info->control.vif)
- return ath10k_vif_to_arvif(info->control.vif)->vdev_id;
+ if (vif)
+ return ath10k_vif_to_arvif(vif)->vdev_id;
if (ar->monitor_started)
return ar->monitor_vdev_id;
ATH10K_SKB_CB(skb)->htt.is_offchan = false;
ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
- ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, info);
+ ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
/* it makes no sense to process injected frames like that */
if (vif && vif->type != NL80211_IFTYPE_MONITOR) {
lockdep_assert_held(&ar->conf_mutex);
- if (ath10k_monitor_is_enabled(ar)) {
- clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
- ar->promisc = false;
- ar->monitor = false;
+ clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+ ar->filter_flags = 0;
+ ar->monitor = false;
+
+ if (ar->monitor_started)
ath10k_monitor_stop(ar);
- }
+
+ ar->monitor_started = false;
ath10k_scan_finish(ar);
ath10k_peer_cleanup_all(ar);
ath10k_hif_power_down(ar);
spin_lock_bh(&ar->data_lock);
- list_for_each_entry(arvif, &ar->arvifs, list) {
- if (!arvif->beacon)
- continue;
-
- dma_unmap_single(arvif->ar->dev,
- ATH10K_SKB_CB(arvif->beacon)->paddr,
- arvif->beacon->len, DMA_TO_DEVICE);
- dev_kfree_skb_any(arvif->beacon);
- arvif->beacon = NULL;
- }
+ list_for_each_entry(arvif, &ar->arvifs, list)
+ ath10k_mac_vif_beacon_cleanup(arvif);
spin_unlock_bh(&ar->data_lock);
}
WARN_ON(1);
ret = -EINVAL;
goto err;
+ case ATH10K_STATE_UTF:
+ ret = -EBUSY;
+ goto err;
}
ret = ath10k_hif_power_up(ar);
goto err_off;
}
- ret = ath10k_core_start(ar);
+ ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
if (ret) {
ath10k_err(ar, "Could not init core: %d\n", ret);
goto err_power_down;
/* First stop monitor interface. Some FW versions crash if there's a
* lone monitor interface. */
if (ar->monitor_started)
- ath10k_monitor_vdev_stop(ar);
+ ath10k_monitor_stop(ar);
list_for_each_entry(arvif, &ar->arvifs, list) {
if (!arvif->is_started)
}
}
- if (ath10k_monitor_is_enabled(ar))
- ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);
+ ath10k_monitor_recalc(ar);
}
static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
ath10k_config_ps(ar);
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
- if (conf->flags & IEEE80211_CONF_MONITOR && !ar->monitor) {
- ar->monitor = true;
- ret = ath10k_monitor_start(ar);
- if (ret) {
- ath10k_warn(ar, "failed to start monitor (config): %d\n",
- ret);
- ar->monitor = false;
- }
- } else if (!(conf->flags & IEEE80211_CONF_MONITOR) &&
- ar->monitor) {
- ar->monitor = false;
- ath10k_monitor_stop(ar);
- }
+ ar->monitor = conf->flags & IEEE80211_CONF_MONITOR;
+ ret = ath10k_monitor_recalc(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to recalc monitor: %d\n", ret);
}
mutex_unlock(&ar->conf_mutex);
ret = -EBUSY;
goto err;
}
- bit = ffs(ar->free_vdev_map);
+ bit = __ffs64(ar->free_vdev_map);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac create vdev %i map %llx\n",
+ bit, ar->free_vdev_map);
- arvif->vdev_id = bit - 1;
+ arvif->vdev_id = bit;
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
if (ar->p2p)
break;
}
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
- arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype);
+ /* Some firmware revisions don't wait for beacon tx completion before
+ * sending another SWBA event. This could lead to hardware using old
+ * (freed) beacon data in some cases, e.g. tx credit starvation
+ * combined with missed TBTT. This is very very rare.
+ *
+ * On non-IOMMU-enabled hosts this could be a possible security issue
+ * because hw could beacon some random data on the air. On
+ * IOMMU-enabled hosts DMAR faults would occur in most cases and target
+ * device would crash.
+ *
+ * Since there are no beacon tx completions (implicit nor explicit)
+ * propagated to host the only workaround for this is to allocate a
+ * DMA-coherent buffer for a lifetime of a vif and use it for all
+ * beacon tx commands. Worst case for this approach is some beacons may
+ * become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap.
+ */
+ if (vif->type == NL80211_IFTYPE_ADHOC ||
+ vif->type == NL80211_IFTYPE_AP) {
+ arvif->beacon_buf = dma_zalloc_coherent(ar->dev,
+ IEEE80211_MAX_FRAME_LEN,
+ &arvif->beacon_paddr,
+ GFP_ATOMIC);
+ if (!arvif->beacon_buf) {
+ ret = -ENOMEM;
+ ath10k_warn(ar, "failed to allocate beacon buffer: %d\n",
+ ret);
+ goto err;
+ }
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d bcnmode %s\n",
+ arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
+ arvif->beacon_buf ? "single-buf" : "per-skb");
ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
arvif->vdev_subtype, vif->addr);
goto err;
}
- ar->free_vdev_map &= ~(1 << arvif->vdev_id);
+ ar->free_vdev_map &= ~(1LL << arvif->vdev_id);
list_add(&arvif->list, &ar->arvifs);
vdev_param = ar->wmi.vdev_param->def_keyid;
err_vdev_delete:
ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
- ar->free_vdev_map |= 1 << arvif->vdev_id;
+ ar->free_vdev_map |= 1LL << arvif->vdev_id;
list_del(&arvif->list);
err:
+ if (arvif->beacon_buf) {
+ dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+ arvif->beacon_buf, arvif->beacon_paddr);
+ arvif->beacon_buf = NULL;
+ }
+
mutex_unlock(&ar->conf_mutex);
return ret;
cancel_work_sync(&arvif->wep_key_work);
spin_lock_bh(&ar->data_lock);
- if (arvif->beacon) {
- dma_unmap_single(arvif->ar->dev,
- ATH10K_SKB_CB(arvif->beacon)->paddr,
- arvif->beacon->len, DMA_TO_DEVICE);
- dev_kfree_skb_any(arvif->beacon);
- arvif->beacon = NULL;
- }
-
+ ath10k_mac_vif_beacon_cleanup(arvif);
spin_unlock_bh(&ar->data_lock);
ret = ath10k_spectral_vif_stop(arvif);
ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n",
arvif->vdev_id, ret);
- ar->free_vdev_map |= 1 << arvif->vdev_id;
+ ar->free_vdev_map |= 1LL << arvif->vdev_id;
list_del(&arvif->list);
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
*total_flags &= SUPPORTED_FILTERS;
ar->filter_flags = *total_flags;
- if (ar->filter_flags & FIF_PROMISC_IN_BSS && !ar->promisc) {
- ar->promisc = true;
- ret = ath10k_monitor_start(ar);
- if (ret) {
- ath10k_warn(ar, "failed to start monitor (promisc): %d\n",
- ret);
- ar->promisc = false;
- }
- } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && ar->promisc) {
- ar->promisc = false;
- ath10k_monitor_stop(ar);
- }
+ ret = ath10k_monitor_recalc(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to recalc montior: %d\n", ret);
mutex_unlock(&ar->conf_mutex);
}
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
int ret = 0;
- u32 vdev_param, pdev_param;
+ u32 vdev_param, pdev_param, slottime, preamble;
mutex_lock(&ar->conf_mutex);
if (changed & BSS_CHANGED_BSSID &&
vif->type != NL80211_IFTYPE_AP) {
if (!is_zero_ether_addr(info->bssid)) {
- ath10k_dbg(ar, ATH10K_DBG_MAC,
- "mac vdev %d create peer %pM\n",
- arvif->vdev_id, info->bssid);
-
- ret = ath10k_peer_create(ar, arvif->vdev_id,
- info->bssid);
- if (ret)
- ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n",
- info->bssid, arvif->vdev_id, ret);
-
if (vif->type == NL80211_IFTYPE_STATION) {
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac vdev %d create peer %pM\n",
+ arvif->vdev_id, info->bssid);
+
+ ret = ath10k_peer_create(ar, arvif->vdev_id,
+ info->bssid);
+ if (ret)
+ ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n",
+ info->bssid, arvif->vdev_id,
+ ret);
/*
* this is never erased as we it for crypto key
* clearing; this is FW requirement
*/
- memcpy(arvif->bssid, info->bssid, ETH_ALEN);
+ ether_addr_copy(arvif->bssid, info->bssid);
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d start %pM\n",
}
if (changed & BSS_CHANGED_ERP_SLOT) {
- u32 slottime;
if (info->use_short_slot)
slottime = WMI_VDEV_SLOT_TIME_SHORT; /* 9us */
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
- u32 preamble;
if (info->use_short_preamble)
preamble = WMI_VDEV_PREAMBLE_SHORT;
else
}
if (changed & BSS_CHANGED_ASSOC) {
- if (info->assoc)
+ if (info->assoc) {
+ /* Workaround: Make sure monitor vdev is not running
+ * when associating to prevent some firmware revisions
+ * (e.g. 10.1 and 10.2) from crashing.
+ */
+ if (ar->monitor_started)
+ ath10k_monitor_stop(ar);
ath10k_bss_assoc(hw, vif, info);
+ ath10k_monitor_recalc(ar);
+ }
}
exit:
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
sta->addr);
- err = ath10k_station_assoc(ar, arvif, sta, true);
+ err = ath10k_station_assoc(ar, arvif->vif, sta, true);
if (err)
ath10k_warn(ar, "failed to reassociate station: %pM\n",
sta->addr);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n",
sta->addr);
- ret = ath10k_station_assoc(ar, arvif, sta, false);
+ ret = ath10k_station_assoc(ar, vif, sta, false);
if (ret)
ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
sta->addr);
- ret = ath10k_station_disassoc(ar, arvif, sta);
+ ret = ath10k_station_disassoc(ar, vif, sta);
if (ret)
ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
}
static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
- u16 ac, bool enable)
+ u16 ac, bool enable)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
u32 value = 0;
continue;
else if (mask->control[band].ht_mcs[i] == 0x00)
break;
- else
- return false;
+
+ return false;
}
ht_nss = i;
continue;
else if (mask->control[band].vht_mcs[i] == 0x0000)
break;
- else
- return false;
+
+ return false;
}
vht_nss = i;
.sta_rc_update = ath10k_sta_rc_update,
.get_tsf = ath10k_get_tsf,
.ampdu_action = ath10k_ampdu_action,
+ .get_et_sset_count = ath10k_debug_get_et_sset_count,
+ .get_et_stats = ath10k_debug_get_et_stats,
+ .get_et_strings = ath10k_debug_get_et_strings,
+
+ CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
+
#ifdef CONFIG_PM
.suspend = ath10k_suspend,
.resume = ath10k_resume,
return ht_cap;
}
-
static void ath10k_get_arvif_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP);
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- /* TODO: Have to deal with 2x2 chips if/when the come out. */
- ar->supp_tx_chainmask = TARGET_10X_TX_CHAIN_MASK;
- ar->supp_rx_chainmask = TARGET_10X_RX_CHAIN_MASK;
- } else {
- ar->supp_tx_chainmask = TARGET_TX_CHAIN_MASK;
- ar->supp_rx_chainmask = TARGET_RX_CHAIN_MASK;
- }
-
ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask;
ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask;