Search Linux Wireless

[PATCH] cfg80211: Add support for sending more than two AKMs in crypto settings

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add support to indicate maximum number of AKMs allowed in
NL80211_CMD_CONNECT, NL80211_CMD_ASSOCIATE and NL80211_CMD_START_AP.
If the driver doesn't indicate the capability, maximum limit is set to
the legacy value i.e. NL80211_MAX_NR_AKM_SUITE.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@xxxxxxxxxxx>
---
 drivers/net/wireless/ath/wil6210/cfg80211.c       |  3 +--
 drivers/net/wireless/quantenna/qtnfmac/commands.c |  6 ++++--
 include/net/cfg80211.h                            |  6 +++++-
 include/uapi/linux/nl80211.h                      | 15 +++++++++++++++
 net/wireless/core.c                               | 11 +++++++++++
 net/wireless/nl80211.c                            | 15 +++++++++++++--
 net/wireless/sme.c                                | 20 +++++++++++++++++++-
 net/wireless/wext-compat.c                        |  8 ++++++++
 8 files changed, 76 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 764d1d1..ac40fe2 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1073,8 +1073,7 @@ static void wil_print_crypto(struct wil6210_priv *wil,
 			     c->ciphers_pairwise[i]);
 	wil_dbg_misc(wil, "}\n");
 	wil_dbg_misc(wil, "AKM suites [%d] {\n", c->n_akm_suites);
-	n = min_t(int, c->n_akm_suites, ARRAY_SIZE(c->akm_suites));
-	for (i = 0; i < n; i++)
+	for (i = 0; i < c->n_akm_suites; i++)
 		wil_dbg_misc(wil, "  [%d] = 0x%08x\n", i,
 			     c->akm_suites[i]);
 	wil_dbg_misc(wil, "}\n");
diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c
index c68563c..866355ae 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/commands.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c
@@ -281,7 +281,8 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
 		aen->ciphers_pairwise[i] =
 				cpu_to_le32(s->crypto.ciphers_pairwise[i]);
 	aen->n_akm_suites = cpu_to_le32(s->crypto.n_akm_suites);
-	for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++)
+	for (i = 0; i < min(QLINK_MAX_NR_AKM_SUITES, s->crypto.n_akm_suites);
+	     i++)
 		aen->akm_suites[i] = cpu_to_le32(s->crypto.akm_suites[i]);
 	aen->control_port = s->crypto.control_port;
 	aen->control_port_no_encrypt = s->crypto.control_port_no_encrypt;
@@ -2134,7 +2135,8 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif,
 
 	aen->n_akm_suites = cpu_to_le32(sme->crypto.n_akm_suites);
 
-	for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++)
+	for (i = 0; i < min(QLINK_MAX_NR_AKM_SUITES, s->crypto.n_akm_suites);
+	     i++)
 		aen->akm_suites[i] = cpu_to_le32(sme->crypto.akm_suites[i]);
 
 	aen->control_port = sme->crypto.control_port;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 6871338..48c7ab1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1112,7 +1112,7 @@ struct cfg80211_crypto_settings {
 	int n_ciphers_pairwise;
 	u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES];
 	int n_akm_suites;
-	u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
+	u32 *akm_suites;
 	bool control_port;
 	__be16 control_port_ethertype;
 	bool control_port_no_encrypt;
@@ -5129,6 +5129,9 @@ struct wiphy_iftype_akm_suites {
  * @ema_max_profile_periodicity: maximum profile periodicity supported by
  *	the driver. Setting this field to a non-zero value indicates that the
  *	driver supports enhanced multi-BSSID advertisements (EMA AP).
+ * @max_num_akm_suites: maximum supported number of AKM suites for
+ *	configuration through %NL80211_CMD_CONNECT, %NL80211_CMD_ASSOCIATE and
+ *	%NL80211_CMD_START_AP.
  */
 struct wiphy {
 	struct mutex mtx;
@@ -5275,6 +5278,7 @@ struct wiphy {
 
 	u8 mbssid_max_interfaces;
 	u8 ema_max_profile_periodicity;
+	u16 max_num_akm_suites;
 
 	char priv[] __aligned(NETDEV_ALIGN);
 };
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 0568a79..00fa5ea 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2663,6 +2663,13 @@ enum nl80211_commands {
  *	association request when used with NL80211_CMD_NEW_STATION). Can be set
  *	only if %NL80211_STA_FLAG_WME is set.
  *
+ * @NL80211_ATTR_MAX_NUM_AKM_SUITES: U16 attribute. Indicates maximum number of
+ *	AKM suites allowed for %NL80211_CMD_CONNECT, %NL80211_CMD_ASSOCIATE and
+ *	%NL80211_CMD_START_AP. If this attribute is not present userspace shall
+ *	consider maximum number of AKM suites supported as
+ *	%NL80211_MAX_NR_AKM_SUITES which is the legacy maximum number prior to
+ *	the introduction of this attribute.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3175,6 +3182,8 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_EHT_CAPABILITY,
 
+	NL80211_ATTR_MAX_NUM_AKM_SUITES,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -3229,6 +3238,12 @@ enum nl80211_attrs {
 #define NL80211_HE_MIN_CAPABILITY_LEN           16
 #define NL80211_HE_MAX_CAPABILITY_LEN           54
 #define NL80211_MAX_NR_CIPHER_SUITES		5
+
+/*
+ * NL80211_MAX_NR_AKM_SUITES is obsolete and not used for indicating maximum
+ * number of supported AKM suites. Instead, maximum number of supported AKM
+ * suites is indicated using %NL80211_ATTR_MAX_NUM_AKM_SUITES attribute.
+ */
 #define NL80211_MAX_NR_AKM_SUITES		2
 #define NL80211_EHT_MIN_CAPABILITY_LEN          13
 #define NL80211_EHT_MAX_CAPABILITY_LEN          51
diff --git a/net/wireless/core.c b/net/wireless/core.c
index f08d4b3..282cabc 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -913,6 +913,15 @@ int wiphy_register(struct wiphy *wiphy)
 		return -EINVAL;
 #endif
 
+	/*
+	 * Maximum number of AKM suites allowed for NL80211_CMD_CONECT,
+	 * NL80211_CMD_ASSOCIATE and NL80211_CMD_START_AP, must be at least
+	 * NL80211_MAX_NR_AKM_SUITES to avoid issues with legacy userspace.
+	 */
+	if (WARN_ON(wiphy->max_num_akm_suites &&
+		    wiphy->max_num_akm_suites < NL80211_MAX_NR_AKM_SUITES))
+		return -EINVAL;
+
 	/* check and set up bitrates */
 	ieee80211_set_bitrate_flags(wiphy);
 
@@ -1154,6 +1163,8 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
 #ifdef CONFIG_CFG80211_WEXT
 	kfree_sensitive(wdev->wext.keys);
 	wdev->wext.keys = NULL;
+	kfree(wdev->wext.connect.crypto.akm_suites);
+	wdev->wext.connect.crypto.akm_suites = NULL;
 #endif
 	/* only initialized if we have a netdev */
 	if (wdev->netdev)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 711061c..4b7cbd5 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -790,6 +790,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
 		NLA_POLICY_RANGE(NLA_BINARY,
 				 NL80211_EHT_MIN_CAPABILITY_LEN,
 				 NL80211_EHT_MAX_CAPABILITY_LEN),
+	[NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_U16 },
 };
 
 /* policy for the key attributes */
@@ -2889,6 +2890,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
 		if (nl80211_put_mbssid_support(&rdev->wiphy, msg))
 			goto nla_put_failure;
 
+		if (nla_put_u16(msg, NL80211_ATTR_MAX_NUM_AKM_SUITES,
+				rdev->wiphy.max_num_akm_suites ?
+				rdev->wiphy.max_num_akm_suites :
+				NL80211_MAX_NR_AKM_SUITES))
+			goto nla_put_failure;
+
 		/* done */
 		state->split_start = 0;
 		break;
@@ -10253,6 +10260,7 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
 	if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
 		void *data;
 		int len;
+		int max_num_akm_suites = NL80211_MAX_NR_AKM_SUITES;
 
 		data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
 		len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
@@ -10261,10 +10269,13 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
 		if (len % sizeof(u32))
 			return -EINVAL;
 
-		if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
+		if (rdev->wiphy.max_num_akm_suites)
+			max_num_akm_suites = rdev->wiphy.max_num_akm_suites;
+
+		if (settings->n_akm_suites > max_num_akm_suites)
 			return -EINVAL;
 
-		memcpy(settings->akm_suites, data, len);
+		settings->akm_suites = data;
 	}
 
 	if (info->attrs[NL80211_ATTR_PMK]) {
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index ff4d48fc..1ff9513 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -57,6 +57,7 @@ static void cfg80211_sme_free(struct wireless_dev *wdev)
 		return;
 
 	kfree(wdev->conn->ie);
+	kfree(wdev->conn->params.crypto.akm_suites);
 	kfree(wdev->conn);
 	wdev->conn = NULL;
 }
@@ -537,7 +538,8 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
 		return -ENOMEM;
 
 	/*
-	 * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
+	 * Copy all parameters, and treat explicitly IEs, BSSID, SSID,
+	 * AKM SUITES.
 	 */
 	memcpy(&wdev->conn->params, connect, sizeof(*connect));
 	if (connect->bssid) {
@@ -563,6 +565,22 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
 		wdev->conn->auto_auth = false;
 	}
 
+	if (connect->crypto.n_akm_suites) {
+		wdev->conn->params.crypto.akm_suites =
+			kcalloc(connect->crypto.n_akm_suites, sizeof(u32),
+				GFP_KERNEL);
+		if (!wdev->conn->params.crypto.akm_suites) {
+			cfg80211_sme_free(wdev);
+			return -ENOMEM;
+		}
+
+		wdev->conn->params.crypto.n_akm_suites =
+			connect->crypto.n_akm_suites;
+		memcpy(wdev->conn->params.crypto.akm_suites,
+		       connect->crypto.akm_suites,
+		       sizeof(u32) * connect->crypto.n_akm_suites);
+	}
+
 	wdev->conn->params.ssid = wdev->ssid;
 	wdev->conn->params.ssid_len = wdev->ssid_len;
 
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index a32065d..0d262e9 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -1102,6 +1102,14 @@ static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt)
 			IW_AUTH_KEY_MGMT_PSK))
 		return -EINVAL;
 
+	if (!wdev->wext.connect.crypto.akm_suites) {
+		wdev->wext.connect.crypto.akm_suites =
+			kcalloc(NL80211_MAX_NR_AKM_SUITES, sizeof(u32),
+				GFP_KERNEL);
+		if (!wdev->wext.connect.crypto.akm_suites)
+			return -ENOMEM;
+	}
+
 	if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) {
 		wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
 			WLAN_AKM_SUITE_8021X;
-- 
2.7.4




[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux