mwifiex: add cfg80211 change_station handler support
This patch adds cfg80211 change_station handler support for mwifiex which is needed for TDLS link setup. Driver creates a command to modify peer link capabilities and issues command to FW. Signed-off-by: Avinash Patil <patila@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
e48e0de005
commit
1f4dfd8a1e
|
@ -2734,6 +2734,30 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy,
|
||||||
return mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CREATE_LINK);
|
return mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CREATE_LINK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mwifiex_cfg80211_change_station(struct wiphy *wiphy,
|
||||||
|
struct net_device *dev,
|
||||||
|
u8 *mac, struct station_parameters *params)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||||
|
|
||||||
|
/* we support change_station handler only for TDLS peers*/
|
||||||
|
if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
|
||||||
|
return -ENOTSUPP;
|
||||||
|
|
||||||
|
/* make sure we are in station mode and connected */
|
||||||
|
if ((priv->bss_type != MWIFIEX_BSS_TYPE_STA) || !priv->media_connected)
|
||||||
|
return -ENOTSUPP;
|
||||||
|
|
||||||
|
priv->sta_params = params;
|
||||||
|
|
||||||
|
ret = mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CONFIG_LINK);
|
||||||
|
priv->sta_params = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* station cfg80211 operations */
|
/* station cfg80211 operations */
|
||||||
static struct cfg80211_ops mwifiex_cfg80211_ops = {
|
static struct cfg80211_ops mwifiex_cfg80211_ops = {
|
||||||
.add_virtual_intf = mwifiex_add_virtual_intf,
|
.add_virtual_intf = mwifiex_add_virtual_intf,
|
||||||
|
@ -2772,6 +2796,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
|
||||||
.tdls_mgmt = mwifiex_cfg80211_tdls_mgmt,
|
.tdls_mgmt = mwifiex_cfg80211_tdls_mgmt,
|
||||||
.tdls_oper = mwifiex_cfg80211_tdls_oper,
|
.tdls_oper = mwifiex_cfg80211_tdls_oper,
|
||||||
.add_station = mwifiex_cfg80211_add_station,
|
.add_station = mwifiex_cfg80211_add_station,
|
||||||
|
.change_station = mwifiex_cfg80211_change_station,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
|
|
@ -1391,6 +1391,11 @@ struct mwifiex_ie_types_extcap {
|
||||||
u8 ext_capab[0];
|
u8 ext_capab[0];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct mwifiex_ie_types_qos_info {
|
||||||
|
struct mwifiex_ie_types_header header;
|
||||||
|
u8 qos_info;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
struct host_cmd_ds_mac_reg_access {
|
struct host_cmd_ds_mac_reg_access {
|
||||||
__le16 action;
|
__le16 action;
|
||||||
__le16 offset;
|
__le16 offset;
|
||||||
|
|
|
@ -529,6 +529,7 @@ struct mwifiex_private {
|
||||||
unsigned long csa_expire_time;
|
unsigned long csa_expire_time;
|
||||||
u8 del_list_idx;
|
u8 del_list_idx;
|
||||||
bool hs2_enabled;
|
bool hs2_enabled;
|
||||||
|
struct station_parameters *sta_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum mwifiex_ba_status {
|
enum mwifiex_ba_status {
|
||||||
|
|
|
@ -1288,27 +1288,96 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv,
|
||||||
struct host_cmd_ds_tdls_oper *tdls_oper = &cmd->params.tdls_oper;
|
struct host_cmd_ds_tdls_oper *tdls_oper = &cmd->params.tdls_oper;
|
||||||
struct mwifiex_ds_tdls_oper *oper = data_buf;
|
struct mwifiex_ds_tdls_oper *oper = data_buf;
|
||||||
struct mwifiex_sta_node *sta_ptr;
|
struct mwifiex_sta_node *sta_ptr;
|
||||||
|
struct host_cmd_tlv_rates *tlv_rates;
|
||||||
|
struct mwifiex_ie_types_htcap *ht_capab;
|
||||||
|
struct mwifiex_ie_types_qos_info *wmm_qos_info;
|
||||||
|
struct mwifiex_ie_types_extcap *extcap;
|
||||||
|
u8 *pos, qos_info;
|
||||||
|
u16 config_len = 0;
|
||||||
|
struct station_parameters *params = priv->sta_params;
|
||||||
|
|
||||||
cmd->command = cpu_to_le16(HostCmd_CMD_TDLS_OPER);
|
cmd->command = cpu_to_le16(HostCmd_CMD_TDLS_OPER);
|
||||||
cmd->size = cpu_to_le16(S_DS_GEN);
|
cmd->size = cpu_to_le16(S_DS_GEN);
|
||||||
|
le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_tdls_oper));
|
||||||
|
|
||||||
tdls_oper->reason = 0;
|
tdls_oper->reason = 0;
|
||||||
memcpy(tdls_oper->peer_mac, oper->peer_mac, ETH_ALEN);
|
memcpy(tdls_oper->peer_mac, oper->peer_mac, ETH_ALEN);
|
||||||
sta_ptr = mwifiex_get_sta_entry(priv, oper->peer_mac);
|
sta_ptr = mwifiex_get_sta_entry(priv, oper->peer_mac);
|
||||||
|
|
||||||
|
pos = (u8 *)tdls_oper + sizeof(struct host_cmd_ds_tdls_oper);
|
||||||
|
|
||||||
switch (oper->tdls_action) {
|
switch (oper->tdls_action) {
|
||||||
case MWIFIEX_TDLS_DISABLE_LINK:
|
case MWIFIEX_TDLS_DISABLE_LINK:
|
||||||
tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_DELETE);
|
tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_DELETE);
|
||||||
break;
|
break;
|
||||||
case MWIFIEX_TDLS_CREATE_LINK:
|
case MWIFIEX_TDLS_CREATE_LINK:
|
||||||
tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_CREATE);
|
tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_CREATE);
|
||||||
|
break;
|
||||||
|
case MWIFIEX_TDLS_CONFIG_LINK:
|
||||||
|
tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_CONFIG);
|
||||||
|
|
||||||
|
if (!params) {
|
||||||
|
dev_err(priv->adapter->dev,
|
||||||
|
"TDLS config params not available for %pM\n",
|
||||||
|
oper->peer_mac);
|
||||||
|
return -ENODATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(__le16 *)pos = cpu_to_le16(params->capability);
|
||||||
|
config_len += sizeof(params->capability);
|
||||||
|
|
||||||
|
qos_info = params->uapsd_queues | (params->max_sp << 5);
|
||||||
|
wmm_qos_info = (struct mwifiex_ie_types_qos_info *)(pos +
|
||||||
|
config_len);
|
||||||
|
wmm_qos_info->header.type = cpu_to_le16(WLAN_EID_QOS_CAPA);
|
||||||
|
wmm_qos_info->header.len = cpu_to_le16(sizeof(qos_info));
|
||||||
|
wmm_qos_info->qos_info = qos_info;
|
||||||
|
config_len += sizeof(struct mwifiex_ie_types_qos_info);
|
||||||
|
|
||||||
|
if (params->ht_capa) {
|
||||||
|
ht_capab = (struct mwifiex_ie_types_htcap *)(pos +
|
||||||
|
config_len);
|
||||||
|
ht_capab->header.type =
|
||||||
|
cpu_to_le16(WLAN_EID_HT_CAPABILITY);
|
||||||
|
ht_capab->header.len =
|
||||||
|
cpu_to_le16(sizeof(struct ieee80211_ht_cap));
|
||||||
|
memcpy(&ht_capab->ht_cap, params->ht_capa,
|
||||||
|
sizeof(struct ieee80211_ht_cap));
|
||||||
|
config_len += sizeof(struct mwifiex_ie_types_htcap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->supported_rates && params->supported_rates_len) {
|
||||||
|
tlv_rates = (struct host_cmd_tlv_rates *)(pos +
|
||||||
|
config_len);
|
||||||
|
tlv_rates->header.type =
|
||||||
|
cpu_to_le16(WLAN_EID_SUPP_RATES);
|
||||||
|
tlv_rates->header.len =
|
||||||
|
cpu_to_le16(params->supported_rates_len);
|
||||||
|
memcpy(tlv_rates->rates, params->supported_rates,
|
||||||
|
params->supported_rates_len);
|
||||||
|
config_len += sizeof(struct host_cmd_tlv_rates) +
|
||||||
|
params->supported_rates_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->ext_capab && params->ext_capab_len) {
|
||||||
|
extcap = (struct mwifiex_ie_types_extcap *)(pos +
|
||||||
|
config_len);
|
||||||
|
extcap->header.type =
|
||||||
|
cpu_to_le16(WLAN_EID_EXT_CAPABILITY);
|
||||||
|
extcap->header.len = cpu_to_le16(params->ext_capab_len);
|
||||||
|
memcpy(extcap->ext_capab, params->ext_capab,
|
||||||
|
params->ext_capab_len);
|
||||||
|
config_len += sizeof(struct mwifiex_ie_types_extcap) +
|
||||||
|
params->ext_capab_len;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(priv->adapter->dev, "Unknown TDLS operation\n");
|
dev_err(priv->adapter->dev, "Unknown TDLS operation\n");
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_tdls_oper));
|
le16_add_cpu(&cmd->size, config_len);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -834,6 +834,19 @@ static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv,
|
||||||
cmd_tdls_oper->peer_mac);
|
cmd_tdls_oper->peer_mac);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ACT_TDLS_CONFIG:
|
||||||
|
if (reason) {
|
||||||
|
dev_err(priv->adapter->dev,
|
||||||
|
"TDLS link config for %pM failed, reason %d\n",
|
||||||
|
cmd_tdls_oper->peer_mac, reason);
|
||||||
|
if (node)
|
||||||
|
node->tdls_status = TDLS_SETUP_FAILURE;
|
||||||
|
} else {
|
||||||
|
dev_dbg(priv->adapter->dev,
|
||||||
|
"TDLS link config for %pM successful\n",
|
||||||
|
cmd_tdls_oper->peer_mac);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(priv->adapter->dev,
|
dev_err(priv->adapter->dev,
|
||||||
"Unknown TDLS command action respnse %d", action);
|
"Unknown TDLS command action respnse %d", action);
|
||||||
|
|
|
@ -543,6 +543,27 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mwifiex_tdls_process_config_link(struct mwifiex_private *priv, u8 *peer)
|
||||||
|
{
|
||||||
|
struct mwifiex_sta_node *sta_ptr;
|
||||||
|
struct mwifiex_ds_tdls_oper tdls_oper;
|
||||||
|
|
||||||
|
memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
|
||||||
|
sta_ptr = mwifiex_get_sta_entry(priv, peer);
|
||||||
|
|
||||||
|
if (!sta_ptr || sta_ptr->tdls_status == TDLS_SETUP_FAILURE) {
|
||||||
|
dev_err(priv->adapter->dev,
|
||||||
|
"link absent for peer %pM; cannot config\n", peer);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
|
||||||
|
tdls_oper.tdls_action = MWIFIEX_TDLS_CONFIG_LINK;
|
||||||
|
return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TDLS_OPER,
|
||||||
|
HostCmd_ACT_GEN_SET, 0, &tdls_oper);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mwifiex_tdls_process_create_link(struct mwifiex_private *priv, u8 *peer)
|
mwifiex_tdls_process_create_link(struct mwifiex_private *priv, u8 *peer)
|
||||||
{
|
{
|
||||||
|
@ -662,6 +683,8 @@ int mwifiex_tdls_oper(struct mwifiex_private *priv, u8 *peer, u8 action)
|
||||||
return mwifiex_tdls_process_disable_link(priv, peer);
|
return mwifiex_tdls_process_disable_link(priv, peer);
|
||||||
case MWIFIEX_TDLS_CREATE_LINK:
|
case MWIFIEX_TDLS_CREATE_LINK:
|
||||||
return mwifiex_tdls_process_create_link(priv, peer);
|
return mwifiex_tdls_process_create_link(priv, peer);
|
||||||
|
case MWIFIEX_TDLS_CONFIG_LINK:
|
||||||
|
return mwifiex_tdls_process_config_link(priv, peer);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue