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

Commit eda0168c authored by Ahmad Masri's avatar Ahmad Masri Committed by Maya Erez
Browse files

wil6210: add FT roam support for AP and station



This feature is needed for enterprise APs and clients to enable
fast roaming as defined in 802.11r between APs in the same ESS.

On AP side, this feature is supported only when disable_ap_sme
is enabled.

Change-Id: I3db3c2904ca483a41d05677b01c3ebb97c8578bb
Signed-off-by: default avatarAhmad Masri <amasri@codeaurora.org>
Signed-off-by: default avatarMaya Erez <merez@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Git-commit: b9010f105f21788b2dbe0e9599677a27247a9092
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git


Signed-off-by: default avatarMaya Erez <merez@codeaurora.org>
parent 7b35e28e
Loading
Loading
Loading
Loading
+268 −52
Original line number Original line Diff line number Diff line
@@ -393,7 +393,9 @@ wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
		.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
		.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
		BIT(IEEE80211_STYPE_PROBE_RESP >> 4) |
		BIT(IEEE80211_STYPE_PROBE_RESP >> 4) |
		BIT(IEEE80211_STYPE_ASSOC_RESP >> 4) |
		BIT(IEEE80211_STYPE_ASSOC_RESP >> 4) |
		BIT(IEEE80211_STYPE_DISASSOC >> 4),
		BIT(IEEE80211_STYPE_DISASSOC >> 4) |
		BIT(IEEE80211_STYPE_AUTH >> 4) |
		BIT(IEEE80211_STYPE_REASSOC_RESP >> 4),
		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
		BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
		BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
		BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
		BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
@@ -1145,6 +1147,26 @@ static void wil_print_crypto(struct wil6210_priv *wil,
		     c->control_port_no_encrypt);
		     c->control_port_no_encrypt);
}
}


static const char *
wil_get_auth_type_name(enum nl80211_auth_type auth_type)
{
	switch (auth_type) {
	case NL80211_AUTHTYPE_OPEN_SYSTEM:
		return "OPEN_SYSTEM";
	case NL80211_AUTHTYPE_SHARED_KEY:
		return "SHARED_KEY";
	case NL80211_AUTHTYPE_FT:
		return "FT";
	case NL80211_AUTHTYPE_NETWORK_EAP:
		return "NETWORK_EAP";
	case NL80211_AUTHTYPE_SAE:
		return "SAE";
	case NL80211_AUTHTYPE_AUTOMATIC:
		return "AUTOMATIC";
	default:
		return "unknown";
	}
}
static void wil_print_connect_params(struct wil6210_priv *wil,
static void wil_print_connect_params(struct wil6210_priv *wil,
				     struct cfg80211_connect_params *sme)
				     struct cfg80211_connect_params *sme)
{
{
@@ -1158,11 +1180,82 @@ static void wil_print_connect_params(struct wil6210_priv *wil,
	if (sme->ssid)
	if (sme->ssid)
		print_hex_dump(KERN_INFO, "  SSID: ", DUMP_PREFIX_OFFSET,
		print_hex_dump(KERN_INFO, "  SSID: ", DUMP_PREFIX_OFFSET,
			       16, 1, sme->ssid, sme->ssid_len, true);
			       16, 1, sme->ssid, sme->ssid_len, true);
	if (sme->prev_bssid)
		wil_info(wil, "  Previous BSSID=%pM\n", sme->prev_bssid);
	wil_info(wil, "  Auth Type: %s\n",
		 wil_get_auth_type_name(sme->auth_type));
	wil_info(wil, "  Privacy: %s\n", sme->privacy ? "secure" : "open");
	wil_info(wil, "  Privacy: %s\n", sme->privacy ? "secure" : "open");
	wil_info(wil, "  PBSS: %d\n", sme->pbss);
	wil_info(wil, "  PBSS: %d\n", sme->pbss);
	wil_print_crypto(wil, &sme->crypto);
	wil_print_crypto(wil, &sme->crypto);
}
}


static int wil_ft_connect(struct wiphy *wiphy,
			  struct net_device *ndev,
			  struct cfg80211_connect_params *sme)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	struct wil6210_vif *vif = ndev_to_vif(ndev);
	struct wmi_ft_auth_cmd auth_cmd;
	int rc;

