qcacld-3.0: Add support to parse ROAM_SYNCH_KEY event

ROAM_SYNCH_KEY event will be sent after roaming to a ML AP
with STA advertising standby-links.

WMI_ROAM_SYNCH_KEY_EVENTID TLV format:
-- wmi_roam_ml_key_material_param: PTK (link_id = 0xf)
-- wmi_roam_ml_key_material_param: GTK (link_id = 0)
-- wmi_roam_ml_key_material_param: IGTK (link_id = 0)
-- wmi_roam_ml_key_material_param: BIGTK (link_id = 0)
-- wmi_roam_ml_key_material_param: LTF KEYSEED (link_id = 0xf)
-- wmi_roam_ml_key_material_param: GTK (link_id = 1)
-- wmi_roam_ml_key_material_param: IGTK (link_id = 1)
-- wmi_roam_ml_key_material_param: BIGTK (link_id = 1)
-- wmi_roam_ml_key_material_param: GTK (link_id = 2)
-- wmi_roam_ml_key_material_param: IGTK (link_id = 2)
-- wmi_roam_ml_key_material_param: BIGTK (link_id = 2)

If length of any key exceeds WMI_MAX_KEY_LEN, then multiple
TLVs will be included for that key.

Change-Id: I64238acfbd29bc40df5971f098ad5802360d8777
CRs-Fixed: 3577923
This commit is contained in:
Pragaspathi Thilagaraj
2023-08-02 05:39:37 +05:30
committed by Rahul Choudhary
parent 89c1955cd1
commit 0f7d749e5f
5 changed files with 456 additions and 3 deletions

View File

@@ -24,6 +24,7 @@
#include <wmi_unified_roam_param.h> #include <wmi_unified_roam_param.h>
#include "wlan_cm_roam_public_struct.h" #include "wlan_cm_roam_public_struct.h"
#include "wlan_crypto_def_i.h"
#ifdef FEATURE_LFR_SUBNET_DETECTION #ifdef FEATURE_LFR_SUBNET_DETECTION
/** /**
@@ -119,6 +120,36 @@ wmi_extract_roam_vendor_control_param_event(wmi_unified_t wmi_handle,
#endif #endif
#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO)
/**
* wmi_extract_roam_synch_key_event() - extract roam synch key event
* @wmi_handle: wmi handle
* @event: roam synch key event buffer pointer
* @len: event len
* @keys: destination buffer to copy keys
* @num_keys: Number of keys
* @mld_addr: MLD address pointer
*
* Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure
*/
QDF_STATUS
wmi_extract_roam_synch_key_event(wmi_unified_t wmi_handle, uint8_t *event,
uint32_t len,
struct wlan_crypto_key_entry **keys,
uint8_t *num_keys,
struct qdf_mac_addr *mld_addr);
#else
static inline QDF_STATUS
wmi_extract_roam_synch_key_event(wmi_unified_t wmi_handle, uint8_t *event,
uint32_t len,
struct wlan_crypto_key_entry **keys,
uint8_t *num_keys,
struct qdf_mac_addr *mld_addr)
{
return QDF_STATUS_E_NOSUPPORT;
}
#endif
/** /**
* wmi_unified_roam_scan_filter_cmd() - send roam scan allowlist, * wmi_unified_roam_scan_filter_cmd() - send roam scan allowlist,
* denylist and preferred list * denylist and preferred list

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -157,6 +157,24 @@ wmi_extract_roam_vendor_control_param_event(wmi_unified_t wmi_handle,
} }
#endif #endif
#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO)
QDF_STATUS
wmi_extract_roam_synch_key_event(wmi_unified_t wmi_handle, uint8_t *event,
uint32_t len,
struct wlan_crypto_key_entry **keys,
uint8_t *num_keys,
struct qdf_mac_addr *mld_addr)
{
if (wmi_handle->ops->extract_roam_synch_key_event)
return wmi_handle->ops->extract_roam_synch_key_event(
wmi_handle, event,
len, keys, num_keys,
mld_addr);
return QDF_STATUS_E_FAILURE;
}
#endif
QDF_STATUS wmi_unified_roam_invoke_cmd(wmi_unified_t wmi_handle, QDF_STATUS wmi_unified_roam_invoke_cmd(wmi_unified_t wmi_handle,
struct roam_invoke_req *roaminvoke) struct roam_invoke_req *roaminvoke)
{ {

View File

@@ -27,6 +27,7 @@
#include "ol_defines.h" #include "ol_defines.h"
#include "wlan_cm_roam_api.h" #include "wlan_cm_roam_api.h"
#include "wlan_mlme_api.h" #include "wlan_mlme_api.h"
#include "wlan_crypto_global_api.h"
#define WMI_MAC_TO_PDEV_MAP(x) ((x) + (1)) #define WMI_MAC_TO_PDEV_MAP(x) ((x) + (1))
#define WMI_PDEV_TO_MAC_MAP(x) ((x) - (1)) #define WMI_PDEV_TO_MAC_MAP(x) ((x) - (1))
@@ -3677,6 +3678,409 @@ wmi_roam_offload_attach_vendor_handoff_tlv(struct wmi_ops *ops)
} }
#endif #endif
#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO)
static inline
enum wlan_crypto_cipher_type wlan_wmi_cipher_to_crypto(uint8_t cipher)
{
switch (cipher) {
case WMI_CIPHER_NONE:
return WLAN_CRYPTO_CIPHER_NONE;
case WMI_CIPHER_WEP:
return WLAN_CRYPTO_CIPHER_WEP;
case WMI_CIPHER_WAPI:
return WLAN_CRYPTO_CIPHER_WAPI_SMS4;
case WMI_CIPHER_AES_CCM:
return WLAN_CRYPTO_CIPHER_AES_CCM;
case WMI_CIPHER_AES_CMAC:
return WLAN_CRYPTO_CIPHER_AES_CMAC;
case WMI_CIPHER_AES_GMAC:
return WLAN_CRYPTO_CIPHER_AES_GMAC;
case WMI_CIPHER_AES_GCM:
return WLAN_CRYPTO_CIPHER_AES_GCM;
default:
return 0;
}
}
#define MLO_PAIRWISE_LINKID 0xF
/**
* wmi_fill_keys_from_tlv - Fill the destination key buffer from the WMI TLV
* @ml_keys: ML Keys TLV pointer
* @dst_key: Destination keys
* @dst_key_len: Destination keys length
* @count: TLV count
* @max_num_tlv: Total number of TLVs
*
* Return: None
*/
static void
wmi_fill_keys_from_tlv(wmi_roam_ml_key_material_param **ml_keys,
uint8_t *dst_key, uint8_t *dst_key_len, uint8_t *count,
uint8_t max_num_tlv)
{
uint8_t rem_key_len, bytes_filled, key_len, total_key_len;
uint8_t max_key_len = WLAN_CRYPTO_KEYBUF_SIZE + WLAN_CRYPTO_MICBUF_SIZE;
*dst_key_len = (*ml_keys)->key_len;
if (*dst_key_len > max_key_len)
*dst_key_len = max_key_len;
total_key_len = *dst_key_len;
rem_key_len = *dst_key_len;
while (rem_key_len) {
if (!(*ml_keys)) {
wmi_err_rl("ml_keys is NULL. rem_key_len:%d",
rem_key_len);
return;
}
if (*count >= max_num_tlv) {
wmi_debug("Read all TLVs count:%d", *count);
return;
}
if (rem_key_len < WMI_MAX_KEY_LEN)
key_len = rem_key_len;
else
key_len = WMI_MAX_KEY_LEN;
bytes_filled = total_key_len - rem_key_len;
qdf_mem_copy(dst_key + bytes_filled, (*ml_keys)->key_buff,
key_len);
(*ml_keys)++;
(*count)++;
rem_key_len -= key_len;
}
}
#define WMI_NUM_KEYS_ALLOCATED (WLAN_MAX_ML_BSS_LINKS * 4)
static QDF_STATUS
extract_roam_synch_key_event_tlv(wmi_unified_t wmi_handle,
uint8_t *event, uint32_t data_len,
struct wlan_crypto_key_entry **entries,
uint8_t *num_entries,
struct qdf_mac_addr *mld_addr)
{
WMI_ROAM_SYNCH_KEY_EVENTID_param_tlvs *param_buf = NULL;
wmi_roam_ml_key_material_param *ml_keys = NULL;
struct wlan_crypto_key_entry *key_entry;
struct wlan_crypto_keys *all_keys;
struct wlan_crypto_key *dst_key, *pairwise;
struct wlan_crypto_key *key_alloc_buf[WMI_NUM_KEYS_ALLOCATED];
bool flush_keybuf;
uint8_t total_num_tlv, j = 0, k = 0;
uint8_t count = 0, total_links = 0, dst_key_count = 0;
uint8_t igtk_idx = 0, bigtk_idx = 0;
bool slot_found;
QDF_STATUS status = QDF_STATUS_SUCCESS;
param_buf = (WMI_ROAM_SYNCH_KEY_EVENTID_param_tlvs *)event;
if (!param_buf) {
wmi_err_rl("received null buf from target");
return QDF_STATUS_E_INVAL;
}
total_num_tlv = param_buf->num_ml_key_material;
ml_keys = (wmi_roam_ml_key_material_param *)param_buf->ml_key_material;
if (!ml_keys) {
wmi_err_rl("received ml keys param is null");
return QDF_STATUS_E_INVAL;
}
*entries = qdf_mem_malloc(WLAN_MAX_ML_BSS_LINKS * sizeof(*key_entry));
if (!*entries)
return QDF_STATUS_E_NOMEM;
/*
* Allocate memory for each PTK, GTK, IGTK, BIGTK keys.
* So total WLAN_MAX_ML_BSS_LINKS * 4 keys are needed
*/
for (k = 0; k < WMI_NUM_KEYS_ALLOCATED; k++) {
key_alloc_buf[k] = qdf_mem_malloc(sizeof(*dst_key));
if (!key_alloc_buf[k]) {
flush_keybuf = true;
status = QDF_STATUS_E_NOMEM;
goto free_entries;
}
}
/*
* key_entry is the master structure that is given directly to the
* crypto module and stored for each link.
* key_entry -> keys ->key filled from dst_key has the PTK & GTK indexed
* with corresponding key index
*
* key_entry -> keys -> iGTK holds the iGTK key
* key_entry -> keys -> BIGTK holds the BIGTK key
*/
key_entry = *entries;
/*
* Initialize all the Key Entry structures with invalid Link
* ID to identify empty links allocated and will be freed
* at the end.
*/
for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++)
key_entry[j].link_id = MLO_INVALID_LINK_IDX;
/*
* TLV Format to parse:
* 1. wmi_roam_ml_key_material_param -> For PTK with Link ID = 0xF
* Copy this PTK to all the key entry of all the links.
*
* 2. wmi_roam_ml_key_material_param -> GTK for a valid Link.
* Get available entry, and fill the GTK to that entry
*
* 3. wmi_roam_ml_key_material_param -> IGTK for a valid link
*
* 4. wmi_roam_ml_key_material_param -> BIGTK for a valid link
*
* 5. wmi_roam_ml_key_material_param -> For LTF Keyseed with Link ID =
* 0xF and flags has LTF_USAGE set.
*
* If any of the key length is > WMI_MAX_KEY_LEN, then multiple
* wmi_roam_ml_key_material_param TLVs follow to get the entire key
*/
while (ml_keys && count < total_num_tlv &&
dst_key_count < WMI_NUM_KEYS_ALLOCATED) {
/*
* Track individual keys with key_alloc_buf[dst_key_count] array
* pointer to avoid mem leaks if parsing/validating any of the
* keys fail.
* Freeing the allocated keys it done at the end of this
* function
*/
dst_key = key_alloc_buf[dst_key_count];
wmi_debug("link_id:%d key_ix:%d key_cipher:%d key_len:%d key_flags:%d",
ml_keys->link_id, ml_keys->key_ix,
ml_keys->key_cipher,
ml_keys->key_len, ml_keys->key_flags);
if (!is_valid_keyix(ml_keys->key_ix)) {
wmi_err_rl("invalid key index:%d", ml_keys->key_ix);
status = QDF_STATUS_E_INVAL;
flush_keybuf = true;
goto free_entries;
}
/* Copy pairwise keys to all the entries */
if (ml_keys->link_id == MLO_PAIRWISE_LINKID) {
WMI_MAC_ADDR_TO_CHAR_ARRAY(&ml_keys->mac_addr,
mld_addr->bytes);
if (!ml_keys->key_len) {
wmi_err_rl("Received key_len as 0 for tlv:%d",
count);
status = QDF_STATUS_E_INVAL;
flush_keybuf = true;
goto free_entries;
}
if (ml_keys->key_flags & LTF_USAGE) {
struct wlan_crypto_ltf_keyseed_data key_seed;
uint8_t key_seed_len;
if (ml_keys->key_len >
WLAN_MAX_SECURE_LTF_KEYSEED_LEN)
ml_keys->key_len =
WLAN_MAX_SECURE_LTF_KEYSEED_LEN;
/*
* Filling the keys from multiple TLVs is
* handled by below API and ml_keys ptr gets
* incremented accordingly inside
*/
wmi_fill_keys_from_tlv(&ml_keys,
key_seed.key_seed,
&key_seed_len, &count,
total_num_tlv);
key_seed.key_seed_len = key_seed_len;
wmi_debug("ML_KEY: Got LTF keyseed key for MLD: "
QDF_MAC_ADDR_FMT " key_seed_len:%d",
QDF_MAC_ADDR_REF(mld_addr->bytes),
key_seed.key_seed_len);
for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++)
key_entry[j].keys.ltf_key_seed =
key_seed;
continue;
}
dst_key->valid = true;
dst_key->keylen = ml_keys->key_len;
dst_key->flags = ml_keys->key_flags;
dst_key->keyix = ml_keys->key_ix;
dst_key->key_type =
WLAN_CRYPTO_KEY_TYPE_UNICAST;
dst_key->cipher_type =
wlan_wmi_cipher_to_crypto(ml_keys->key_cipher);
dst_key->keylen = ml_keys->key_len;
wmi_fill_keys_from_tlv(&ml_keys, dst_key->keyval,
&dst_key->keylen, &count,
total_num_tlv);
wmi_err_rl("ML_KEY: Got Pairwise key for MLD: "
QDF_MAC_ADDR_FMT " rem_len:%d",
QDF_MAC_ADDR_REF(mld_addr->bytes),
dst_key->keylen);
pairwise = dst_key;
/*
* Pairwise keys will be sent only once. Copy that for
* all the link entries
*/
for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) {
dst_key = key_alloc_buf[dst_key_count];
*dst_key = *pairwise;
key_entry[j].keys.key[dst_key->keyix] = dst_key;
dst_key_count++;
}
continue;
}
slot_found = false;
for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) {
if (ml_keys->link_id == MLO_INVALID_LINK_IDX)
break;
if (key_entry[j].link_id == MLO_INVALID_LINK_IDX ||
key_entry[j].link_id == ml_keys->link_id) {
slot_found = true;
break;
}
}
if (!slot_found) {
wmi_err_rl("Not able to find a entry for link:%d j=%d",
ml_keys->link_id, j);
break;
}
WMI_MAC_ADDR_TO_CHAR_ARRAY(&ml_keys->mac_addr,
dst_key->macaddr);
key_entry[j].link_id = ml_keys->link_id;
qdf_copy_macaddr((struct qdf_mac_addr *)key_entry[j].mac_addr.raw,
(struct qdf_mac_addr *)dst_key->macaddr);
all_keys = &key_entry[j].keys;
dst_key->valid = true;
dst_key->keyix = ml_keys->key_ix;
dst_key->cipher_type =
wlan_wmi_cipher_to_crypto(ml_keys->key_cipher);
qdf_mem_copy(dst_key->keyrsc, ml_keys->pn, WMI_MAX_PN_LEN);
/*
* For LTF keyseed or FILS SHA 384, FILS SHA 512 cases, the key
* size will go beyond WMI_MAX_KEY_LEN(32). So extract first 32
* bytes from 1st TLV and extract the rest of the bytes from
* the following TLVs
*/
dst_key->keylen = ml_keys->key_len;
wmi_fill_keys_from_tlv(&ml_keys, dst_key->keyval,
&dst_key->keylen, &count, total_num_tlv);
if (is_igtk(dst_key->keyix)) {
dst_key->key_type = WLAN_CRYPTO_KEY_TYPE_GROUP;
igtk_idx = dst_key->keyix - WLAN_CRYPTO_MAXKEYIDX;
bigtk_idx = igtk_idx - WLAN_CRYPTO_MAXIGTKKEYIDX;
wmi_debug("ML_KEY: Slot:%d link_id:%d addr: " QDF_MAC_ADDR_FMT "Key is IGTK key_ix:%d igtk_idx:%d bigtk:%d",
j, key_entry[j].link_id,
QDF_MAC_ADDR_REF(dst_key->macaddr),
dst_key->keyix, igtk_idx, bigtk_idx);
all_keys->igtk_key[igtk_idx] = dst_key;
all_keys->def_igtk_tx_keyid = igtk_idx;
bigtk_idx = 0;
igtk_idx = 0;
} else if (is_bigtk(dst_key->keyix)) {
dst_key->key_type = WLAN_CRYPTO_KEY_TYPE_GROUP;
igtk_idx = dst_key->keyix - WLAN_CRYPTO_MAXKEYIDX;
bigtk_idx = igtk_idx - WLAN_CRYPTO_MAXIGTKKEYIDX;
wmi_debug("ML_KEY: Slot:%d link_id:%d addr: " QDF_MAC_ADDR_FMT "Key is BIGTK key_ix:%d igtk_idx:%d bigtk:%d",
j, key_entry[j].link_id,
QDF_MAC_ADDR_REF(dst_key->macaddr),
dst_key->keyix, igtk_idx, bigtk_idx);
all_keys->bigtk_key[bigtk_idx] = dst_key;
all_keys->def_bigtk_tx_keyid = bigtk_idx;
bigtk_idx = 0;
igtk_idx = 0;
} else if (is_gtk(dst_key->keyix)) {
wmi_debug("ML_KEY: Slot:%d link_id:%d addr: " QDF_MAC_ADDR_FMT " Key is GTK key_ix:%d",
j, key_entry[j].link_id,
QDF_MAC_ADDR_REF(dst_key->macaddr),
dst_key->keyix);
dst_key->key_type = WLAN_CRYPTO_KEY_TYPE_GROUP;
all_keys->key[dst_key->keyix] = dst_key;
} else {
wmi_debug("Key is Pairwise. Shouldn't reach here");
/* Pairwise key */
dst_key->key_type = WLAN_CRYPTO_KEY_TYPE_UNICAST;
all_keys->key[dst_key->keyix] = dst_key;
}
dst_key_count++;
}
for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) {
if (key_entry[j].link_id != MLO_INVALID_LINK_IDX)
total_links++;
}
*num_entries = total_links;
/* Free the invalid dst_keys allocated */
if (!*num_entries)
goto free_entries;
/*
* This is to free the unfilled key_alloc_buf that
* was allocated initially
*/
flush_keybuf = false;
wmi_err_rl("ML_KEYS: total_entries filled:%d total_num_tlv:%d dst_key_count:%d",
*num_entries, total_num_tlv, dst_key_count);
goto free_keys;
free_entries:
qdf_mem_zero(*entries,
WLAN_MAX_ML_BSS_LINKS * sizeof(**entries));
qdf_mem_free(*entries);
free_keys:
for (k = 0; k < WMI_NUM_KEYS_ALLOCATED; k++) {
if (!key_alloc_buf[k])
continue;
if (!flush_keybuf && key_alloc_buf[k]->valid)
continue;
wmi_debug("Free key allocated at idx:%d", k);
qdf_mem_zero(key_alloc_buf[k], sizeof(key_alloc_buf[k]));
qdf_mem_free(key_alloc_buf[k]);
}
return status;
}
static void
wmi_roam_offload_attach_mlo_tlv(struct wmi_ops *ops)
{
ops->extract_roam_synch_key_event = extract_roam_synch_key_event_tlv;
}
#else
static inline void
wmi_roam_offload_attach_mlo_tlv(struct wmi_ops *ops)
{}
#endif
void wmi_roam_offload_attach_tlv(wmi_unified_t wmi_handle) void wmi_roam_offload_attach_tlv(wmi_unified_t wmi_handle)
{ {
struct wmi_ops *ops = wmi_handle->ops; struct wmi_ops *ops = wmi_handle->ops;
@@ -3703,6 +4107,7 @@ void wmi_roam_offload_attach_tlv(wmi_unified_t wmi_handle)
ops->send_set_roam_trigger_cmd = send_set_roam_trigger_cmd_tlv; ops->send_set_roam_trigger_cmd = send_set_roam_trigger_cmd_tlv;
ops->extract_roam_candidate_frame = extract_roam_candidate_frame_tlv; ops->extract_roam_candidate_frame = extract_roam_candidate_frame_tlv;
wmi_roam_offload_attach_vendor_handoff_tlv(ops); wmi_roam_offload_attach_vendor_handoff_tlv(ops);
wmi_roam_offload_attach_mlo_tlv(ops);
} }
#else #else
static inline QDF_STATUS static inline QDF_STATUS

View File

@@ -87,7 +87,6 @@
#include "wlan_mlo_mgr_sta.h" #include "wlan_mlo_mgr_sta.h"
#include "wlan_mlo_mgr_roam.h" #include "wlan_mlo_mgr_roam.h"
#define RSN_AUTH_KEY_MGMT_SAE WLAN_RSN_SEL(WLAN_AKM_SAE)
#define MAX_PWR_FCC_CHAN_12 8 #define MAX_PWR_FCC_CHAN_12 8
#define MAX_PWR_FCC_CHAN_13 2 #define MAX_PWR_FCC_CHAN_13 2
#define MAX_CB_VALUE_IN_INI (2) #define MAX_CB_VALUE_IN_INI (2)