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

Commit 230d8442 authored by Vladimir Kondratiev's avatar Vladimir Kondratiev Committed by Kalle Valo
Browse files

wil6210: broadcast for secure link



Introduce 2 types of GTK, Tx (for this STA) and Rx (for each peer).
Now, AP has only Tx GTK, STA - only Rx one. PBSS not supported yet;
for it, continue using pseudo-DMS.
Handle per-vring .1x state, update it from WMI_VRING_EN_EVENTID
event. This allows unification for unicast and broadcast vrings.
This mechanism replaces former per-CID "data_port_open"

Signed-off-by: default avatarVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent dc16427b
Loading
Loading
Loading
Loading
+50 −14
Original line number Diff line number Diff line
@@ -425,10 +425,17 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	wil->privacy = sme->privacy;

	if (wil->privacy) {
		/* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */
		rc = wmi_del_cipher_key(wil, 0, bss->bssid);
		/* For secure assoc, remove old keys */
		rc = wmi_del_cipher_key(wil, 0, bss->bssid,
					WMI_KEY_USE_PAIRWISE);
		if (rc) {
			wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
			wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n");
			goto out;
		}
		rc = wmi_del_cipher_key(wil, 0, bss->bssid,
					WMI_KEY_USE_RX_GROUP);
		if (rc) {
			wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n");
			goto out;
		}
	}
@@ -462,6 +469,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
		conn.auth_mode = WMI_AUTH_WPA2_PSK;
		conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
		conn.pairwise_crypto_len = 16;
		conn.group_crypto_type = WMI_CRYPT_AES_GCMP;
		conn.group_crypto_len = 16;
	} else {
		conn.dot11_auth_mode = WMI_AUTH11_OPEN;
		conn.auth_mode = WMI_AUTH_NONE;
@@ -563,6 +572,39 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy,
	return 0;
}

static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil,
					       bool pairwise)
{
	struct wireless_dev *wdev = wil->wdev;
	enum wmi_key_usage rc;
	static const char * const key_usage_str[] = {
		[WMI_KEY_USE_PAIRWISE]	= "WMI_KEY_USE_PAIRWISE",
		[WMI_KEY_USE_RX_GROUP]	= "WMI_KEY_USE_RX_GROUP",
		[WMI_KEY_USE_TX_GROUP]	= "WMI_KEY_USE_TX_GROUP",
	};

	if (pairwise) {
		rc = WMI_KEY_USE_PAIRWISE;
	} else {
		switch (wdev->iftype) {
		case NL80211_IFTYPE_STATION:
			rc = WMI_KEY_USE_RX_GROUP;
			break;
		case NL80211_IFTYPE_AP:
			rc = WMI_KEY_USE_TX_GROUP;
			break;
		default:
			/* TODO: Rx GTK or Tx GTK? */
			wil_err(wil, "Can't determine GTK type\n");
			rc = WMI_KEY_USE_RX_GROUP;
			break;
		}
	}
	wil_dbg_misc(wil, "%s() -> %s\n", __func__, key_usage_str[rc]);

	return rc;
}

static int wil_cfg80211_add_key(struct wiphy *wiphy,
				struct net_device *ndev,
				u8 key_index, bool pairwise,
@@ -570,16 +612,13 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
				struct key_params *params)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);

	wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
		     pairwise ? "PTK" : "GTK");

	/* group key is not used */
	if (!pairwise)
		return 0;

	return wmi_add_cipher_key(wil, key_index, mac_addr,
				  params->key_len, params->key);
	return wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len,
				  params->key, key_usage);
}

static int wil_cfg80211_del_key(struct wiphy *wiphy,
@@ -588,15 +627,12 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy,
				const u8 *mac_addr)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);

	wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
		     pairwise ? "PTK" : "GTK");

	/* group key is not used */
	if (!pairwise)
		return 0;

	return wmi_del_cipher_key(wil, key_index, mac_addr);
	return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage);
}

