From 36ee9d37b53c933f4dd8f934f8e0273b5e901549 Mon Sep 17 00:00:00 2001
From: Sathishkumar Muruganandam <murugana@codeaurora.org>
Date: Fri, 8 Jan 2021 00:02:54 +0530
Subject: [PATCH 1/3] mac80211: add dynamic VLAN support on NSS offload

NSS requires dynamic AP_VLAN vif ifnum and its corresponding VLAN ID
and group key index to configure dynamic VLAN ext VDEV in NSS.

Hence mac80211 set_key and sta_state callbacks are modified to advertise
AP_VLAN vif when NSS offload is enabled and VLAN ID provided by hostapd
in key params is stored to ieee80211_key_conf for the driver.

Co-Developed-by: Seevalamuthu Mariappan <seevalam@codeaurora.org>
Signed-off-by: Seevalamuthu Mariappan <seevalam@codeaurora.org>
Signed-off-by: Sathishkumar Muruganandam <murugana@codeaurora.org>
---
 include/net/mac80211.h    | 3 +++
 net/mac80211/cfg.c        | 1 +
 net/mac80211/driver-ops.c | 4 +++-
 net/mac80211/driver-ops.h | 4 +++-
 net/mac80211/key.c        | 5 ++++-
 net/mac80211/tx.c         | 4 ++++
 6 files changed, 18 insertions(+), 3 deletions(-)

--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1910,6 +1910,8 @@ enum ieee80211_key_flags {
  * @tx_pn: PN used for TX keys, may be used by the driver as well if it
  *	needs to do software PN assignment by itself (e.g. due to TSO)
  * @flags: key flags, see &enum ieee80211_key_flags.
+ * @vlan_id: VLAN ID corresponding to the group key.
+ *	For VLAN interfaces 1-4096, 0 for non-vlan interfaces
  * @keyidx: the key index (0-3)
  * @keylen: key material length
  * @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte)
@@ -1928,6 +1930,7 @@ struct ieee80211_key_conf {
 	u8 hw_key_idx;
 	s8 keyidx;
 	u16 flags;
+	u16 vlan_id;
 	u8 keylen;
 	u8 key[];
 };
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -510,6 +510,7 @@ static int ieee80211_add_key(struct wiph
 		break;
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_AP_VLAN:
+		key->conf.vlan_id = params->vlan_id;
 		/* Keys without a station are used for TX only */
 		if (sta && test_sta_flag(sta, WLAN_STA_MFP))
 			key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
--- a/net/mac80211/driver-ops.c
+++ b/net/mac80211/driver-ops.c
@@ -113,7 +113,11 @@ int drv_sta_state(struct ieee80211_local
 
 	might_sleep();
 
-	sdata = get_bss_sdata(sdata);
+	if (!ieee80211_hw_check(&local->hw, SUPPORTS_NSS_OFFLOAD) ||
+	    !(old_state == IEEE80211_STA_ASSOC &&
+	      new_state == IEEE80211_STA_AUTHORIZED))
+		sdata = get_bss_sdata(sdata);
+
 	if (!check_sdata_in_driver(sdata))
 		return -EIO;
 
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -261,7 +261,9 @@ static inline int drv_set_key(struct iee
 
 	might_sleep();
 
-	sdata = get_bss_sdata(sdata);
+	if (!ieee80211_hw_check(&local->hw, SUPPORTS_NSS_OFFLOAD))
+		sdata = get_bss_sdata(sdata);
+
 	if (!check_sdata_in_driver(sdata))
 		return -EIO;
 
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -167,7 +167,8 @@ static int ieee80211_key_enable_hw_accel
 		goto out_unsupported;
 
 	sdata = key->sdata;
-	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+	    !ieee80211_hw_check(&key->local->hw, SUPPORTS_NSS_OFFLOAD)) {
 		/*
 		 * The driver doesn't know anything about VLAN interfaces.
 		 * Hence, don't send GTKs for VLAN interfaces to the driver.
@@ -553,6 +554,8 @@ ieee80211_key_alloc(u32 cipher, int idx,
 	 */
 	key->conf.flags = 0;
 	key->flags = 0;
+	/* VLAN ID initialised to zero for non-vlan interfaces */
+	key->conf.vlan_id = 0;
 
 	key->conf.cipher = cipher;
 	key->conf.keyidx = idx;
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4248,8 +4248,11 @@ static void ieee80211_8023_xmit(struct i
 				struct ieee80211_key *key, struct sk_buff *skb)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ethhdr *ehdr = (struct ethhdr *)skb->data;
 	struct ieee80211_local *local = sdata->local;
 	struct tid_ampdu_tx *tid_tx;
+	unsigned char *ra = ehdr->h_dest;
+	bool multicast;
 	u8 tid;
 
 	if (local->ops->wake_tx_queue) {
@@ -4258,6 +4261,12 @@ static void ieee80211_8023_xmit(struct i
 		skb_get_hash(skb);
 	}
 
+	multicast = is_multicast_ether_addr(ra);
+
+	if (multicast && sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+	    !atomic_read(&sdata->u.vlan.num_mcast_sta))
+		goto out_free;
+
 	if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
 	    test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
 		goto out_free;
