From 6f8b924d645fadb1603a12f796ee18fe4ce3e4c2 Mon Sep 17 00:00:00 2001 From: Ashok Kumar Date: Mon, 10 Dec 2018 12:26:24 +0530 Subject: [PATCH] qcacmn: Add support for pmksa handling Added support for pmksa handling in crypto to support add_pmksa, del_pmksa and flush_pmksa function calls from cfg80211. Added support for adding pmkid in rsnie. Change-Id: Ic8add9635c2e7fd73da21b1305467e6500f6d73c CRs-Fixed: 2363632 --- .../crypto/inc/wlan_crypto_global_api.h | 28 ++- .../crypto/inc/wlan_crypto_global_def.h | 17 +- .../crypto/src/wlan_crypto_global_api.c | 185 +++++++++++++++++- .../crypto/src/wlan_crypto_obj_mgr.c | 5 +- 4 files changed, 230 insertions(+), 5 deletions(-) diff --git a/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h b/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h index 22d6c335f198..c9c560e82d12 100644 --- a/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h +++ b/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h @@ -300,13 +300,15 @@ uint8_t *wlan_crypto_build_wpaie(struct wlan_objmgr_vdev *vdev, * wlan_crypto_build_rsnie - called by mlme to build rsnie * @vdev: vdev * @iebuf: ie buffer + * @bssid: bssid mac address to add pmkid in rsnie * * This function gets called by mlme to build rsnie from given vdev * * Return: end of buffer */ uint8_t *wlan_crypto_build_rsnie(struct wlan_objmgr_vdev *vdev, - uint8_t *iebuf); + uint8_t *iebuf, + struct qdf_mac_addr *bssid); /** * wlan_crypto_wapiie_check - called by mlme to check the wapiie @@ -799,5 +801,29 @@ static inline QDF_STATUS wlan_crypto_set_key_req(struct wlan_objmgr_vdev *vdev, return QDF_STATUS_SUCCESS; } #endif /* CRYPTO_SET_KEY_CONVERGED */ +/** + * wlan_crypto_pmksa_flush - called to flush saved pmksa + * @crypto_params: crypto_params + * + * This function flush saved pmksa from crypto params. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_pmksa_flush(struct wlan_crypto_params *crypto_params); + +/** + * wlan_crypto_set_vdev_param - called by ucfg to set crypto param + * @vdev: vdev + * @pmksa: pmksa to be set/del. + * @set: set(set=1) or del(set=0) pmksa from the list. + * + * This function gets called from ucfg to set or del pmksa. + * when given pmksa is NULL and set is 0, it is for flush all entries. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_crypto_set_del_pmksa(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_pmksa *pmksa, + bool set); #endif /* end of _WLAN_CRYPTO_GLOBAL_API_H_ */ diff --git a/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h b/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h index 3e87fe0a1151..4288edc0c2fb 100644 --- a/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h +++ b/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h @@ -48,6 +48,7 @@ #define WLAN_CRYPTO_KEYIX_NONE ((uint16_t)-1) #define WLAN_CRYPTO_MAXKEYIDX (4) #define WLAN_CRYPTO_MAXIGTKKEYIDX (2) +#define WLAN_CRYPTO_MAX_PMKID (3) /* 40 bit wep key len */ #define WLAN_CRYPTO_KEY_WEP40_LEN (5) @@ -205,6 +206,17 @@ enum wlan_crypto_key_type { WLAN_CRYPTO_KEY_TYPE_GROUP, }; +/** + * struct wlan_crypto_pmksa - structure of crypto to contain pmkid + * @bssid: bssid for which pmkid is saved + * @pmkid: pmkid + */ + +struct wlan_crypto_pmksa { + struct qdf_mac_addr bssid; + uint8_t pmkid[PMKID_LEN]; +}; + /** * struct wlan_crypto_params - holds crypto params * @authmodeset: authentication mode @@ -212,8 +224,9 @@ enum wlan_crypto_key_type { * @mcastcipherset: multicast cipher * @mgmtcipherset: mgmt cipher * @cipher_caps: cipher capability - * @rsn_caps: rsn_capability * @key_mgmt: key mgmt + * @pmksa: pmksa + * @rsn_caps: rsn_capability * * This structure holds crypto params for peer or vdev */ @@ -224,6 +237,7 @@ struct wlan_crypto_params { uint32_t mgmtcipherset; uint32_t cipher_caps; uint32_t key_mgmt; + struct wlan_crypto_pmksa *pmksa[WLAN_CRYPTO_MAX_PMKID]; uint16_t rsn_caps; }; @@ -235,6 +249,7 @@ typedef enum wlan_crypto_param_type { WLAN_CRYPTO_PARAM_CIPHER_CAP, WLAN_CRYPTO_PARAM_RSN_CAP, WLAN_CRYPTO_PARAM_KEY_MGMT, + WLAN_CRYPTO_PARAM_PMKSA, } wlan_crypto_param_type; /** diff --git a/umac/cmn_services/crypto/src/wlan_crypto_global_api.c b/umac/cmn_services/crypto/src/wlan_crypto_global_api.c index f1974be7ce4e..fca2ff7e16ce 100644 --- a/umac/cmn_services/crypto/src/wlan_crypto_global_api.c +++ b/umac/cmn_services/crypto/src/wlan_crypto_global_api.c @@ -311,6 +311,156 @@ int32_t wlan_crypto_get_peer_param(struct wlan_objmgr_peer *peer, return value; } qdf_export_symbol(wlan_crypto_get_peer_param); + +static +QDF_STATUS wlan_crypto_set_pmksa(struct wlan_crypto_params *crypto_params, + struct wlan_crypto_pmksa *pmksa) +{ + uint8_t i, first_available_slot; + uint8_t slot_found = 0; + + /* find the empty slot or slot with same bssid */ + for (i = 0; i < WLAN_CRYPTO_MAX_PMKID; i++) { + if (!crypto_params->pmksa[i]) { + if (!slot_found) { + slot_found = 1; + first_available_slot = i; + } + continue; + } + if (qdf_is_macaddr_equal(&pmksa->bssid, + &crypto_params->pmksa[i]->bssid)) { + /* free the current pmksa and use this slot */ + qdf_mem_free(crypto_params->pmksa[i]); + crypto_params->pmksa[i] = pmksa; + return QDF_STATUS_SUCCESS; + } + } + + if (i == WLAN_CRYPTO_MAX_PMKID && !slot_found) { + crypto_err("no entry available for pmksa"); + qdf_mem_free(pmksa); + return QDF_STATUS_E_INVAL; + } + crypto_params->pmksa[first_available_slot] = pmksa; + + return QDF_STATUS_SUCCESS; +} + +static +QDF_STATUS wlan_crypto_del_pmksa(struct wlan_crypto_params *crypto_params, + struct wlan_crypto_pmksa *pmksa) +{ + uint8_t i; + + /* find slot with same bssid */ + for (i = 0; i < WLAN_CRYPTO_MAX_PMKID; i++) { + if (!crypto_params->pmksa[i]) + continue; + if (qdf_is_macaddr_equal(&pmksa->bssid, + &crypto_params->pmksa[i]->bssid)) { + qdf_mem_free(crypto_params->pmksa[i]); + crypto_params->pmksa[i] = NULL; + return QDF_STATUS_SUCCESS; + } + } + + return QDF_STATUS_E_INVAL; +} + +QDF_STATUS wlan_crypto_pmksa_flush(struct wlan_crypto_params *crypto_params) +{ + uint8_t i; + + for (i = 0; i < WLAN_CRYPTO_MAX_PMKID; i++) { + if (!crypto_params->pmksa[i]) + continue; + qdf_mem_free(crypto_params->pmksa[i]); + crypto_params->pmksa[i] = NULL; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_crypto_set_del_pmksa(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_pmksa *pmksa, + bool set) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) + return QDF_STATUS_E_NOSUPPORT; + + if (!pmksa && set) { + crypto_err("pmksa is NULL for set operation"); + return QDF_STATUS_E_INVAL; + } + crypto_priv = (struct wlan_crypto_comp_priv *) + wlan_get_vdev_crypto_obj(vdev); + + if (!crypto_priv) { + crypto_err("crypto_priv NULL"); + return QDF_STATUS_E_INVAL; + } + + crypto_params = &crypto_priv->crypto_params; + if (set) { + status = wlan_crypto_set_pmksa(crypto_params, pmksa); + /* Set pmksa */ + } else { + /* del pmksa */ + if (!pmksa) + status = wlan_crypto_pmksa_flush(crypto_params); + else + status = wlan_crypto_del_pmksa(crypto_params, pmksa); + } + + return status; +} + +/** + * wlan_crypto_get_pmksa - called to get pmksa of bssid passed. + * @vdev: vdev + * @bssid: bssid + * + * This function gets called from to get pmksa for the bssid. + * + * Return: wlan_crypto_pmksa when match found else NULL. + */ +static struct wlan_crypto_pmksa * +wlan_crypto_get_pmksa(struct wlan_objmgr_vdev *vdev, struct qdf_mac_addr *bssid) +{ + struct wlan_crypto_comp_priv *crypto_priv; + struct wlan_crypto_params *crypto_params; + uint8_t i; + + if (!bssid) { + crypto_err("bssid is NULL"); + return NULL; + } + crypto_priv = (struct wlan_crypto_comp_priv *) + wlan_get_vdev_crypto_obj(vdev); + + if (!crypto_priv) { + crypto_err("crypto_priv NULL"); + return NULL; + } + + crypto_params = &crypto_priv->crypto_params; + + for (i = 0; i < WLAN_CRYPTO_MAX_PMKID; i++) { + if (!crypto_params->pmksa[i]) + continue; + if (qdf_is_macaddr_equal(bssid, + &crypto_params->pmksa[i]->bssid)) { + return crypto_params->pmksa[i]; + } + } + + return NULL; +} /** * wlan_crypto_is_htallowed - called to check is HT allowed for cipher * @vdev: vdev @@ -2412,13 +2562,16 @@ uint8_t *wlan_crypto_build_wpaie(struct wlan_objmgr_vdev *vdev, * wlan_crypto_build_rsnie - called by mlme to build rsnie * @vdev: vdev * @iebuf: ie buffer + * @bssid: bssid mac address to add pmkid in rsnie * * This function gets called by mlme to build rsnie from given vdev * * Return: end of buffer */ uint8_t *wlan_crypto_build_rsnie(struct wlan_objmgr_vdev *vdev, - uint8_t *iebuf){ + uint8_t *iebuf, + struct qdf_mac_addr *bssid) +{ uint8_t *frm = iebuf; uint8_t *selcnt; struct wlan_crypto_comp_priv *crypto_priv; @@ -2569,7 +2722,21 @@ add_rsn_caps: /* optional capabilities */ if (crypto_params->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED) { /* PMK list */ - WLAN_CRYPTO_ADDSHORT(frm, 0); + if (bssid) { + struct wlan_crypto_pmksa *pmksa; + + pmksa = wlan_crypto_get_pmksa(vdev, bssid); + + if (pmksa) { + WLAN_CRYPTO_ADDSHORT(frm, 1); + qdf_mem_copy(frm, pmksa->pmkid, PMKID_LEN); + frm += PMKID_LEN; + } else { + WLAN_CRYPTO_ADDSHORT(frm, 0); + } + } else + WLAN_CRYPTO_ADDSHORT(frm, 0); + if (HAS_MGMT_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CMAC)) { RSN_ADD_CIPHER_TO_SUITE(frm, @@ -2593,6 +2760,20 @@ add_rsn_caps: WLAN_CRYPTO_CIPHER_AES_GMAC_256 ); } + } else { + /* PMK list */ + if (bssid) { + struct wlan_crypto_pmksa *pmksa; + + pmksa = wlan_crypto_get_pmksa(vdev, bssid); + if (pmksa) { + WLAN_CRYPTO_ADDSHORT(frm, 1); + qdf_mem_copy(frm, pmksa->pmkid, PMKID_LEN); + frm += PMKID_LEN; + } else { + WLAN_CRYPTO_ADDSHORT(frm, 0); + } + } } /* calculate element length */ diff --git a/umac/cmn_services/crypto/src/wlan_crypto_obj_mgr.c b/umac/cmn_services/crypto/src/wlan_crypto_obj_mgr.c index 28f611dadb0d..401ca5c7d09b 100644 --- a/umac/cmn_services/crypto/src/wlan_crypto_obj_mgr.c +++ b/umac/cmn_services/crypto/src/wlan_crypto_obj_mgr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -214,9 +214,12 @@ static QDF_STATUS wlan_crypto_vdev_obj_destroy_handler( crypto_err("crypto_priv NULL"); return QDF_STATUS_E_INVAL; } + wlan_objmgr_vdev_component_obj_detach(vdev, WLAN_UMAC_COMP_CRYPTO, (void *)crypto_priv); + + wlan_crypto_pmksa_flush(&crypto_priv->crypto_params); wlan_crypto_free_key(crypto_priv); qdf_mem_free(crypto_priv);