	if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) {
		wil_err(wil, "FT: FW does not support FT roaming\n");
		return -EOPNOTSUPP;
	}

	if (!sme->prev_bssid) {
		wil_err(wil, "FT: prev_bssid was not set\n");
		return -EINVAL;
	}

	if (ether_addr_equal(sme->prev_bssid, sme->bssid)) {
		wil_err(wil, "FT: can not roam to same AP\n");
		return -EINVAL;
	}

	if (!test_bit(wil_vif_fwconnected, vif->status)) {
		wil_err(wil, "FT: roam while not connected\n");
		return -EINVAL;
	}

	if (vif->privacy != sme->privacy) {
		wil_err(wil, "FT: privacy mismatch, current (%d) roam (%d)\n",
			vif->privacy, sme->privacy);
		return -EINVAL;
	}

	if (sme->pbss) {
		wil_err(wil, "FT: roam is not valid for PBSS\n");
		return -EINVAL;
	}

	memset(&auth_cmd, 0, sizeof(auth_cmd));
	auth_cmd.channel = sme->channel->hw_value - 1;
	ether_addr_copy(auth_cmd.bssid, sme->bssid);

	if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities))
		if (wil->force_edmg_channel) {
			rc = wil_spec2wmi_ch(wil->force_edmg_channel,
					     &auth_cmd.channel);
			if (rc)
				wil_err(wil, "FT: wmi channel for channel %d not found",
					wil->force_edmg_channel);
		}

	wil_info(wil, "FT: roaming\n");

	set_bit(wil_vif_ft_roam, vif->status);
	rc = wmi_send(wil, WMI_FT_AUTH_CMDID, vif->mid,
		      &auth_cmd, sizeof(auth_cmd));
	if (rc == 0)
		mod_timer(&vif->connect_timer,
			  jiffies + msecs_to_jiffies(5000));
	else
		clear_bit(wil_vif_ft_roam, vif->status);

	return rc;
}

static int wil_cfg80211_connect(struct wiphy *wiphy,
static int wil_cfg80211_connect(struct wiphy *wiphy,
				struct net_device *ndev,
				struct net_device *ndev,
				struct cfg80211_connect_params *sme)
				struct cfg80211_connect_params *sme)
@@ -1175,11 +1268,20 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	const u8 *rsn_eid;
	const u8 *rsn_eid;
	int ch;
	int ch;
	int rc = 0;
	int rc = 0;
	bool is_ft_roam = false;
	u8 network_type;
	enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS;
	enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS;


	wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid);
	wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid);
	wil_print_connect_params(wil, sme);
	wil_print_connect_params(wil, sme);


	if (sme->auth_type == NL80211_AUTHTYPE_FT)
		is_ft_roam = true;
	if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC &&
	    test_bit(wil_vif_fwconnected, vif->status))
		is_ft_roam = true;

	if (!is_ft_roam)
		if (test_bit(wil_vif_fwconnecting, vif->status) ||
		if (test_bit(wil_vif_fwconnecting, vif->status) ||
		    test_bit(wil_vif_fwconnected, vif->status))
		    test_bit(wil_vif_fwconnected, vif->status))
			return -EALREADY;
			return -EALREADY;
@@ -1192,8 +1294,13 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	rsn_eid = sme->ie ?
	rsn_eid = sme->ie ?
			cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
			cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
			NULL;
			NULL;
	if (sme->privacy && !rsn_eid)
	if (sme->privacy && !rsn_eid) {
		wil_info(wil, "WSC connection\n");
		wil_info(wil, "WSC connection\n");
		if (is_ft_roam) {
			wil_err(wil, "No WSC with FT roam\n");
			return -EINVAL;
		}
	}


	if (sme->pbss)
	if (sme->pbss)
		bss_type = IEEE80211_BSS_TYPE_PBSS;
		bss_type = IEEE80211_BSS_TYPE_PBSS;
