blob: c059cf146e93334df593b57dec5e077dd684a357 [file] [log] [blame]
/*
* Copyright (c) 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
* 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: defines crypto driver functions interfacing with linux kernel
*/
#include <wlan_crypto_global_def.h>
#include <wlan_crypto_global_api.h>
#include <wlan_objmgr_vdev_obj.h>
#include <wlan_crypto_main_i.h>
#include <net/cfg80211.h>
#include <wlan_nl_to_crypto_params.h>
#include "wlan_cfg80211_crypto.h"
#include <wlan_cfg80211.h>
static void wlan_cfg80211_translate_key(struct wlan_objmgr_vdev *vdev,
uint8_t key_index,
enum wlan_crypto_key_type key_type,
const u8 *mac_addr,
struct key_params *params,
struct wlan_crypto_key *crypto_key)
{
qdf_mem_zero(crypto_key, sizeof(*crypto_key));
crypto_key->keylen = params->key_len;
crypto_key->keyix = key_index;
cfg80211_debug("key_type %d, opmode %d, key_len %d, seq_len %d",
key_type, vdev->vdev_mlme.vdev_opmode,
params->key_len, params->seq_len);
qdf_mem_copy(&crypto_key->keyval[0], params->key, params->key_len);
qdf_mem_copy(&crypto_key->keyrsc[0], params->seq, params->seq_len);
crypto_key->cipher_type = osif_nl_to_crypto_cipher_type(params->cipher);
if (IS_WEP_CIPHER(crypto_key->cipher_type) && !mac_addr) {
/*
* This is a valid scenario in case of WEP, where-in the
* keys are passed by the user space during the connect request
* but since we did not connect yet, so we do not know the peer
* address yet.
*/
cfg80211_debug("No Mac Address to copy");
return;
}
if (key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) {
qdf_mem_copy(&crypto_key->macaddr, mac_addr, QDF_MAC_ADDR_SIZE);
} else {
if ((vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE) ||
(vdev->vdev_mlme.vdev_opmode == QDF_P2P_CLIENT_MODE))
qdf_mem_copy(&crypto_key->macaddr, mac_addr,
QDF_MAC_ADDR_SIZE);
else
qdf_mem_copy(&crypto_key->macaddr,
vdev->vdev_mlme.macaddr,
QDF_MAC_ADDR_SIZE);
}
cfg80211_debug("mac %pM", crypto_key->macaddr);
}
int wlan_cfg80211_store_key(struct wlan_objmgr_vdev *vdev,
uint8_t key_index,
enum wlan_crypto_key_type key_type,
const u8 *mac_addr, struct key_params *params)
{
struct wlan_crypto_key *crypto_key = NULL;
enum wlan_crypto_cipher_type cipher;
int cipher_len;
QDF_STATUS status;
if (!vdev) {
cfg80211_err("vdev is NULL");
return -EINVAL;
}
if (!params) {
cfg80211_err("Key params is NULL");
return -EINVAL;
}
cipher_len = osif_nl_to_crypto_cipher_len(params->cipher);
if (cipher_len < 0 || params->key_len < cipher_len) {
cfg80211_err("cipher length %d less than reqd len %d",
params->key_len, cipher_len);
return -EINVAL;
}
cipher = osif_nl_to_crypto_cipher_type(params->cipher);
if (!IS_WEP_CIPHER(cipher)) {
if ((key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) &&
!mac_addr) {
cfg80211_err("mac_addr is NULL for pairwise Key");
return -EINVAL;
}
}
status = wlan_crypto_validate_key_params(cipher, key_index,
params->key_len,
params->seq_len);
if (QDF_IS_STATUS_ERROR(status)) {
cfg80211_err("Invalid key params");
return -EINVAL;
}
/*
* key may already exist at times and may be retrieved only to
* update it.
*/
crypto_key = wlan_crypto_get_key(vdev, key_index);
if (!crypto_key) {
crypto_key = qdf_mem_malloc(sizeof(*crypto_key));
if (!crypto_key)
return -EINVAL;
status = wlan_crypto_save_key(vdev, key_index, crypto_key);
if (QDF_IS_STATUS_ERROR(status)) {
cfg80211_err("Failed to save key");
qdf_mem_free(crypto_key);
return -EINVAL;
}
}
wlan_cfg80211_translate_key(vdev, key_index, key_type, mac_addr,
params, crypto_key);
return 0;
}
int wlan_cfg80211_crypto_add_key(struct wlan_objmgr_vdev *vdev,
enum wlan_crypto_key_type key_type,
uint8_t key_index)
{
struct wlan_crypto_key *crypto_key;
QDF_STATUS status;
crypto_key = wlan_crypto_get_key(vdev, key_index);
if (!crypto_key) {
cfg80211_err("Crypto KEY is NULL");
return -EINVAL;
}
status = ucfg_crypto_set_key_req(vdev, crypto_key, key_type);
return qdf_status_to_os_return(status);
}
#ifdef CONFIG_CRYPTO_COMPONENT
int wlan_cfg80211_set_default_key(struct wlan_objmgr_vdev *vdev,
uint8_t key_index, struct qdf_mac_addr *bssid)
{
return wlan_crypto_default_key(vdev, (uint8_t *)bssid,
key_index, true);
}
#endif