/* Need to be present or wiphy_new() will WARN */
+7 −7
Original line number Diff line number Diff line
/*
 * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
 * Copyright (c) 2012-2015 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
@@ -124,15 +124,17 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)

			if (cid < WIL6210_MAX_CID)
				seq_printf(s,
					   "\n%pM CID %d TID %d BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
					   "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
					   wil->sta[cid].addr, cid, tid,
					   txdata->dot1x_open ? "+" : "-",
					   txdata->agg_wsize,
					   txdata->agg_timeout,
					   txdata->agg_amsdu ? "+" : "-",
					   used, avail, sidle);
			else
				seq_printf(s,
					   "\nBroadcast [%3d|%3d] idle %s\n",
					   "\nBroadcast 1x%s [%3d|%3d] idle %s\n",
					   txdata->dot1x_open ? "+" : "-",
					   used, avail, sidle);

			wil_print_vring(s, wil, name, vring, '_', 'H');
@@ -1195,8 +1197,7 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
			status = "connected";
			break;
		}
		seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
			   (p->data_port_open ? " data_port_open" : ""));
		seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);

		if (p->status == wil_sta_connected) {
			rc = wil_cid_fill_sinfo(wil, i, &sinfo);
@@ -1376,8 +1377,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
			status = "connected";
			break;
		}
		seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
			   (p->data_port_open ? " data_port_open" : ""));
		seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);

		if (p->status == wil_sta_connected) {
			spin_lock_bh(&p->tid_rx_lock);
+3 −3
Original line number Diff line number Diff line
@@ -150,7 +150,6 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
	wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
		     sta->status);

	sta->data_port_open = false;
	if (sta->status != wil_sta_unused) {
		if (!from_event)
			wmi_disconnect_sta(wil, sta->addr, reason_code);
@@ -377,9 +376,10 @@ int wil_bcast_init(struct wil6210_priv *wil)
	if (ri < 0)
		return ri;

	rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order);
	if (rc == 0)
	wil->bcast_vring = ri;
	rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order);
	if (rc)
		wil->bcast_vring = -1;

	return rc;
}
+25 −21
Original line number Diff line number Diff line
/*
 * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
 * Copyright (c) 2012-2015 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
@@ -724,6 +724,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,

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

	if (!wil->privacy)
		txdata->dot1x_open = true;
	rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
		      WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
	if (rc)
@@ -738,11 +740,13 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
	vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);

	txdata->enabled = 1;
	if (wil->sta[cid].data_port_open && (agg_wsize >= 0))
	if (txdata->dot1x_open && (agg_wsize >= 0))
		wil_addba_tx_request(wil, id, agg_wsize);

	return 0;
 out_free:
	txdata->dot1x_open = false;
	txdata->enabled = 0;
	wil_vring_free(wil, vring, 1);
 out:

@@ -792,6 +796,8 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)

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

	if (!wil->privacy)
		txdata->dot1x_open = true;
	rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, &cmd, sizeof(cmd),
		      WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
	if (rc)
@@ -809,6 +815,8 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)

	return 0;
 out_free:
	txdata->enabled = 0;
	txdata->dot1x_open = false;
	wil_vring_free(wil, vring, 1);
 out:

@@ -828,6 +836,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
	wil_dbg_misc(wil, "%s() id=%d\n", __func__, id);

	spin_lock_bh(&txdata->lock);
	txdata->dot1x_open = false;
	txdata->enabled = 0; /* no Tx can be in progress or start anew */
	spin_unlock_bh(&txdata->lock);
	/* make sure NAPI won't touch this vring */