@@ -1215,6 +1322,45 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	vif->privacy = sme->privacy;
	vif->privacy = sme->privacy;
	vif->pbss = sme->pbss;
	vif->pbss = sme->pbss;


	rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
	if (rc)
		goto out;

	switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
	case WLAN_CAPABILITY_DMG_TYPE_AP:
		network_type = WMI_NETTYPE_INFRA;
		break;
	case WLAN_CAPABILITY_DMG_TYPE_PBSS:
		network_type = WMI_NETTYPE_P2P;
		break;
	default:
		wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
			bss->capability);
		rc = -EINVAL;
		goto out;
	}

	ch = bss->channel->hw_value;
	if (ch == 0) {
		wil_err(wil, "BSS at unknown frequency %dMhz\n",
			bss->channel->center_freq);
		rc = -EOPNOTSUPP;
		goto out;
	}

	if (is_ft_roam) {
		if (network_type != WMI_NETTYPE_INFRA) {
			wil_err(wil, "FT: Unsupported BSS type, capability= 0x%04x\n",
				bss->capability);
			rc = -EINVAL;
			goto out;
		}
		rc = wil_ft_connect(wiphy, ndev, sme);
		if (rc == 0)
			vif->bss = bss;
		goto out;
	}

	if (vif->privacy) {
	if (vif->privacy) {
		/* For secure assoc, remove old keys */
		/* For secure assoc, remove old keys */
		rc = wmi_del_cipher_key(vif, 0, bss->bssid,
		rc = wmi_del_cipher_key(vif, 0, bss->bssid,
@@ -1231,28 +1377,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
		}
		}
	}
	}


	/* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info
	 * elements. Send it also in case it's empty, to erase previously set
	 * ies in FW.
	 */
	rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
	if (rc)
		goto out;

	/* WMI_CONNECT_CMD */
	/* WMI_CONNECT_CMD */
	memset(&conn, 0, sizeof(conn));
	memset(&conn, 0, sizeof(conn));
	switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
	conn.network_type = network_type;
	case WLAN_CAPABILITY_DMG_TYPE_AP:
		conn.network_type = WMI_NETTYPE_INFRA;
		break;
	case WLAN_CAPABILITY_DMG_TYPE_PBSS:
		conn.network_type = WMI_NETTYPE_P2P;
		break;
	default:
		wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
			bss->capability);
		goto out;
	}
	if (vif->privacy) {
	if (vif->privacy) {
		if (rsn_eid) { /* regular secure connection */
		if (rsn_eid) { /* regular secure connection */
			conn.dot11_auth_mode = WMI_AUTH11_SHARED;
			conn.dot11_auth_mode = WMI_AUTH11_SHARED;
@@ -1272,14 +1399,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,


	conn.ssid_len = min_t(u8, ssid_eid[1], 32);
	conn.ssid_len = min_t(u8, ssid_eid[1], 32);
	memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);
	memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);

	ch = bss->channel->hw_value;
	if (ch == 0) {
		wil_err(wil, "BSS at unknown frequency %dMhz\n",
			bss->channel->center_freq);
		rc = -EOPNOTSUPP;
		goto out;
	}
	conn.channel = ch - 1;
	conn.channel = ch - 1;


	if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities))
	if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities))
@@ -1485,7 +1604,7 @@ wil_find_sta_by_key_usage(struct wil6210_priv *wil, u8 mid,
	return &wil->sta[cid];
	return &wil->sta[cid];
}
}


