KEY_TYPE_ID_WAPI,
        KEY_TYPE_ID_AES_CMAC,
 };
+
+#define WPA_PN_SIZE            8
+#define KEY_PARAMS_FIXED_LEN   10
+#define KEY_INDEX_MASK         0xf
+#define FW_KEY_API_VER_MAJOR_V2        2
+
 #define KEY_MCAST      BIT(0)
 #define KEY_UNICAST    BIT(1)
 #define KEY_ENABLED    BIT(2)
+#define KEY_DEFAULT    BIT(3)
+#define KEY_TX_KEY     BIT(4)
+#define KEY_RX_KEY     BIT(5)
 #define KEY_IGTK       BIT(10)
 
-#define WAPI_KEY_LEN                   50
+#define WAPI_KEY_LEN                   (WLAN_KEY_LEN_SMS4 + PN_LEN + 2)
 
 #define MAX_POLL_TRIES                 100
 #define MAX_FIRMWARE_POLL_TRIES                        100
 #define TLV_TYPE_PWK_CIPHER         (PROPRIETARY_TLV_BASE_ID + 145)
 #define TLV_TYPE_GWK_CIPHER         (PROPRIETARY_TLV_BASE_ID + 146)
 #define TLV_TYPE_COALESCE_RULE      (PROPRIETARY_TLV_BASE_ID + 154)
+#define TLV_TYPE_KEY_PARAM_V2       (PROPRIETARY_TLV_BASE_ID + 156)
 #define TLV_TYPE_FW_API_REV         (PROPRIETARY_TLV_BASE_ID + 199)
 
 #define MWIFIEX_TX_DATA_BUF_SIZE_2K        2048
        u8 key[WLAN_KEY_LEN_AES_CMAC];
 } __packed;
 
+struct mwifiex_wep_param {
+       __le16 key_len;
+       u8 key[WLAN_KEY_LEN_WEP104];
+} __packed;
+
+struct mwifiex_tkip_param {
+       u8 pn[WPA_PN_SIZE];
+       __le16 key_len;
+       u8 key[WLAN_KEY_LEN_TKIP];
+} __packed;
+
+struct mwifiex_aes_param {
+       u8 pn[WPA_PN_SIZE];
+       __le16 key_len;
+       u8 key[WLAN_KEY_LEN_CCMP];
+} __packed;
+
+struct mwifiex_wapi_param {
+       u8 pn[PN_LEN];
+       __le16 key_len;
+       u8 key[WLAN_KEY_LEN_SMS4];
+} __packed;
+
+struct mwifiex_cmac_aes_param {
+       u8 ipn[IGTK_PN_LEN];
+       __le16 key_len;
+       u8 key[WLAN_KEY_LEN_AES_CMAC];
+} __packed;
+
+struct mwifiex_ie_type_key_param_set_v2 {
+       __le16 type;
+       __le16 len;
+       u8 mac_addr[ETH_ALEN];
+       u8 key_idx;
+       u8 key_type;
+       __le16 key_info;
+       union {
+               struct mwifiex_wep_param wep;
+               struct mwifiex_tkip_param tkip;
+               struct mwifiex_aes_param aes;
+               struct mwifiex_wapi_param wapi;
+               struct mwifiex_cmac_aes_param cmac_aes;
+       } key_params;
+} __packed;
+
+struct host_cmd_ds_802_11_key_material_v2 {
+       __le16 action;
+       struct mwifiex_ie_type_key_param_set_v2 key_param_set;
+} __packed;
+
 struct host_cmd_ds_802_11_key_material {
        __le16 action;
        struct mwifiex_ie_type_key_param_set key_param_set;
                struct host_cmd_ds_11n_cfg htcfg;
                struct host_cmd_ds_wmm_get_status get_wmm_status;
                struct host_cmd_ds_802_11_key_material key_material;
+               struct host_cmd_ds_802_11_key_material_v2 key_material_v2;
                struct host_cmd_ds_version_ext verext;
                struct host_cmd_ds_mgmt_frame_reg reg_mask;
                struct host_cmd_ds_remain_on_chan roc_cfg;
 
        return 0;
 }
 
