Commit 843dc664 authored by John W. Linville's avatar John W. Linville
Browse files

Merge branch 'for-linville' of git://github.com/kvalo/ath6kl

parents 5d6a1b06 9df2a0b7
#------------------------------------------------------------------------------
# Copyright (c) 2004-2010 Atheros Communications Inc.
# Copyright (c) 2004-2011 Atheros Communications Inc.
# Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
# All rights reserved.
#
#
......
/*
* Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
......@@ -105,7 +106,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
}
ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n",
targ_info->version, targ_info->type);
targ_info->version, targ_info->type);
return 0;
}
......@@ -192,7 +193,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header);
ath6kl_dbg(ATH6KL_DBG_BMI,
"bmi write memory: addr: 0x%x, len: %d\n", addr, len);
"bmi write memory: addr: 0x%x, len: %d\n", addr, len);
len_remain = len;
while (len_remain) {
......@@ -434,7 +435,7 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
offset += sizeof(tx_len);
memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain],
tx_len);
tx_len);
offset += tx_len;
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
......
/*
* Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
......@@ -222,6 +223,29 @@ struct ath6kl_bmi_target_info {
__le32 type; /* target type */
} __packed;
#define ath6kl_bmi_write_hi32(ar, item, val) \
({ \
u32 addr; \
__le32 v; \
\
addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \
v = cpu_to_le32(val); \
ath6kl_bmi_write(ar, addr, (u8 *) &v, sizeof(v)); \
})
#define ath6kl_bmi_read_hi32(ar, item, val) \
({ \
u32 addr, *check_type = val; \
__le32 tmp; \
int ret; \
\
(void) (check_type == val); \
addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \
ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4); \
*val = le32_to_cpu(tmp); \
ret; \
})
int ath6kl_bmi_init(struct ath6kl *ar);
void ath6kl_bmi_cleanup(struct ath6kl *ar);
void ath6kl_bmi_reset(struct ath6kl *ar);
......
/*
* Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
......@@ -68,6 +69,10 @@ static struct ieee80211_rate ath6kl_rates[] = {
#define ath6kl_g_rates (ath6kl_rates + 0)
#define ath6kl_g_rates_size 12
#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
IEEE80211_HT_CAP_SGI_20 | \
IEEE80211_HT_CAP_SGI_40)
static struct ieee80211_channel ath6kl_2ghz_channels[] = {
CHAN2G(1, 2412, 0),
CHAN2G(2, 2417, 0),
......@@ -112,6 +117,8 @@ static struct ieee80211_supported_band ath6kl_band_2ghz = {
.channels = ath6kl_2ghz_channels,
.n_bitrates = ath6kl_g_rates_size,
.bitrates = ath6kl_g_rates,
.ht_cap.cap = ath6kl_g_htcap,
.ht_cap.ht_supported = true,
};
static struct ieee80211_supported_band ath6kl_band_5ghz = {
......@@ -119,6 +126,8 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = {
.channels = ath6kl_5ghz_a_channels,
.n_bitrates = ath6kl_a_rates_size,
.bitrates = ath6kl_a_rates,
.ht_cap.cap = ath6kl_g_htcap,
.ht_cap.ht_supported = true,
};
#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
......@@ -381,7 +390,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
return false;
if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
ar->num_vif))
ar->num_vif))
return false;
if (type == NL80211_IFTYPE_STATION ||
......@@ -407,6 +416,12 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
return false;
}
static bool ath6kl_is_tx_pending(struct ath6kl *ar)
{
return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0;
}
static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme)
{
......@@ -414,6 +429,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct ath6kl_vif *vif = netdev_priv(dev);
int status;
u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
u16 interval;
ath6kl_cfg80211_sscan_disable(vif);
......@@ -450,8 +466,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
* sleep until the command queue drains
*/
wait_event_interruptible_timeout(ar->event_wq,
ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
WMI_TIMEOUT);
ath6kl_is_tx_pending(ar),
WMI_TIMEOUT);
if (signal_pending(current)) {
ath6kl_err("cmd queue drain timeout\n");
up(&ar->sem);
......@@ -546,7 +562,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
if (!ar->usr_bss_filter) {
clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
ALL_BSS_FILTER, 0) != 0) {
ALL_BSS_FILTER, 0) != 0) {
ath6kl_err("couldn't set bss filtering\n");
up(&ar->sem);
return -EIO;
......@@ -568,6 +584,20 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
vif->grp_crypto_len, vif->ch_hint);
vif->reconnect_flag = 0;
if (vif->nw_type == INFRA_NETWORK) {
interval = max_t(u16, vif->listen_intvl_t,
ATH6KL_MAX_WOW_LISTEN_INTL);
status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
interval,
0);
if (status) {
ath6kl_err("couldn't set listen intervel\n");
up(&ar->sem);
return status;
}
}
status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
vif->dot11_auth_mode, vif->auth_mode,
vif->prwise_crypto,
......@@ -590,8 +620,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
}
if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
((vif->auth_mode == WPA_PSK_AUTH)
|| (vif->auth_mode == WPA2_PSK_AUTH))) {
((vif->auth_mode == WPA_PSK_AUTH) ||
(vif->auth_mode == WPA2_PSK_AUTH))) {
mod_timer(&vif->disconnect_timer,
jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
}
......@@ -824,13 +854,13 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
if (vif->sme_state == SME_CONNECTING) {
cfg80211_connect_result(vif->ndev,
bssid, NULL, 0,
NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
bssid, NULL, 0,
NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
} else if (vif->sme_state == SME_CONNECTED) {
cfg80211_disconnected(vif->ndev, reason,
NULL, 0, GFP_KERNEL);
NULL, 0, GFP_KERNEL);
}
vif->sme_state = SME_DISCONNECTED;
......@@ -876,19 +906,14 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
request->ssids[i].ssid);
}
/*
* FIXME: we should clear the IE in fw if it's not set so just
* remove the check altogether
*/
if (request->ie) {
ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_PROBE_REQ,
request->ie, request->ie_len);
if (ret) {
ath6kl_err("failed to set Probe Request appie for "
"scan");
return ret;
}
/* this also clears IE in fw if it's not set */
ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_PROBE_REQ,
request->ie, request->ie_len);
if (ret) {
ath6kl_err("failed to set Probe Request appie for "
"scan");
return ret;
}
/*
......@@ -917,7 +942,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
force_fg_scan = 1;
if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
ar->fw_capabilities)) {
ar->fw_capabilities)) {
/*
* If capable of doing P2P mgmt operations using
* station interface, send additional information like
......@@ -926,14 +951,17 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
*/
ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
WMI_LONG_SCAN, force_fg_scan,
false, 0, 0, n_channels,
channels, request->no_cck,
false, 0,
ATH6KL_FG_SCAN_INTERVAL,
n_channels, channels,
request->no_cck,
request->rates);
} else {
ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
WMI_LONG_SCAN, force_fg_scan,
false, 0, 0, n_channels,
channels);
false, 0,
ATH6KL_FG_SCAN_INTERVAL,
n_channels, channels);
}
if (ret)
ath6kl_err("wmi_startscan_cmd failed\n");
......@@ -1046,9 +1074,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
return -ENOTSUPP;
}
if (((vif->auth_mode == WPA_PSK_AUTH)
|| (vif->auth_mode == WPA2_PSK_AUTH))
&& (key_usage & GROUP_USAGE))
if (((vif->auth_mode == WPA_PSK_AUTH) ||
(vif->auth_mode == WPA2_PSK_AUTH)) &&
(key_usage & GROUP_USAGE))
del_timer(&vif->disconnect_timer);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
......@@ -1058,7 +1086,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
if (vif->nw_type == AP_NETWORK && !pairwise &&
(key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
key_type == WAPI_CRYPT) && params) {
key_type == WAPI_CRYPT)) {
ar->ap_mode_bkey.valid = true;
ar->ap_mode_bkey.key_index = key_index;
ar->ap_mode_bkey.key_type = key_type;
......@@ -1263,7 +1291,6 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
{
struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
struct ath6kl_vif *vif;
u8 ath6kl_dbm;
int dbm = MBM_TO_DBM(mbm);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
......@@ -1280,7 +1307,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
case NL80211_TX_POWER_AUTOMATIC:
return 0;
case NL80211_TX_POWER_LIMITED:
ar->tx_pwr = ath6kl_dbm = dbm;
ar->tx_pwr = dbm;
break;
default:
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
......@@ -1288,7 +1315,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
return -EOPNOTSUPP;
}
ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm);
return 0;
}
......@@ -1349,7 +1376,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
}
if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
mode.pwr_mode) != 0) {
mode.pwr_mode) != 0) {
ath6kl_err("wmi_powermode_cmd failed\n");
return -EIO;
}
......@@ -1904,7 +1931,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
struct ath6kl_vif *vif;
int ret, left;
u32 filter = 0;
u16 i;
u16 i, bmiss_time;
u8 index = 0;
__be32 ips[MAX_IP_ADDRS];
......@@ -1941,6 +1968,34 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
if (ret)
return ret;
netif_stop_queue(vif->ndev);
if (vif->nw_type != AP_NETWORK) {
ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_MAX_WOW_LISTEN_INTL,
0);
if (ret)
return ret;
/* Set listen interval x 15 times as bmiss time */
bmiss_time = ATH6KL_MAX_WOW_LISTEN_INTL * 15;
if (bmiss_time > ATH6KL_MAX_BMISS_TIME)
bmiss_time = ATH6KL_MAX_BMISS_TIME;
ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
bmiss_time, 0);
if (ret)
return ret;
ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
0xFFFF, 0, 0xFFFF, 0, 0, 0,
0, 0, 0, 0);
if (ret)
return ret;
}
ar->state = ATH6KL_STATE_SUSPENDING;
/* Setup own IP addr for ARP agent. */
in_dev = __in_dev_get_rtnl(vif->ndev);
if (!in_dev)
......@@ -2019,15 +2074,46 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
if (!vif)
return -EIO;
ar->state = ATH6KL_STATE_RESUMING;
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_AWAKE);
return ret;
if (ret) {
ath6kl_warn("Failed to configure host sleep mode for "
"wow resume: %d\n", ret);
ar->state = ATH6KL_STATE_WOW;
return ret;
}
if (vif->nw_type != AP_NETWORK) {
ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
if (ret)
return ret;
ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
vif->listen_intvl_t, 0);
if (ret)
return ret;
ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
vif->bmiss_time_t, 0);
if (ret)
return ret;
}
ar->state = ATH6KL_STATE_ON;
netif_wake_queue(vif->ndev);
return 0;
}
int ath6kl_cfg80211_suspend(struct ath6kl *ar,
enum ath6kl_cfg_suspend_mode mode,
struct cfg80211_wowlan *wow)
{
enum ath6kl_state prev_state;
int ret;
switch (mode) {
......@@ -2038,11 +2124,14 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
/* Flush all non control pkts in TX path */
ath6kl_tx_data_cleanup(ar);
prev_state = ar->state;
ret = ath6kl_wow_suspend(ar, wow);
if (ret) {
ath6kl_err("wow suspend failed: %d\n", ret);
ar->state = prev_state;
return ret;
}
ar->state = ATH6KL_STATE_WOW;
break;
......@@ -2114,7 +2203,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
return ret;
}
ar->state = ATH6KL_STATE_ON;
break;
case ATH6KL_STATE_DEEPSLEEP:
......@@ -2188,6 +2276,9 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
*/
void ath6kl_check_wow_status(struct ath6kl *ar)
{
if (ar->state == ATH6KL_STATE_SUSPENDING)
return;
if (ar->state == ATH6KL_STATE_WOW)
ath6kl_cfg80211_resume(ar);
}
......@@ -2275,30 +2366,27 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
struct ath6kl *ar = vif->ar;
int res;
if (info->beacon_ies) {
res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_BEACON,
info->beacon_ies,
info->beacon_ies_len);
if (res)
return res;
}
/* this also clears IE in fw if it's not set */
res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_BEACON,
info->beacon_ies,
info->beacon_ies_len);
if (res)
return res;
if (info->proberesp_ies) {
res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
info->proberesp_ies_len);
if (res)
return res;
}
/* this also clears IE in fw if it's not set */
res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
info->proberesp_ies_len);
if (res)
return res;
if (info->assocresp_ies) {
res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_ASSOC_RESP,
info->assocresp_ies,
info->assocresp_ies_len);
if (res)
return res;
}
/* this also clears IE in fw if it's not set */
res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_ASSOC_RESP,
info->assocresp_ies,
info->assocresp_ies_len);
if (res)
return res;
return 0;
}
......@@ -2309,6 +2397,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
struct ieee80211_mgmt *mgmt;
bool hidden = false;
u8 *ies;
int ies_len;
struct wmi_connect_cmd p;
......@@ -2345,7 +2434,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
memcpy(vif->ssid, info->ssid, info->ssid_len);
vif->ssid_len = info->ssid_len;
if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
return -EOPNOTSUPP; /* TODO */
hidden = true;
res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden);
if (res)
return res;
ret = ath6kl_set_auth_type(vif, info->auth_type);
if (ret)
......@@ -2584,6 +2677,76 @@ static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
return ret;
}
static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
u32 id,
u32 freq,
u32 wait,
const u8 *buf,
size_t len,
bool *more_data,
bool no_cck)
{
struct ieee80211_mgmt *mgmt;
struct ath6kl_sta *conn;
bool is_psq_empty = false;
struct ath6kl_mgmt_buff *mgmt_buf;
size_t mgmt_buf_size;
struct ath6kl *ar = vif->ar;
mgmt = (struct ieee80211_mgmt *) buf;
if (is_multicast_ether_addr(mgmt->da))
return false;
conn = ath6kl_find_sta(vif, mgmt->da);
if (!conn)
return false;
if (conn->sta_flags & STA_PS_SLEEP) {
if (!(conn->sta_flags & STA_PS_POLLED)) {
/* Queue the frames if the STA is sleeping */
mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff);
mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL);
if (!mgmt_buf)
return false;
INIT_LIST_HEAD(&mgmt_buf->list);
mgmt_buf->id = id;
mgmt_buf->freq = freq;
mgmt_buf->wait = wait;
mgmt_buf->len = len;
mgmt_buf->no_cck = no_cck;
memcpy(mgmt_buf->buf, buf, len);
spin_lock_bh(&conn->psq_lock);
is_psq_empty = skb_queue_empty(&conn->psq) &&
(conn->mgmt_psq_len == 0);
list_add_tail(&mgmt_buf->list, &conn->mgmt_psq);
conn->mgmt_psq_len++;
spin_unlock_bh(&conn->psq_lock);
/*
* If this is the first pkt getting queued
* for this STA, update the PVB for this
* STA.
*/
if (is_psq_empty)
ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx,
conn->aid, 1);
return true;
}
/*
* This tx is because of a PsPoll.
* Determine if MoreData bit has to be set.
*/
spin_lock_bh(&conn->psq_lock);
if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0))
*more_data = true;
spin_unlock_bh(&conn->psq_lock);
}
return false;
}
static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
......@@ -2595,6 +2758,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
struct ath6kl_vif *vif = netdev_priv(dev);
u32 id;
const struct ieee80211_mgmt *mgmt;
bool more_data, queued;
mgmt = (const struct ieee80211_mgmt *) buf;
if (buf + len >= mgmt->u.probe_resp.variable &&
......@@ -2620,22 +2784,19 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
*cookie = id;
if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
ar->fw_capabilities)) {
/*
* If capable of doing P2P mgmt operations using
* station interface, send additional information like
* supported rates to advertise and xmit rates for
* probe requests
*/
return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,