static void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
		       struct wil_sta_info *cs,
		       struct wil_sta_info *cs,
		       struct key_params *params)
		       struct key_params *params)
{
{
@@ -1570,12 +1689,18 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
		     params->seq_len, params->seq);
		     params->seq_len, params->seq);


	if (IS_ERR(cs)) {
	if (IS_ERR(cs)) {
		/* in FT, sta info may not be available as add_key may be
		 * sent by host before FW sends WMI_CONNECT_EVENT
		 */
		if (!test_bit(wil_vif_ft_roam, vif->status)) {
			wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n",
			wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n",
				mac_addr, key_usage_str[key_usage], key_index,
				mac_addr, key_usage_str[key_usage], key_index,
				params->seq_len, params->seq);
				params->seq_len, params->seq);
			return -EINVAL;
			return -EINVAL;
		}
		}
	}


	if (!IS_ERR(cs))
		wil_del_rx_key(key_index, key_usage, cs);
		wil_del_rx_key(key_index, key_usage, cs);


	if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) {
	if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) {
@@ -1589,7 +1714,10 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,


	rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len,
	rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len,
				params->key, key_usage);
				params->key, key_usage);
	if (!rc)
	if (!rc && !IS_ERR(cs))
		/* in FT set crypto will take place upon receiving
		 * WMI_RING_EN_EVENTID event
		 */
		wil_set_crypto_rx(key_index, key_usage, cs, params);
		wil_set_crypto_rx(key_index, key_usage, cs, params);


	return rc;
	return rc;
@@ -1752,21 +1880,36 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
}
}


/* internal functions for device reset and starting AP */
/* internal functions for device reset and starting AP */
static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
static u8 *
				 struct cfg80211_beacon_data *bcon)
_wil_cfg80211_get_proberesp_ies(const u8 *proberesp, u16 proberesp_len,
				u16 *ies_len)
{
{
	int rc;
	u8 *ies = NULL;
	u16 len = 0, proberesp_len = 0;
	u8 *ies = NULL, *proberesp = NULL;


	if (bcon->probe_resp) {
	if (proberesp) {
		struct ieee80211_mgmt *f =
		struct ieee80211_mgmt *f =
			(struct ieee80211_mgmt *)bcon->probe_resp;
			(struct ieee80211_mgmt *)proberesp;
		size_t hlen = offsetof(struct ieee80211_mgmt,
		size_t hlen = offsetof(struct ieee80211_mgmt,
				       u.probe_resp.variable);
				       u.probe_resp.variable);
		proberesp = f->u.probe_resp.variable;

		proberesp_len = bcon->probe_resp_len - hlen;
		ies = f->u.probe_resp.variable;
		if (ies_len)
			*ies_len = proberesp_len - hlen;
	}

	return ies;
}
}

static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
				 struct cfg80211_beacon_data *bcon)
{
	int rc;
	u16 len = 0, proberesp_len = 0;
	u8 *ies = NULL, *proberesp;

	proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp,
						    bcon->probe_resp_len,
						    &proberesp_len);
	rc = _wil_cfg80211_merge_extra_ies(proberesp,
	rc = _wil_cfg80211_merge_extra_ies(proberesp,
					   proberesp_len,
					   proberesp_len,
					   bcon->proberesp_ies,
					   bcon->proberesp_ies,
@@ -1810,6 +1953,9 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
	struct wireless_dev *wdev = ndev->ieee80211_ptr;
	struct wireless_dev *wdev = ndev->ieee80211_ptr;
	u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
	u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
	u8 is_go = (wdev->iftype == NL80211_IFTYPE_P2P_GO);
	u8 is_go = (wdev->iftype == NL80211_IFTYPE_P2P_GO);
	u16 proberesp_len = 0;
	u8 *proberesp;
	bool ft = false;


	if (pbss)
	if (pbss)
		wmi_nettype = WMI_NETTYPE_P2P;
		wmi_nettype = WMI_NETTYPE_P2P;
@@ -1822,6 +1968,25 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,


	wil_set_recovery_state(wil, fw_recovery_idle);
	wil_set_recovery_state(wil, fw_recovery_idle);


	proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp,
						    bcon->probe_resp_len,
						    &proberesp_len);
	/* check that the probe response IEs has a MDE */
	if ((proberesp && proberesp_len > 0 &&
	     cfg80211_find_ie(WLAN_EID_MOBILITY_DOMAIN,
			      proberesp,
			      proberesp_len)))
		ft = true;

	if (ft) {
		if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING,
			      wil->fw_capabilities)) {
			wil_err(wil, "FW does not support FT roaming\n");
			return -ENOTSUPP;
		}
		set_bit(wil_vif_ft_roam, vif->status);
	}

	mutex_lock(&wil->mutex);
	mutex_lock(&wil->mutex);


	if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
	if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