@@ -848,12 +857,11 @@ static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
	if (cid < 0)
		return NULL;

	if (!wil->sta[cid].data_port_open &&
	    (skb->protocol != cpu_to_be16(ETH_P_PAE)))
		return NULL;

	/* TODO: fix for multiple TID */
	for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
		if (!wil->vring_tx_data[i].dot1x_open &&
		    (skb->protocol != cpu_to_be16(ETH_P_PAE)))
			continue;
		if (wil->vring2cid_tid[i][0] == cid) {
			struct vring *v = &wil->vring_tx[i];

@@ -883,7 +891,7 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,

	/* In the STA mode, it is expected to have only 1 VRING
	 * for the AP we connected to.
	 * find 1-st vring and see whether it is eligible for data
	 * find 1-st vring eligible for this skb and use it.
	 */
	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
		v = &wil->vring_tx[i];
@@ -894,9 +902,9 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
		if (cid >= WIL6210_MAX_CID) /* skip BCAST */
			continue;

		if (!wil->sta[cid].data_port_open &&
		if (!wil->vring_tx_data[i].dot1x_open &&
		    (skb->protocol != cpu_to_be16(ETH_P_PAE)))
			break;
			continue;

		wil_dbg_txrx(wil, "Tx -> ring %d\n", i);

@@ -918,7 +926,6 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
 *    in all cases override dest address to unicast peer's address
 * Use old strategy when new is not supported yet:
 *  - for PBSS
 *  - for secure link
 */
static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
					 struct sk_buff *skb)
@@ -931,6 +938,9 @@ static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
	v = &wil->vring_tx[i];
	if (!v->va)
		return NULL;
	if (!wil->vring_tx_data[i].dot1x_open &&
	    (skb->protocol != cpu_to_be16(ETH_P_PAE)))
		return NULL;

	return v;
}
@@ -963,7 +973,8 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
		cid = wil->vring2cid_tid[i][0];
		if (cid >= WIL6210_MAX_CID) /* skip BCAST */
			continue;
		if (!wil->sta[cid].data_port_open)
		if (!wil->vring_tx_data[i].dot1x_open &&
		    (skb->protocol != cpu_to_be16(ETH_P_PAE)))
			continue;

		/* don't Tx back to source when re-routing Rx->Tx at the AP */
@@ -989,7 +1000,8 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
		cid = wil->vring2cid_tid[i][0];
		if (cid >= WIL6210_MAX_CID) /* skip BCAST */
			continue;
		if (!wil->sta[cid].data_port_open)
		if (!wil->vring_tx_data[i].dot1x_open &&
		    (skb->protocol != cpu_to_be16(ETH_P_PAE)))
			continue;

		if (0 == memcmp(wil->sta[cid].addr, src, ETH_ALEN))
@@ -1016,9 +1028,6 @@ static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil,
	if (wdev->iftype != NL80211_IFTYPE_AP)
		return wil_find_tx_bcast_2(wil, skb);

	if (wil->privacy)
		return wil_find_tx_bcast_2(wil, skb);

	return wil_find_tx_bcast_1(wil, skb);
}

@@ -1144,13 +1153,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
	wil_tx_desc_map(d, pa, len, vring_index);
	if (unlikely(mcast)) {
		d->mac.d[0] |= BIT(MAC_CFG_DESC_TX_0_MCS_EN_POS); /* MCS 0 */
		if (unlikely(len > WIL_BCAST_MCS0_LIMIT)) {
			/* set MCS 1 */
		if (unlikely(len > WIL_BCAST_MCS0_LIMIT)) /* set MCS 1 */
			d->mac.d[0] |= (1 << MAC_CFG_DESC_TX_0_MCS_INDEX_POS);
			/* packet mode 2 */
			d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS) |
				       (2 << MAC_CFG_DESC_TX_1_PKT_MODE_POS);
		}
	}
	/* Process TCP/UDP checksum offloading */
	if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) {
+4 −3
Original line number Diff line number Diff line
@@ -398,6 +398,7 @@ struct vring {
 * Additional data for Tx Vring
 */
struct vring_tx_data {
	bool dot1x_open;
	int enabled;
	cycles_t idle, last_idle, begin;
	u8 agg_wsize; /* agreed aggregation window, 0 - no agg */
@@ -486,7 +487,6 @@ struct wil_sta_info {
	u8 addr[ETH_ALEN];
	enum wil_sta_status status;
	struct wil_net_stats stats;
	bool data_port_open; /* can send any data, not only EAPOL */
	/* Rx BACK */
	struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
	spinlock_t tid_rx_lock; /* guarding tid_rx array */
@@ -716,9 +716,10 @@ int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid);
int wmi_set_channel(struct wil6210_priv *wil, int channel);
int wmi_get_channel(struct wil6210_priv *wil, int *channel);
int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
		       const void *mac_addr);
		       const void *mac_addr, int key_usage);
int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
		       const void *mac_addr, int key_len, const void *key);
		       const void *mac_addr, int key_len, const void *key,
		       int key_usage);
int wmi_echo(struct wil6210_priv *wil);
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
Loading