diff mbox series

[RFC,v1,103/256] cl8k: add key.c

Message ID 20210617160223.160998-104-viktor.barna@celeno.com
State New
Headers show
Series wireless: cl8k driver for Celeno IEEE 802.11ax devices | expand

Commit Message

Viktor Barna June 17, 2021, 3:59 p.m. UTC
From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/key.c | 197 +++++++++++++++++++++++++
 1 file changed, 197 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/key.c

--
2.30.0
diff mbox series

Patch

diff --git a/drivers/net/wireless/celeno/cl8k/key.c b/drivers/net/wireless/celeno/cl8k/key.c
new file mode 100644
index 000000000000..276c2e76e126
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/key.c
@@ -0,0 +1,197 @@ 
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "key.h"
+#include "fw/msg_tx.h"
+#include "fw/fw_msg.h"
+#include "sta.h"
+#include "tx/single_cfm.h"
+#include "tx/agg_cfm.h"
+#include "tx/tx_queue.h"
+
+static int cmd_set_key(struct cl_hw *cl_hw,
+                      struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta,
+                      struct ieee80211_key_conf *key)
+{
+       int error = 0;
+       struct mm_key_add_cfm *key_add_cfm;
+       u8 cipher_suite = 0;
+
+       /* Retrieve the cipher suite selector */
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+               cipher_suite = MAC_CIPHER_SUITE_WEP40;
+               break;
+       case WLAN_CIPHER_SUITE_WEP104:
+               cipher_suite = MAC_CIPHER_SUITE_WEP104;
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+               cipher_suite = MAC_CIPHER_SUITE_TKIP;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               cipher_suite = MAC_CIPHER_SUITE_CCMP;
+               break;
+       case WLAN_CIPHER_SUITE_GCMP:
+       case WLAN_CIPHER_SUITE_GCMP_256:
+               cipher_suite = MAC_CIPHER_SUITE_GCMP;
+               break;
+       case WLAN_CIPHER_SUITE_AES_CMAC:
+               return -EOPNOTSUPP;
+       default:
+               return -EINVAL;
+       }
+
+       error = cl_msg_tx_key_add(cl_hw, vif, sta, key, cipher_suite);
+       if (error)
+               return error;
+
+       key_add_cfm = (struct mm_key_add_cfm *)(cl_hw->msg_cfm_params[MM_KEY_ADD_CFM]);
+       if (!key_add_cfm)
+               return -ENOMSG;
+
+       if (key_add_cfm->status != 0) {
+               cl_dbg_verbose(cl_hw, "Status Error (%u)\n", key_add_cfm->status);
+               cl_msg_tx_free_cfm_params(cl_hw, MM_KEY_ADD_CFM);
+               return -EIO;
+       }
+
+       /* Save the index retrieved from firmware */
+       key->hw_key_idx = key_add_cfm->hw_key_idx;
+
+       cl_msg_tx_free_cfm_params(cl_hw, MM_KEY_ADD_CFM);
+
+       /*
+        * Now inform mac80211 about our choices regarding header fields generation:
+        * we let mac80211 take care of all generations
+        */
+       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+       if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
+               key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+
+       if (sta) {
+               struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+
+               cl_sta->key_conf = key;
+       } else {
+               struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+
+               cl_vif->key_conf = key;
+       }
+
+       return error;
+}
+
+static int cmd_disable_key(struct cl_hw *cl_hw,
+                          struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta,
+                          struct ieee80211_key_conf *key)
+{
+       if (sta) {
+               struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+
+               cl_sta->key_conf = NULL;
+               cl_sta->key_disable = true;
+
+               /*
+                * Make sure there aren't any packets in firmware before deleting the key,
+                * otherwise they will be transmitted without encryption.
+                */
+               cl_txq_flush_sta(cl_hw, cl_sta);
+               cl_single_cfm_poll_empty_sta(cl_hw, cl_sta->sta_idx);
+               cl_agg_cfm_poll_empty_sta(cl_hw, cl_sta);
+       } else {
+               struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+
+               cl_vif->key_conf = NULL;
+       }
+
+       return cl_msg_tx_key_del(cl_hw, key->hw_key_idx);
+}
+
+int cl_key_set(struct cl_hw *cl_hw,
+              enum set_key_cmd cmd,
+              struct ieee80211_vif *vif,
+              struct ieee80211_sta *sta,
+              struct ieee80211_key_conf *key)
+{
+       int error = 0;
+
+       switch (cmd) {
+       case SET_KEY:
+               error = cmd_set_key(cl_hw, vif, sta, key);
+               break;
+
+       case DISABLE_KEY:
+               error = cmd_disable_key(cl_hw, vif, sta, key);
+               break;
+
+       default:
+               error = -EINVAL;
+               break;
+       }
+
+       return error;
+}
+
+struct ieee80211_key_conf *cl_key_get(struct cl_sta *cl_sta)
+{
+       if (cl_sta->key_conf)
+               return cl_sta->key_conf;
+
+       if (cl_sta->cl_vif->key_conf)
+               return cl_sta->cl_vif->key_conf;
+
+       return NULL;
+}
+
+bool cl_key_is_cipher_ccmp_gcmp(struct ieee80211_key_conf *keyconf)
+{
+       u32 cipher;
+
+       if (!keyconf)
+               return false;
+
+       cipher = keyconf->cipher;
+
+       return ((cipher == WLAN_CIPHER_SUITE_CCMP) ||
+               (cipher == WLAN_CIPHER_SUITE_GCMP) ||
+               (cipher == WLAN_CIPHER_SUITE_GCMP_256));
+}
+
+void cl_key_ccmp_gcmp_pn_to_hdr(u8 *hdr, u64 pn, int key_id)
+{
+       hdr[0] = pn;
+       hdr[1] = pn >> 8;
+       hdr[2] = 0;
+       hdr[3] = 0x20 | (key_id << 6);
+       hdr[4] = pn >> 16;
+       hdr[5] = pn >> 24;
+       hdr[6] = pn >> 32;
+       hdr[7] = pn >> 40;
+}
+
+u8 cl_key_get_cipher_len(struct sk_buff *skb)
+{
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+
+       if (key_conf) {
+               switch (key_conf->cipher) {
+               case WLAN_CIPHER_SUITE_WEP40:
+               case WLAN_CIPHER_SUITE_WEP104:
+                       return IEEE80211_WEP_IV_LEN;
+               case WLAN_CIPHER_SUITE_TKIP:
+                       return  IEEE80211_TKIP_IV_LEN;
+               case WLAN_CIPHER_SUITE_CCMP:
+                       return  IEEE80211_CCMP_HDR_LEN;
+               case WLAN_CIPHER_SUITE_CCMP_256:
+                       return  IEEE80211_CCMP_256_HDR_LEN;
+               case WLAN_CIPHER_SUITE_GCMP:
+               case WLAN_CIPHER_SUITE_GCMP_256:
+                       return  IEEE80211_GCMP_HDR_LEN;
+               }
+       }
+
+       return 0;
+}