@@ -1983,6 +2148,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
	mutex_lock(&wil->mutex);
	mutex_lock(&wil->mutex);


	wmi_pcp_stop(vif);
	wmi_pcp_stop(vif);
	clear_bit(wil_vif_ft_roam, vif->status);


	if (last)
	if (last)
		__wil_down(wil);
		__wil_down(wil);
@@ -2002,8 +2168,9 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy,
	struct wil6210_vif *vif = ndev_to_vif(dev);
	struct wil6210_vif *vif = ndev_to_vif(dev);
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);


	wil_dbg_misc(wil, "add station %pM aid %d mid %d\n",
	wil_dbg_misc(wil, "add station %pM aid %d mid %d mask 0x%x set 0x%x\n",
		     mac, params->aid, vif->mid);
		     mac, params->aid, vif->mid,
		     params->sta_flags_mask, params->sta_flags_set);


	if (!disable_ap_sme) {
	if (!disable_ap_sme) {
		wil_err(wil, "not supported with AP SME enabled\n");
		wil_err(wil, "not supported with AP SME enabled\n");
@@ -2383,6 +2550,54 @@ static void wil_cfg80211_reg_notify(struct wiphy *wiphy,
	memcpy(wil->regdomain, request->alpha2, 2);
	memcpy(wil->regdomain, request->alpha2, 2);
}
}


static int
wil_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
			   struct cfg80211_update_ft_ies_params *ftie)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	struct wil6210_vif *vif = ndev_to_vif(dev);
	struct cfg80211_bss *bss;
	struct wmi_ft_reassoc_cmd reassoc;
	int rc = 0;

	wil_dbg_misc(wil, "update ft ies, mid=%d\n", vif->mid);
	wil_hex_dump_misc("FT IE ", DUMP_PREFIX_OFFSET, 16, 1,
			  ftie->ie, ftie->ie_len, true);

	if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) {
		wil_err(wil, "FW does not support FT roaming\n");
		return -EOPNOTSUPP;
	}

	rc = wmi_update_ft_ies(vif, ftie->ie_len, ftie->ie);
	if (rc)
		return rc;

	if (!test_bit(wil_vif_ft_roam, vif->status))
		/* vif is not roaming */
		return 0;

	/* wil_vif_ft_roam is set. wil_cfg80211_update_ft_ies is used as
	 * a trigger for reassoc
	 */

	bss = vif->bss;
	if (!bss) {
		wil_err(wil, "FT: bss is NULL\n");
		return -EINVAL;
	}

	memset(&reassoc, 0, sizeof(reassoc));
	ether_addr_copy(reassoc.bssid, bss->bssid);

	rc = wmi_send(wil, WMI_FT_REASSOC_CMDID, vif->mid,
		      &reassoc, sizeof(reassoc));
	if (rc)
		wil_err(wil, "FT: reassoc failed (%d)\n", rc);

	return rc;
}

static const struct cfg80211_ops wil_cfg80211_ops = {
static const struct cfg80211_ops wil_cfg80211_ops = {
	.add_virtual_intf = wil_cfg80211_add_iface,
	.add_virtual_intf = wil_cfg80211_add_iface,
	.del_virtual_intf = wil_cfg80211_del_iface,
	.del_virtual_intf = wil_cfg80211_del_iface,
@@ -2418,6 +2633,7 @@ static const struct cfg80211_ops wil_cfg80211_ops = {
	.resume = wil_cfg80211_resume,
	.resume = wil_cfg80211_resume,
	.sched_scan_start = wil_cfg80211_sched_scan_start,
	.sched_scan_start = wil_cfg80211_sched_scan_start,
	.sched_scan_stop = wil_cfg80211_sched_scan_stop,
	.sched_scan_stop = wil_cfg80211_sched_scan_stop,
	.update_ft_ies = wil_cfg80211_update_ft_ies,
};
};


static void wil_wiphy_init(struct wiphy *wiphy)
static void wil_wiphy_init(struct wiphy *wiphy)
+15 −2
Original line number Original line Diff line number Diff line
@@ -1708,6 +1708,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
		char *status = "unknown";
		char *status = "unknown";
		u8 aid = 0;
		u8 aid = 0;
		u8 mid;
		u8 mid;
		bool sta_connected = false;


		switch (p->status) {
		switch (p->status) {
		case wil_sta_unused:
		case wil_sta_unused:
@@ -1722,8 +1723,20 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
			break;
			break;
		}
		}
		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
		seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
		if (mid < wil->max_vifs) {
			   mid, aid);
			struct wil6210_vif *vif = wil->vifs[mid];

			if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
			    p->status == wil_sta_connected)
				sta_connected = true;
		}
		/* print roam counter only for connected stations */
		if (sta_connected)
			seq_printf(s, "[%d] %pM connected (roam counter %d) MID %d AID %d\n",
				   i, p->addr, p->stats.ft_roams, mid, aid);
		else
			seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i,
				   p->addr, status, mid, aid);


		if (p->status == wil_sta_connected) {
		if (p->status == wil_sta_connected) {
			spin_lock_bh(&p->tid_rx_lock);
			spin_lock_bh(&p->tid_rx_lock);
+2 −0
Original line number Original line Diff line number Diff line
@@ -362,6 +362,8 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
			vif->bss = NULL;
			vif->bss = NULL;
		}
		}
		clear_bit(wil_vif_fwconnecting, vif->status);
		clear_bit(wil_vif_fwconnecting, vif->status);
		clear_bit(wil_vif_ft_roam, vif->status);

		break;
		break;
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_P2P_GO:
	case NL80211_IFTYPE_P2P_GO:
+83 −0
Original line number Original line Diff line number Diff line
@@ -1085,6 +1085,88 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
	return rc;
	return rc;
}
}


static int wil_tx_vring_modify(struct wil6210_vif *vif, int ring_id, int cid,
			       int tid)
{
	struct wil6210_priv *wil = vif_to_wil(vif);
	int rc;
	struct wmi_vring_cfg_cmd cmd = {
		.action = cpu_to_le32(WMI_VRING_CMD_MODIFY),
		.vring_cfg = {
			.tx_sw_ring = {
				.max_mpdu_size =
					cpu_to_le16(wil_mtu2macbuf(mtu_max)),
				.ring_size = 0,
			},
			.ringid = ring_id,
			.cidxtid = mk_cidxtid(cid, tid),
			.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
			.mac_ctrl = 0,
			.to_resolution = 0,
			.agg_max_wsize = 0,
			.schd_params = {
				.priority = cpu_to_le16(0),
				.timeslot_us = cpu_to_le16(0xfff),
			},
		},
	};
	struct {
		struct wmi_cmd_hdr wmi;
		struct wmi_vring_cfg_done_event cmd;
	} __packed reply = {
		.cmd = {.status = WMI_FW_STATUS_FAILURE},
	};
	struct wil_ring *vring = &wil->ring_tx[ring_id];
	struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];

	wil_dbg_misc(wil, "vring_modify: ring %d cid %d tid %d\n", ring_id,
		     cid, tid);
	lockdep_assert_held(&wil->mutex);

	if (!vring->va) {
		wil_err(wil, "Tx ring [%d] not allocated\n", ring_id);
		return -EINVAL;
	}

	if (wil->ring2cid_tid[ring_id][0] != cid ||
	    wil->ring2cid_tid[ring_id][1] != tid) {
		wil_err(wil, "ring info does not match cid=%u tid=%u\n",
			wil->ring2cid_tid[ring_id][0],
			wil->ring2cid_tid[ring_id][1]);
	}

	cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);

	rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
		      WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
	if (rc)
		goto fail;

	if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) {
		wil_err(wil, "Tx modify failed, status 0x%02x\n",
			reply.cmd.status);
		rc = -EINVAL;
		goto fail;
	}

	/* set BA aggregation window size to 0 to force a new BA with the
	 * new AP
	 */
	txdata->agg_wsize = 0;
	if (txdata->dot1x_open && agg_wsize >= 0)
		wil_addba_tx_request(wil, ring_id, agg_wsize);

	return 0;