+/* This function populates key material v2 command
+ * to set network key for AES & CMAC AES.
+ */
+static int mwifiex_set_aes_key_v2(struct mwifiex_private *priv,
+                                 struct host_cmd_ds_command *cmd,
+                                 struct mwifiex_ds_encrypt_key *enc_key,
+                                 struct host_cmd_ds_802_11_key_material_v2 *km)
+{
+       struct mwifiex_adapter *adapter = priv->adapter;
+       u16 size, len = KEY_PARAMS_FIXED_LEN;
+
+       if (enc_key->is_igtk_key) {
+               dev_dbg(adapter->dev, "%s: Set CMAC AES Key\n", __func__);
+               if (enc_key->is_rx_seq_valid)
+                       memcpy(km->key_param_set.key_params.cmac_aes.ipn,
+                              enc_key->pn, enc_key->pn_len);
+               km->key_param_set.key_info &= cpu_to_le16(~KEY_MCAST);
+               km->key_param_set.key_info |= cpu_to_le16(KEY_IGTK);
+               km->key_param_set.key_type = KEY_TYPE_ID_AES_CMAC;
+               km->key_param_set.key_params.cmac_aes.key_len =
+                                         cpu_to_le16(enc_key->key_len);
+               memcpy(km->key_param_set.key_params.cmac_aes.key,
+                      enc_key->key_material, enc_key->key_len);
+               len += sizeof(struct mwifiex_cmac_aes_param);
+       } else {
+               dev_dbg(adapter->dev, "%s: Set AES Key\n", __func__);
+               if (enc_key->is_rx_seq_valid)
+                       memcpy(km->key_param_set.key_params.aes.pn,
+                              enc_key->pn, enc_key->pn_len);
+               km->key_param_set.key_type = KEY_TYPE_ID_AES;
+               km->key_param_set.key_params.aes.key_len =
+                                         cpu_to_le16(enc_key->key_len);
+               memcpy(km->key_param_set.key_params.aes.key,
+                      enc_key->key_material, enc_key->key_len);
+               len += sizeof(struct mwifiex_aes_param);
+       }
+
+       km->key_param_set.len = cpu_to_le16(len);
+       size = len + sizeof(struct mwifiex_ie_types_header) +
+              sizeof(km->action) + S_DS_GEN;
+       cmd->size = cpu_to_le16(size);
+
+       return 0;
+}
+
+/* This function prepares command to set/get/reset network key(s).
+ * This function prepares key material command for V2 format.
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting WEP keys, WAPI keys or WPA keys along with required
+ *        encryption (TKIP, AES) (as required)
+ *      - Ensuring correct endian-ness
+ */
+static int
+mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
+                                  struct host_cmd_ds_command *cmd,
+                                  u16 cmd_action, u32 cmd_oid,
+                                  struct mwifiex_ds_encrypt_key *enc_key)
+{
+       struct mwifiex_adapter *adapter = priv->adapter;
+       u8 *mac = enc_key->mac_addr;
+       u16 key_info, len = KEY_PARAMS_FIXED_LEN;
+       struct host_cmd_ds_802_11_key_material_v2 *km =
+                                               &cmd->params.key_material_v2;
+
+       cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+       km->action = cpu_to_le16(cmd_action);
+
+       if (cmd_action == HostCmd_ACT_GEN_GET) {
+               dev_dbg(adapter->dev, "%s: Get key\n", __func__);
+               km->key_param_set.key_idx =
+                                       enc_key->key_index & KEY_INDEX_MASK;
+               km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
+               km->key_param_set.len = cpu_to_le16(KEY_PARAMS_FIXED_LEN);
+               memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN);
+
+               if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
+                       key_info = KEY_UNICAST;
+               else
+                       key_info = KEY_MCAST;
+
+               if (enc_key->is_igtk_key)
+                       key_info |= KEY_IGTK;
+
+               km->key_param_set.key_info = cpu_to_le16(key_info);
+
+               cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
+                                       S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+                                       sizeof(km->action));
+               return 0;
+       }
+
+       memset(&km->key_param_set, 0,
+              sizeof(struct mwifiex_ie_type_key_param_set_v2));
+
+       if (enc_key->key_disable) {
+               dev_dbg(adapter->dev, "%s: Remove key\n", __func__);
+               km->action = cpu_to_le16(HostCmd_ACT_GEN_REMOVE);
+               km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
+               km->key_param_set.len = cpu_to_le16(KEY_PARAMS_FIXED_LEN);
+               km->key_param_set.key_idx = enc_key->key_index & KEY_INDEX_MASK;
+               key_info = KEY_MCAST | KEY_UNICAST;
+               km->key_param_set.key_info = cpu_to_le16(key_info);
+               memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN);
+               cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
+                                       S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+                                       sizeof(km->action));
+               return 0;
+       }
+
+       km->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
+       km->key_param_set.key_idx = enc_key->key_index & KEY_INDEX_MASK;
+       km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
+       key_info = KEY_ENABLED;
+       memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN);
+
+       if (enc_key->key_len <= WLAN_KEY_LEN_WEP104) {
+               dev_dbg(adapter->dev, "%s: Set WEP Key\n", __func__);
+               len += sizeof(struct mwifiex_wep_param);
+               km->key_param_set.len = cpu_to_le16(len);
+               km->key_param_set.key_type = KEY_TYPE_ID_WEP;
+
+               if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+                               key_info |= KEY_MCAST | KEY_UNICAST;
+               } else {
+                       if (enc_key->is_current_wep_key) {
+                               key_info |= KEY_MCAST | KEY_UNICAST;
+                               if (km->key_param_set.key_idx ==
+                                   (priv->wep_key_curr_index & KEY_INDEX_MASK))
+                                       key_info |= KEY_DEFAULT;
+                       } else {
+                               if (mac) {
+                                       if (is_broadcast_ether_addr(mac))
+                                               key_info |= KEY_MCAST;
+                                       else
+                                               key_info |= KEY_UNICAST |
+                                                           KEY_DEFAULT;
+                               } else {
+                                       key_info |= KEY_MCAST;
+                               }
+                       }
+               }
+               km->key_param_set.key_info = cpu_to_le16(key_info);
+
+               km->key_param_set.key_params.wep.key_len =
+                                                 cpu_to_le16(enc_key->key_len);
+               memcpy(km->key_param_set.key_params.wep.key,
+                      enc_key->key_material, enc_key->key_len);
+
+               cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
+                                       len + sizeof(km->action) + S_DS_GEN);
+               return 0;
+       }
+
+       if (is_broadcast_ether_addr(mac))
+               key_info |= KEY_MCAST | KEY_RX_KEY;
+       else
+               key_info |= KEY_UNICAST | KEY_TX_KEY | KEY_RX_KEY;
+
+       if (enc_key->is_wapi_key) {
+               dev_dbg(adapter->dev, "%s: Set WAPI Key\n", __func__);
+               km->key_param_set.key_type = KEY_TYPE_ID_WAPI;
+               memcpy(km->key_param_set.key_params.wapi.pn, enc_key->pn,
+                      PN_LEN);
+               km->key_param_set.key_params.wapi.key_len =
+                                               cpu_to_le16(enc_key->key_len);
+               memcpy(km->key_param_set.key_params.wapi.key,
+                      enc_key->key_material, enc_key->key_len);
+               if (is_broadcast_ether_addr(mac))
+                       priv->sec_info.wapi_key_on = true;
+
+               if (!priv->sec_info.wapi_key_on)
+                       key_info |= KEY_DEFAULT;
+               km->key_param_set.key_info = cpu_to_le16(key_info);
+
+               len += sizeof(struct mwifiex_wapi_param);
+               km->key_param_set.len = cpu_to_le16(len);
+               cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
+                                       len + sizeof(km->action) + S_DS_GEN);
+               return 0;
+       }
+
+       if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+               key_info |= KEY_DEFAULT;
+               /* Enable unicast bit for WPA-NONE/ADHOC_AES */
+               if (!priv->sec_info.wpa2_enabled &&
+                   !is_broadcast_ether_addr(mac))
+                       key_info |= KEY_UNICAST;
+       } else {
+               /* Enable default key for WPA/WPA2 */
+               if (!priv->wpa_is_gtk_set)
+                       key_info |= KEY_DEFAULT;
+       }
+
+       km->key_param_set.key_info = cpu_to_le16(key_info);
+
+       if (enc_key->key_len == WLAN_KEY_LEN_CCMP)
+               return mwifiex_set_aes_key_v2(priv, cmd, enc_key, km);
+
+       if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
+               dev_dbg(adapter->dev, "%s: Set TKIP Key\n", __func__);
+               if (enc_key->is_rx_seq_valid)
+                       memcpy(km->key_param_set.key_params.tkip.pn,
+                              enc_key->pn, enc_key->pn_len);
+               km->key_param_set.key_type = KEY_TYPE_ID_TKIP;
+               km->key_param_set.key_params.tkip.key_len =
+                                               cpu_to_le16(enc_key->key_len);
+               memcpy(km->key_param_set.key_params.tkip.key,
+                      enc_key->key_material, enc_key->key_len);
+
+               len += sizeof(struct mwifiex_tkip_param);
+               km->key_param_set.len = cpu_to_le16(len);
+               cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
+                                       len + sizeof(km->action) + S_DS_GEN);
+       }
+
+       return 0;
+}
+
 /*
  * This function prepares command to set/get/reset network key(s).
+ * This function prepares key material command for V1 format.
  *
  * Preparation includes -
  *      - Setting command ID, action and proper size
  *      - Ensuring correct endian-ness
  */
 static int
-mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
-                               struct host_cmd_ds_command *cmd,
-                               u16 cmd_action, u32 cmd_oid,
-                               struct mwifiex_ds_encrypt_key *enc_key)
+mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv,
+                                  struct host_cmd_ds_command *cmd,
+                                  u16 cmd_action, u32 cmd_oid,
+                                  struct mwifiex_ds_encrypt_key *enc_key)
 {
        struct host_cmd_ds_802_11_key_material *key_material =
                &cmd->params.key_material;
        return ret;
 }
 
+/* Wrapper function for setting network key depending upon FW KEY API version */
+static int
+mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
+                               struct host_cmd_ds_command *cmd,
+                               u16 cmd_action, u32 cmd_oid,
+                               struct mwifiex_ds_encrypt_key *enc_key)
+{
+       if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+               return mwifiex_cmd_802_11_key_material_v2(priv, cmd,
+                                                         cmd_action, cmd_oid,
+                                                         enc_key);
+
+       else
+               return mwifiex_cmd_802_11_key_material_v1(priv, cmd,
+                                                         cmd_action, cmd_oid,
+                                                         enc_key);
+}
+
 /*
  * This function prepares command to set/get 11d domain information.
  *
 
 static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
                              struct mwifiex_ds_encrypt_key *encrypt_key)
 {
+       struct mwifiex_adapter *adapter = priv->adapter;
        int ret;
        struct mwifiex_wep_key *wep_key;
        int index;
                /* Copy the required key as the current key */
                wep_key = &priv->wep_key[index];
                if (!wep_key->key_length) {
-                       dev_err(priv->adapter->dev,
+                       dev_err(adapter->dev,
                                "key not set, so cannot enable it\n");
                        return -1;
                }
+
+               if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2) {
+                       memcpy(encrypt_key->key_material,
+                              wep_key->key_material, wep_key->key_length);
+                       encrypt_key->key_len = wep_key->key_length;
+               }
+
                priv->wep_key_curr_index = (u16) index;
                priv->sec_info.wep_enabled = 1;
        } else {
                priv->sec_info.wep_enabled = 1;
        }
        if (wep_key->key_length) {
+               void *enc_key;
+
+               if (encrypt_key->key_disable)
+                       memset(&priv->wep_key[index], 0,
+                              sizeof(struct mwifiex_wep_key));
+
+               if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+                       enc_key = encrypt_key;
+               else
+                       enc_key = NULL;
+
                /* Send request to firmware */
                ret = mwifiex_send_cmd_async(priv,
                                             HostCmd_CMD_802_11_KEY_MATERIAL,
-                                            HostCmd_ACT_GEN_SET, 0, NULL);
+                                            HostCmd_ACT_GEN_SET, 0, enc_key);
                if (ret)
                        return ret;
        }
+
        if (priv->sec_info.wep_enabled)
                priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
        else
 
        memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key));
        encrypt_key.key_len = key_len;
+       encrypt_key.key_index = key_index;
 
        if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
                encrypt_key.is_igtk_key = true;
 
        if (!disable) {
-               encrypt_key.key_index = key_index;
                if (key_len)
                        memcpy(encrypt_key.key_material, key, key_len);
+               else
+                       encrypt_key.is_current_wep_key = true;
+
                if (mac_addr)
                        memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
-               if (kp && kp->seq && kp->seq_len)
+               if (kp && kp->seq && kp->seq_len) {
                        memcpy(encrypt_key.pn, kp->seq, kp->seq_len);
+                       encrypt_key.pn_len = kp->seq_len;
+                       encrypt_key.is_rx_seq_valid = true;
+               }
        } else {
+               if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
+                       return 0;
                encrypt_key.key_disable = true;
                if (mac_addr)
                        memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);