Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f4dfd8a authored by Avinash Patil's avatar Avinash Patil Committed by John W. Linville
Browse files

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: default avatarAvinash Patil <patila@marvell.com>
Signed-off-by: default avatarBing Zhao <bzhao@marvell.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e48e0de0
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -2734,6 +2734,30 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy,
	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 */
static struct cfg80211_ops mwifiex_cfg80211_ops = {
	.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_oper = mwifiex_cfg80211_tdls_oper,
	.add_station = mwifiex_cfg80211_add_station,
	.change_station = mwifiex_cfg80211_change_station,
};

#ifdef CONFIG_PM
+5 −0
Original line number Diff line number Diff line
@@ -1391,6 +1391,11 @@ struct mwifiex_ie_types_extcap {
	u8 ext_capab[0];
} __packed;

struct mwifiex_ie_types_qos_info {
	struct mwifiex_ie_types_header header;
	u8 qos_info;
} __packed;

struct host_cmd_ds_mac_reg_access {
	__le16 action;
	__le16 offset;
+1 −0
Original line number Diff line number Diff line
@@ -529,6 +529,7 @@ struct mwifiex_private {
	unsigned long csa_expire_time;
	u8 del_list_idx;
	bool hs2_enabled;
	struct station_parameters *sta_params;
};

enum mwifiex_ba_status {
+70 −1
Original line number Diff line number Diff line
@@ -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 mwifiex_ds_tdls_oper *oper = data_buf;
	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->size = cpu_to_le16(S_DS_GEN);
	le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_tdls_oper));

	tdls_oper->reason = 0;
	memcpy(tdls_oper->peer_mac, oper->peer_mac, ETH_ALEN);
	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) {
	case MWIFIEX_TDLS_DISABLE_LINK:
		tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_DELETE);
		break;
	case MWIFIEX_TDLS_CREATE_LINK:
		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;
	default:
		dev_err(priv->adapter->dev, "Unknown TDLS operation\n");
		return -ENOTSUPP;
	}

	le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_tdls_oper));
	le16_add_cpu(&cmd->size, config_len);

	return 0;
}
+13 −0
Original line number Diff line number Diff line
@@ -834,6 +834,19 @@ static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv,
				cmd_tdls_oper->peer_mac);
		}
		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:
		dev_err(priv->adapter->dev,
			"Unknown TDLS command action respnse %d", action);
Loading