wifi: wilc1000: add IGTK support
authorAjay Singh <ajay.kathat@microchip.com>
Tue, 24 May 2022 12:06:21 +0000 (12:06 +0000)
committerKalle Valo <kvalo@kernel.org>
Mon, 30 May 2022 11:18:00 +0000 (14:18 +0300)
Add support to handle IGTK keys which are required for MFP to FW. Index ID
4 and 5 are used to store the IGTK key.

Signed-off-by: Ajay Singh <ajay.kathat@microchip.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220524120606.9675-4-ajay.kathat@microchip.com
drivers/net/wireless/microchip/wilc1000/cfg80211.c
drivers/net/wireless/microchip/wilc1000/fw.h
drivers/net/wireless/microchip/wilc1000/hif.c
drivers/net/wireless/microchip/wilc1000/hif.h
drivers/net/wireless/microchip/wilc1000/netdev.h
drivers/net/wireless/microchip/wilc1000/wlan_if.h

index ea59ce9..1ac4684 100644 (file)
@@ -307,6 +307,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
        int ret;
        u32 i;
        u8 security = WILC_FW_SEC_NO;
+       enum mfptype mfp_type = WILC_FW_MFP_NONE;
        enum authtype auth_type = WILC_FW_AUTH_ANY;
        u32 cipher_group;
        struct cfg80211_bss *bss;
@@ -416,6 +417,13 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
        wfi_drv->conn_info.arg = priv;
        wfi_drv->conn_info.param = join_params;
 
+       if (sme->mfp == NL80211_MFP_OPTIONAL)
+               mfp_type = WILC_FW_MFP_OPTIONAL;
+       else if (sme->mfp == NL80211_MFP_REQUIRED)
+               mfp_type = WILC_FW_MFP_REQUIRED;
+
+       wfi_drv->conn_info.mfp_type = mfp_type;
+
        ret = wilc_set_join_req(vif, bss->bssid, sme->ie, sme->ie_len);
        if (ret) {
                netdev_err(dev, "wilc_set_join_req(): Error\n");
@@ -495,6 +503,18 @@ static int wilc_wfi_cfg_allocate_wpa_entry(struct wilc_priv *priv, u8 idx)
        return 0;
 }
 
