blob: fcdc8d874967da16cddd8ad932487fb7781a3b56 [file] [log] [blame]
/*
* Copyright (c) 2017-2018 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
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/**
* DOC: Public API intialization of crypto service with object manager
*/
#include <qdf_types.h>
#include <wlan_cmn.h>
#include <wlan_objmgr_cmn.h>
#include <wlan_objmgr_global_obj.h>
#include <wlan_objmgr_psoc_obj.h>
#include <wlan_objmgr_pdev_obj.h>
#include <wlan_objmgr_vdev_obj.h>
#include <wlan_objmgr_peer_obj.h>
#include "wlan_crypto_global_def.h"
#include "wlan_crypto_global_api.h"
#include "wlan_crypto_def_i.h"
#include "wlan_crypto_main_i.h"
#include "wlan_crypto_obj_mgr_i.h"
#include "wlan_crypto_fils_api.h"
extern const struct wlan_crypto_cipher
*wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_MAX];
static QDF_STATUS wlan_crypto_register_all_ciphers(
struct wlan_crypto_params *crypto_param)
{
if (HAS_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_WEP)) {
wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_WEP]
= wep_register();
}
if (HAS_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_TKIP_MIC)) {
wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_TKIP]
= tkip_register();
}
if (HAS_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_AES)) {
wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_AES_CCM]
= ccmp_register();
wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_AES_CCM_256]
= ccmp256_register();
wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_AES_GCM]
= gcmp_register();
wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_AES_GCM_256]
= gcmp256_register();
}
if (HAS_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_WAPI_SMS4)) {
wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_WAPI_SMS4]
= wapi_register();
}
if (HAS_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_FILS_AEAD)) {
wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_FILS_AEAD]
= fils_register();
}
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS wlan_crypto_vdev_obj_create_handler(
struct wlan_objmgr_vdev *vdev,
void *arg)
{
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_objmgr_pdev *pdev;
struct wlan_crypto_params *crypto_param;
QDF_STATUS status;
if (!vdev)
return QDF_STATUS_E_INVAL;
crypto_priv = qdf_mem_malloc(sizeof(struct wlan_crypto_comp_priv));
if (!crypto_priv)
return QDF_STATUS_E_NOMEM;
crypto_param = &(crypto_priv->crypto_params);
RESET_AUTHMODE(crypto_param);
RESET_UCAST_CIPHERS(crypto_param);
RESET_MCAST_CIPHERS(crypto_param);
RESET_MGMT_CIPHERS(crypto_param);
RESET_KEY_MGMT(crypto_param);
RESET_CIPHER_CAP(crypto_param);
pdev = wlan_vdev_get_pdev(vdev);
wlan_pdev_obj_lock(pdev);
if (wlan_pdev_nif_fw_cap_get(pdev, WLAN_SOC_C_WEP))
SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_WEP);
if (wlan_pdev_nif_fw_cap_get(pdev, WLAN_SOC_C_TKIP))
SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_TKIP_MIC);
if (wlan_pdev_nif_fw_cap_get(pdev, WLAN_SOC_C_AES)) {
SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_AES);
SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_CCM256);
SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_GCM);
SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_GCM_256);
}
if (wlan_pdev_nif_fw_cap_get(pdev, WLAN_SOC_C_CKIP))
SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_CKIP);
if (wlan_pdev_nif_fw_cap_get(pdev, WLAN_SOC_C_WAPI))
SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_WAPI_SMS4);
SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_FILS_AEAD);
wlan_pdev_obj_unlock(pdev);
/* update the crypto cipher table based on the fw caps*/
/* update the fw_caps into ciphercaps then attach to objmgr*/
wlan_crypto_register_all_ciphers(crypto_param);
status = wlan_objmgr_vdev_component_obj_attach(vdev,
WLAN_UMAC_COMP_CRYPTO,
(void *)crypto_priv,
QDF_STATUS_SUCCESS);
if (status != QDF_STATUS_SUCCESS)
qdf_mem_free(crypto_priv);
return status;
}
static QDF_STATUS wlan_crypto_peer_obj_create_handler(
struct wlan_objmgr_peer *peer,
void *arg)
{
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_param;
QDF_STATUS status;
if (!peer)
return QDF_STATUS_E_INVAL;
crypto_priv = qdf_mem_malloc(sizeof(struct wlan_crypto_comp_priv));
if (!crypto_priv)
return QDF_STATUS_E_NOMEM;
status = wlan_objmgr_peer_component_obj_attach(peer,
WLAN_UMAC_COMP_CRYPTO, (void *)crypto_priv,
QDF_STATUS_SUCCESS);
if (status == QDF_STATUS_SUCCESS) {
crypto_param = &crypto_priv->crypto_params;
RESET_AUTHMODE(crypto_param);
RESET_UCAST_CIPHERS(crypto_param);
RESET_MCAST_CIPHERS(crypto_param);
RESET_MGMT_CIPHERS(crypto_param);
RESET_KEY_MGMT(crypto_param);
RESET_CIPHER_CAP(crypto_param);
if (wlan_vdev_get_selfpeer(peer->peer_objmgr.vdev) != peer) {
wlan_crypto_set_peer_wep_keys(
wlan_peer_get_vdev(peer), peer);
}
} else {
qdf_print("%s[%d] peer obj failed status %d\n",
__func__, __LINE__, status);
qdf_mem_free(crypto_priv);
}
return status;
}
static void wlan_crypto_free_key(struct wlan_crypto_comp_priv *crypto_priv)
{
uint8_t i;
if (!crypto_priv) {
qdf_print("%s[%d] crypto_priv NULL\n", __func__, __LINE__);
return;
}
for (i = 0; i < WLAN_CRYPTO_MAXKEYIDX; i++) {
if (crypto_priv->key[i]) {
qdf_mem_free(crypto_priv->key[i]);
crypto_priv->key[i] = NULL;
}
}
for (i = 0; i < WLAN_CRYPTO_MAXIGTKKEYIDX; i++) {
if (crypto_priv->igtk_key[i]) {
qdf_mem_free(crypto_priv->igtk_key[i]);
crypto_priv->igtk_key[i] = NULL;
}
}
}
static QDF_STATUS wlan_crypto_vdev_obj_destroy_handler(
struct wlan_objmgr_vdev *vdev,
void *arg){
struct wlan_crypto_comp_priv *crypto_priv;
if (!vdev) {
qdf_print("%s[%d] Vdev NULL\n", __func__, __LINE__);
return QDF_STATUS_E_INVAL;
}
crypto_priv = (struct wlan_crypto_comp_priv *)
wlan_get_vdev_crypto_obj(vdev);
if (!crypto_priv) {
qdf_print("%s[%d] crypto_priv NULL\n", __func__, __LINE__);
return QDF_STATUS_E_INVAL;
}
wlan_objmgr_vdev_component_obj_detach(vdev,
WLAN_UMAC_COMP_CRYPTO,
(void *)crypto_priv);
wlan_crypto_free_key(crypto_priv);
qdf_mem_free(crypto_priv);
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS wlan_crypto_peer_obj_destroy_handler(
struct wlan_objmgr_peer *peer,
void *arg){
struct wlan_crypto_comp_priv *crypto_priv;
if (!peer) {
qdf_print("%s[%d] Peer NULL\n", __func__, __LINE__);
return QDF_STATUS_E_INVAL;
}
crypto_priv = (struct wlan_crypto_comp_priv *)
wlan_get_peer_crypto_obj(peer);
if (!crypto_priv) {
qdf_print("%s[%d] crypto_priv NULL\n", __func__, __LINE__);
return QDF_STATUS_E_INVAL;
}
wlan_objmgr_peer_component_obj_detach(peer,
WLAN_UMAC_COMP_CRYPTO,
(void *)crypto_priv);
wlan_crypto_free_key(crypto_priv);
qdf_mem_free(crypto_priv);
return QDF_STATUS_SUCCESS;
}
/**
* __wlan_crypto_init - Init the crypto service with object manager
* Called from crypto init context.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS __wlan_crypto_init(void)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
status = wlan_objmgr_register_vdev_create_handler(
WLAN_UMAC_COMP_CRYPTO,
wlan_crypto_vdev_obj_create_handler, NULL);
if (status != QDF_STATUS_SUCCESS)
return status;
status = wlan_objmgr_register_peer_create_handler(
WLAN_UMAC_COMP_CRYPTO,
wlan_crypto_peer_obj_create_handler, NULL);
if (status != QDF_STATUS_SUCCESS)
goto err_peer_create;
status = wlan_objmgr_register_vdev_destroy_handler(
WLAN_UMAC_COMP_CRYPTO,
wlan_crypto_vdev_obj_destroy_handler, NULL);
if (status != QDF_STATUS_SUCCESS)
goto err_vdev_delete;
status = wlan_objmgr_register_peer_destroy_handler(
WLAN_UMAC_COMP_CRYPTO,
wlan_crypto_peer_obj_destroy_handler, NULL);
if (status != QDF_STATUS_SUCCESS)
goto err_peer_delete;
goto register_success;
err_peer_delete:
wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_CRYPTO,
wlan_crypto_vdev_obj_destroy_handler, NULL);
err_vdev_delete:
wlan_objmgr_unregister_peer_create_handler(WLAN_UMAC_COMP_CRYPTO,
wlan_crypto_peer_obj_create_handler, NULL);
err_peer_create:
wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_CRYPTO,
wlan_crypto_vdev_obj_create_handler, NULL);
register_success:
return status;
}
/**
* __wlan_crypto_deinit - Deinit the crypto service with object manager
* Called from crypto context.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS __wlan_crypto_deinit(void)
{
if (wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_CRYPTO,
wlan_crypto_vdev_obj_create_handler, NULL)
!= QDF_STATUS_SUCCESS) {
return QDF_STATUS_E_FAILURE;
}
if (wlan_objmgr_unregister_peer_create_handler(WLAN_UMAC_COMP_CRYPTO,
wlan_crypto_peer_obj_create_handler, NULL)
!= QDF_STATUS_SUCCESS) {
return QDF_STATUS_E_FAILURE;
}
if (wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_CRYPTO,
wlan_crypto_vdev_obj_destroy_handler, NULL)
!= QDF_STATUS_SUCCESS) {
return QDF_STATUS_E_FAILURE;
}
if (wlan_objmgr_unregister_peer_destroy_handler(WLAN_UMAC_COMP_CRYPTO,
wlan_crypto_peer_obj_destroy_handler, NULL)
!= QDF_STATUS_SUCCESS) {
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}