fail:
	spin_lock_bh(&txdata->lock);
	txdata->dot1x_open = false;
	txdata->enabled = 0;
	spin_unlock_bh(&txdata->lock);
	wil->ring2cid_tid[ring_id][0] = WIL6210_MAX_CID;
	wil->ring2cid_tid[ring_id][1] = 0;
	return rc;
}

int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size)
int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size)
{
{
	struct wil6210_priv *wil = vif_to_wil(vif);
	struct wil6210_priv *wil = vif_to_wil(vif);
@@ -2307,6 +2389,7 @@ void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil)
	wil->txrx_ops.ring_init_bcast = wil_vring_init_bcast;
	wil->txrx_ops.ring_init_bcast = wil_vring_init_bcast;
	wil->txrx_ops.tx_init = wil_tx_init;
	wil->txrx_ops.tx_init = wil_tx_init;
	wil->txrx_ops.tx_fini = wil_tx_fini;
	wil->txrx_ops.tx_fini = wil_tx_fini;
	wil->txrx_ops.tx_ring_modify = wil_tx_vring_modify;
	/* RX ops */
	/* RX ops */
	wil->txrx_ops.rx_init = wil_rx_init;
	wil->txrx_ops.rx_init = wil_rx_init;
	wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp;
	wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp;
+11 −0
Original line number Original line Diff line number Diff line
@@ -748,6 +748,16 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
	return rc;
	return rc;
}
}


static int wil_tx_ring_modify_edma(struct wil6210_vif *vif, int ring_id,
				   int cid, int tid)
{
	struct wil6210_priv *wil = vif_to_wil(vif);

	wil_err(wil, "ring modify is not supported for EDMA\n");

	return -EOPNOTSUPP;
}

/* This function is used only for RX SW reorder */
/* This function is used only for RX SW reorder */
static int wil_check_bar(struct wil6210_priv *wil, void *msg, int cid,
static int wil_check_bar(struct wil6210_priv *wil, void *msg, int cid,
			 struct sk_buff *skb, struct wil_net_stats *stats)
			 struct sk_buff *skb, struct wil_net_stats *stats)
@@ -1601,6 +1611,7 @@ void wil_init_txrx_ops_edma(struct wil6210_priv *wil)
	wil->txrx_ops.tx_desc_map = wil_tx_desc_map_edma;
	wil->txrx_ops.tx_desc_map = wil_tx_desc_map_edma;
	wil->txrx_ops.tx_desc_unmap = wil_tx_desc_unmap_edma;
	wil->txrx_ops.tx_desc_unmap = wil_tx_desc_unmap_edma;
	wil->txrx_ops.tx_ring_tso = __wil_tx_ring_tso_edma;
	wil->txrx_ops.tx_ring_tso = __wil_tx_ring_tso_edma;
	wil->txrx_ops.tx_ring_modify = wil_tx_ring_modify_edma;
	/* RX ops */
	/* RX ops */
	wil->txrx_ops.rx_init = wil_rx_init_edma;
	wil->txrx_ops.rx_init = wil_rx_init_edma;
	wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp_edma;
	wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp_edma;
Loading