+static int wilc_wfi_cfg_allocate_wpa_igtk_entry(struct wilc_priv *priv, u8 idx)
+{
+       idx -= 4;
+       if (!priv->wilc_igtk[idx]) {
+               priv->wilc_igtk[idx] = kzalloc(sizeof(*priv->wilc_igtk[idx]),
+                                              GFP_KERNEL);
+               if (!priv->wilc_igtk[idx])
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
 static int wilc_wfi_cfg_copy_wpa_info(struct wilc_wfi_key *key_info,
                                      struct key_params *params)
 {
@@ -531,6 +551,7 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
        u8 op_mode;
        struct wilc_vif *vif = netdev_priv(netdev);
        struct wilc_priv *priv = &vif->priv;
+       struct wilc_wfi_key *key;
 
        switch (params->cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
@@ -594,6 +615,26 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
                                           key_index);
 
                break;
+       case WLAN_CIPHER_SUITE_AES_CMAC:
+               ret = wilc_wfi_cfg_allocate_wpa_igtk_entry(priv, key_index);
+               if (ret)
+                       return -ENOMEM;
+
+               key = priv->wilc_igtk[key_index - 4];
+               ret = wilc_wfi_cfg_copy_wpa_info(key, params);
+               if (ret)
+                       return -ENOMEM;
+
+               if (priv->wdev.iftype == NL80211_IFTYPE_AP ||
+                   priv->wdev.iftype == NL80211_IFTYPE_P2P_GO)
+                       op_mode = WILC_AP_MODE;
+               else
+                       op_mode = WILC_STATION_MODE;
+
+               ret = wilc_add_igtk(vif, params->key, keylen, params->seq,
+                                   params->seq_len, mac_addr, op_mode,
+                                   key_index);
+               break;
 
        default:
                netdev_err(netdev, "%s: Unsupported cipher\n", __func__);
@@ -611,23 +652,34 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev,
        struct wilc_vif *vif = netdev_priv(netdev);
        struct wilc_priv *priv = &vif->priv;
 
-       if (priv->wilc_gtk[key_index]) {
-               kfree(priv->wilc_gtk[key_index]->key);
-               priv->wilc_gtk[key_index]->key = NULL;
-               kfree(priv->wilc_gtk[key_index]->seq);
-               priv->wilc_gtk[key_index]->seq = NULL;
-
-               kfree(priv->wilc_gtk[key_index]);
-               priv->wilc_gtk[key_index] = NULL;
-       }
-
-       if (priv->wilc_ptk[key_index]) {
-               kfree(priv->wilc_ptk[key_index]->key);
-               priv->wilc_ptk[key_index]->key = NULL;
-               kfree(priv->wilc_ptk[key_index]->seq);
-               priv->wilc_ptk[key_index]->seq = NULL;
-               kfree(priv->wilc_ptk[key_index]);
-               priv->wilc_ptk[key_index] = NULL;
+       if (!pairwise && (key_index == 4 || key_index == 5)) {
+               key_index -= 4;
+               if (priv->wilc_igtk[key_index]) {
+                       kfree(priv->wilc_igtk[key_index]->key);
+                       priv->wilc_igtk[key_index]->key = NULL;
+                       kfree(priv->wilc_igtk[key_index]->seq);
+                       priv->wilc_igtk[key_index]->seq = NULL;
+                       kfree(priv->wilc_igtk[key_index]);
+                       priv->wilc_igtk[key_index] = NULL;
+               }
+       } else {
+               if (priv->wilc_gtk[key_index]) {
+                       kfree(priv->wilc_gtk[key_index]->key);
+                       priv->wilc_gtk[key_index]->key = NULL;
+                       kfree(priv->wilc_gtk[key_index]->seq);
+                       priv->wilc_gtk[key_index]->seq = NULL;
+
+                       kfree(priv->wilc_gtk[key_index]);
+                       priv->wilc_gtk[key_index] = NULL;
+               }
+               if (priv->wilc_ptk[key_index]) {
+                       kfree(priv->wilc_ptk[key_index]->key);
+                       priv->wilc_ptk[key_index]->key = NULL;
+                       kfree(priv->wilc_ptk[key_index]->seq);
+                       priv->wilc_ptk[key_index]->seq = NULL;
+                       kfree(priv->wilc_ptk[key_index]);
+                       priv->wilc_ptk[key_index] = NULL;
+               }
        }
 
        return 0;
@@ -642,11 +694,20 @@ static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
        struct  key_params key_params;
 
        if (!pairwise) {
-               key_params.key = priv->wilc_gtk[key_index]->key;
-               key_params.cipher = priv->wilc_gtk[key_index]->cipher;
-               key_params.key_len = priv->wilc_gtk[key_index]->key_len;
-               key_params.seq = priv->wilc_gtk[key_index]->seq;
-               key_params.seq_len = priv->wilc_gtk[key_index]->seq_len;
+               if (key_index == 4 || key_index == 5) {
+                       key_index -= 4;
+                       key_params.key = priv->wilc_igtk[key_index]->key;
+                       key_params.cipher = priv->wilc_igtk[key_index]->cipher;
+                       key_params.key_len = priv->wilc_igtk[key_index]->key_len;
+                       key_params.seq = priv->wilc_igtk[key_index]->seq;
+                       key_params.seq_len = priv->wilc_igtk[key_index]->seq_len;
+               } else {
+                       key_params.key = priv->wilc_gtk[key_index]->key;
+                       key_params.cipher = priv->wilc_gtk[key_index]->cipher;
+                       key_params.key_len = priv->wilc_gtk[key_index]->key_len;
+                       key_params.seq = priv->wilc_gtk[key_index]->seq;
+                       key_params.seq_len = priv->wilc_gtk[key_index]->seq_len;
+               }
        } else {
                key_params.key = priv->wilc_ptk[key_index]->key;
                key_params.cipher = priv->wilc_ptk[key_index]->cipher;
@@ -667,6 +728,14 @@ static int set_default_key(struct wiphy *wiphy, struct net_device *netdev,
        return 0;
 }
 
+static int set_default_mgmt_key(struct wiphy *wiphy, struct net_device *netdev,
+                               u8 key_index)
+{
+       struct wilc_vif *vif = netdev_priv(netdev);
+
+       return wilc_set_default_mgmt_key_index(vif, key_index);
+}
+
 static int get_station(struct wiphy *wiphy, struct net_device *dev,
                       const u8 *mac, struct station_info *sinfo)
 {
@@ -1626,6 +1695,7 @@ static const struct cfg80211_ops wilc_cfg80211_ops = {
        .del_key = del_key,
        .get_key = get_key,
        .set_default_key = set_default_key,
+       .set_default_mgmt_key = set_default_mgmt_key,
        .add_virtual_intf = add_virtual_intf,
        .del_virtual_intf = del_virtual_intf,
        .change_virtual_intf = change_virtual_intf,
index 9449c5d..5c5cac4 100644 (file)
@@ -54,6 +54,14 @@ struct wilc_ap_wpa_ptk {
        u8 key[];
 } __packed;
 
+struct wilc_wpa_igtk {
+       u8 index;
+       u8 pn_len;
+       u8 pn[6];
+       u8 key_len;
+       u8 key[];
+} __packed;
+
 struct wilc_gtk_key {
        u8 mac_addr[ETH_ALEN];
        u8 rsc[8];
index 5d9d3ab..4038a25 100644 (file)
@@ -271,12 +271,19 @@ error:
 static int wilc_send_connect_wid(struct wilc_vif *vif)
 {
        int result = 0;
-       struct wid wid_list[4];
+       struct wid wid_list[5];
        u32 wid_cnt = 0;
        struct host_if_drv *hif_drv = vif->hif_drv;
        struct wilc_conn_info *conn_attr = &hif_drv->conn_info;
        struct wilc_join_bss_param *bss_param = conn_attr->param;
 
+
+        wid_list[wid_cnt].id = WID_SET_MFP;
+        wid_list[wid_cnt].type = WID_CHAR;
+        wid_list[wid_cnt].size = sizeof(char);
+        wid_list[wid_cnt].val = (s8 *)&conn_attr->mfp_type;
+        wid_cnt++;
+
        wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;
        wid_list[wid_cnt].type = WID_BIN_DATA;
        wid_list[wid_cnt].val = conn_attr->req_ies;
@@ -1143,6 +1150,36 @@ int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
        return result;
 }
 
+int wilc_add_igtk(struct wilc_vif *vif, const u8 *igtk, u8 igtk_key_len,
+                 const u8 *pn, u8 pn_len, const u8 *mac_addr, u8 mode, u8 index)
+{
+       int result = 0;
+       u8 t_key_len = igtk_key_len;
+       struct wid wid;
+       struct wilc_wpa_igtk *key_buf;
+
+       key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
+       if (!key_buf)
+               return -ENOMEM;
+
+       key_buf->index = index;
+
+       memcpy(&key_buf->pn[0], pn, pn_len);
+       key_buf->pn_len = pn_len;
+
+       memcpy(&key_buf->key[0], igtk, igtk_key_len);
+       key_buf->key_len = t_key_len;
+
+       wid.id = WID_ADD_IGTK;
+       wid.type = WID_STR;
+       wid.size = sizeof(*key_buf) + t_key_len;
+       wid.val = (s8 *)key_buf;
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       kfree(key_buf);
+
+       return result;
+}
+
 int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
                    u8 index, u32 key_rsc_len, const u8 *key_rsc,
                    const u8 *rx_mic, const u8 *tx_mic, u8 mode,
@@ -1932,3 +1969,20 @@ int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)
 
        return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
 }
+
+int wilc_set_default_mgmt_key_index(struct wilc_vif *vif, u8 index)
+{
+        struct wid wid;
+        int result;
+
+        wid.id = WID_DEFAULT_MGMT_KEY_ID;
+        wid.type = WID_CHAR;
+        wid.size = sizeof(char);
+        wid.val = &index;
+        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+        if (result)
+                netdev_err(vif->ndev,
+                           "Failed to send default mgmt key index\n");
+
+        return result;
+}
index f1a0a1f..d8dd94d 100644 (file)
@@ -108,6 +108,7 @@ struct wilc_conn_info {
        u8 bssid[ETH_ALEN];
        u8 security;
        enum authtype auth_type;
+       enum mfptype mfp_type;
        u8 ch;
        u8 *req_ies;
        size_t req_ies_len;
@@ -155,6 +156,9 @@ struct wilc_vif;
 int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
                 const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
                 u8 mode, u8 cipher_mode, u8 index);
+int wilc_add_igtk(struct wilc_vif *vif, const u8 *igtk, u8 igtk_key_len,
+                 const u8 *pn, u8 pn_len, const u8 *mac_addr, u8 mode,
+                 u8 index);
 s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
                           u32 *out_val);
 int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
@@ -210,4 +214,5 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length);
 void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length);
 void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
                                struct cfg80211_crypto_settings *crypto);
+int wilc_set_default_mgmt_key_index(struct wilc_vif *vif, u8 index);
 #endif
index a0d9e98..822e65d 100644 (file)
@@ -129,6 +129,7 @@ struct wilc_priv {
        struct net_device *real_ndev;
        struct wilc_wfi_key *wilc_gtk[WILC_MAX_NUM_STA];
        struct wilc_wfi_key *wilc_ptk[WILC_MAX_NUM_STA];
+       struct wilc_wfi_key *wilc_igtk[2];
        u8 wilc_groupkey;
 
        /* mutexes */
index 18f13b5..df2f5a6 100644 (file)
@@ -91,6 +91,12 @@ enum authtype {
        WILC_FW_AUTH_OPEN_SYSTEM_SHA256 = 13
 };
 
+enum mfptype {
+       WILC_FW_MFP_NONE = 0x0,
+       WILC_FW_MFP_OPTIONAL = 0x1,
+       WILC_FW_MFP_REQUIRED = 0x2
+};
+
 enum site_survey {
        WILC_FW_SITE_SURVEY_1CH = 0,
        WILC_FW_SITE_SURVEY_ALL_CH = 1,
@@ -661,6 +667,9 @@ enum {
        WID_LOG_TERMINAL_SWITCH         = 0x00CD,
        WID_TX_POWER                    = 0x00CE,
        WID_WOWLAN_TRIGGER              = 0X00CF,
+       WID_SET_MFP                     = 0x00D0,
+
+       WID_DEFAULT_MGMT_KEY_ID         = 0x00D2,
        /*  EMAC Short WID list */
        /*  RTS Threshold */
        /*
@@ -750,6 +759,7 @@ enum {
        WID_REMOVE_KEY                  = 0x301E,
        WID_ASSOC_REQ_INFO              = 0x301F,
        WID_ASSOC_RES_INFO              = 0x3020,
+       WID_ADD_IGTK                    = 0x3022,
        WID_MANUFACTURER                = 0x3026, /* Added for CAPI tool */
        WID_MODEL_NAME                  = 0x3027, /* Added for CAPI tool */
        WID_MODEL_NUM                   = 0x3028, /* Added for CAPI tool */