blob: 03d7ed98f8422ecd1332f5c9d14fac19702706c8 [file] [log] [blame]
/*
* 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
* 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 APIs for crypto service
*/
#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_utility.h>
#include "wlan_crypto_global_def.h"
#include "wlan_crypto_global_api.h"
#include "wlan_crypto_def_i.h"
#include "wlan_crypto_param_handling_i.h"
#include "wlan_crypto_obj_mgr_i.h"
#include <qdf_module.h>
const struct wlan_crypto_cipher *wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_MAX];
#define WPA_ADD_CIPHER_TO_SUITE(frm, cipher) \
WLAN_CRYPTO_ADDSELECTOR(frm,\
wlan_crypto_wpa_cipher_to_suite(cipher))
#define RSN_ADD_CIPHER_TO_SUITE(frm, cipher) \
WLAN_CRYPTO_ADDSELECTOR(frm,\
wlan_crypto_rsn_cipher_to_suite(cipher))
#define WPA_ADD_KEYMGMT_TO_SUITE(frm, keymgmt)\
WLAN_CRYPTO_ADDSELECTOR(frm,\
wlan_crypto_wpa_keymgmt_to_suite(keymgmt))
#define RSN_ADD_KEYMGMT_TO_SUITE(frm, keymgmt)\
WLAN_CRYPTO_ADDSELECTOR(frm,\
wlan_crypto_rsn_keymgmt_to_suite(keymgmt))
/**
* wlan_crypto_vdev_get_crypto_params - called by mlme to get crypto params
* @vdev:vdev
*
* This function gets called by mlme to get crypto params
*
* Return: wlan_crypto_params or NULL in case of failure
*/
static struct wlan_crypto_params *wlan_crypto_vdev_get_comp_params(
struct wlan_objmgr_vdev *vdev,
struct wlan_crypto_comp_priv **crypto_priv){
*crypto_priv = (struct wlan_crypto_comp_priv *)
wlan_get_vdev_crypto_obj(vdev);
if (!(*crypto_priv)) {
crypto_err("crypto_priv NULL");
return NULL;
}
return &((*crypto_priv)->crypto_params);
}
/**
* wlan_crypto_peer_get_crypto_params - called by mlme to get crypto params
* @peer:peer
*
* This function gets called by mlme to get crypto params
*
* Return: wlan_crypto_params or NULL in case of failure
*/
static struct wlan_crypto_params *wlan_crypto_peer_get_comp_params(
struct wlan_objmgr_peer *peer,
struct wlan_crypto_comp_priv **crypto_priv){
*crypto_priv = (struct wlan_crypto_comp_priv *)
wlan_get_peer_crypto_obj(peer);
if (!*crypto_priv) {
crypto_err("crypto_priv NULL");
return NULL;
}
return &((*crypto_priv)->crypto_params);
}
static QDF_STATUS wlan_crypto_set_igtk_key(struct wlan_crypto_key *key)
{
return QDF_STATUS_SUCCESS;
}
/**
* wlan_crypto_set_param - called by ucfg to set crypto param
* @crypto_params: crypto_params
* @param: param to be set.
* @value: value
*
* This function gets called from ucfg to set param
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
static QDF_STATUS wlan_crypto_set_param(struct wlan_crypto_params *crypto_params,
wlan_crypto_param_type param,
uint32_t value){
QDF_STATUS status = QDF_STATUS_E_INVAL;
crypto_debug("param %d, value %d", param, value);
switch (param) {
case WLAN_CRYPTO_PARAM_AUTH_MODE:
status = wlan_crypto_set_authmode(crypto_params, value);
break;
case WLAN_CRYPTO_PARAM_UCAST_CIPHER:
status = wlan_crypto_set_ucastciphers(crypto_params, value);
break;
case WLAN_CRYPTO_PARAM_MCAST_CIPHER:
status = wlan_crypto_set_mcastcipher(crypto_params, value);
break;
case WLAN_CRYPTO_PARAM_MGMT_CIPHER:
status = wlan_crypto_set_mgmtcipher(crypto_params, value);
break;
case WLAN_CRYPTO_PARAM_CIPHER_CAP:
status = wlan_crypto_set_cipher_cap(crypto_params, value);
break;
case WLAN_CRYPTO_PARAM_RSN_CAP:
status = wlan_crypto_set_rsn_cap(crypto_params, value);
break;
case WLAN_CRYPTO_PARAM_KEY_MGMT:
status = wlan_crypto_set_key_mgmt(crypto_params, value);
break;
default:
status = QDF_STATUS_E_INVAL;
}
return status;
}
/**
* wlan_crypto_set_vdev_param - called by ucfg to set crypto param
* @vdev: vdev
* @param: param to be set.
* @value: value
*
* This function gets called from ucfg to set param
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_set_vdev_param(struct wlan_objmgr_vdev *vdev,
wlan_crypto_param_type param,
uint32_t value){
QDF_STATUS status = QDF_STATUS_E_INVAL;
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
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);
status = wlan_crypto_set_param(crypto_params, param, value);
return status;
}
/**
* wlan_crypto_set_param - called by ucfg to set crypto param
*
* @peer: peer
* @param: param to be set.
* @value: value
*
* This function gets called from ucfg to set param
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_set_peer_param(struct wlan_objmgr_peer *peer,
wlan_crypto_param_type param,
uint32_t value){
QDF_STATUS status = QDF_STATUS_E_INVAL;
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
crypto_params = wlan_crypto_peer_get_comp_params(peer,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
crypto_params = &(crypto_priv->crypto_params);
status = wlan_crypto_set_param(crypto_params, param, value);
return status;
}
/**
* wlan_crypto_get_param_value - called by crypto APIs to get value for param
* @param: Crypto param type
* @crypto_params: Crypto params struct
*
* This function gets called from in-within crypto layer
*
* Return: value or -1 for failure
*/
static int32_t wlan_crypto_get_param_value(wlan_crypto_param_type param,
struct wlan_crypto_params *crypto_params)
{
int32_t value = -1;
switch (param) {
case WLAN_CRYPTO_PARAM_AUTH_MODE:
value = wlan_crypto_get_authmode(crypto_params);
break;
case WLAN_CRYPTO_PARAM_UCAST_CIPHER:
value = wlan_crypto_get_ucastciphers(crypto_params);
break;
case WLAN_CRYPTO_PARAM_MCAST_CIPHER:
value = wlan_crypto_get_mcastcipher(crypto_params);
break;
case WLAN_CRYPTO_PARAM_MGMT_CIPHER:
value = wlan_crypto_get_mgmtciphers(crypto_params);
break;
case WLAN_CRYPTO_PARAM_CIPHER_CAP:
value = wlan_crypto_get_cipher_cap(crypto_params);
break;
case WLAN_CRYPTO_PARAM_RSN_CAP:
value = wlan_crypto_get_rsn_cap(crypto_params);
break;
case WLAN_CRYPTO_PARAM_KEY_MGMT:
value = wlan_crypto_get_key_mgmt(crypto_params);
break;
default:
value = QDF_STATUS_E_INVAL;
}
return value;
}
/**
* wlan_crypto_get_param - called to get value for param from vdev
* @vdev: vdev
* @param: Crypto param type
*
* This function gets called to get value for param from vdev
*
* Return: value or -1 for failure
*/
int32_t wlan_crypto_get_param(struct wlan_objmgr_vdev *vdev,
wlan_crypto_param_type param)
{
int32_t value = -1;
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
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);
value = wlan_crypto_get_param_value(param, crypto_params);
return value;
}
/**
* wlan_crypto_get_peer_param - called to get value for param from peer
* @peer: peer
* @param: Crypto param type
*
* This function gets called to get value for param from peer
*
* Return: value or -1 for failure
*/
int32_t wlan_crypto_get_peer_param(struct wlan_objmgr_peer *peer,
wlan_crypto_param_type param)
{
int32_t value = -1;
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
crypto_params = wlan_crypto_peer_get_comp_params(peer,
&crypto_priv);
if (!crypto_params) {
crypto_err("crypto_params NULL");
return QDF_STATUS_E_INVAL;
}
value = wlan_crypto_get_param_value(param, crypto_params);
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 = 0;
bool slot_found = false;
/* 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 = true;
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_zero(crypto_params->pmksa[i],
sizeof(struct wlan_crypto_pmksa));
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");
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_zero(crypto_params->pmksa[i],
sizeof(struct wlan_crypto_pmksa));
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_zero(crypto_params->pmksa[i],
sizeof(struct wlan_crypto_pmksa));
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;
enum QDF_OPMODE op_mode;
op_mode = wlan_vdev_mlme_get_opmode(vdev);
if (op_mode != QDF_STA_MODE && op_mode != QDF_SAP_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;
}
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
* @peer: peer
*
* This function gets called to check is HT allowed for cipher.
* HT is not allowed for wep and tkip.
*
* Return: 0 - not allowed or 1 - allowed
*/
uint8_t wlan_crypto_is_htallowed(struct wlan_objmgr_vdev *vdev,
struct wlan_objmgr_peer *peer)
{
int32_t ucast_cipher;
if (!(vdev || peer)) {
crypto_err("Invalid params");
return 0;
}
if (vdev)
ucast_cipher = wlan_crypto_get_param(vdev,
WLAN_CRYPTO_PARAM_UCAST_CIPHER);
else
ucast_cipher = wlan_crypto_get_peer_param(peer,
WLAN_CRYPTO_PARAM_UCAST_CIPHER);
return (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_WEP)) ||
((ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_TKIP)) &&
!(ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_CCM)) &&
!(ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_GCM)) &&
!(ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_GCM_256)) &&
!(ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_CCM_256)));
}
qdf_export_symbol(wlan_crypto_is_htallowed);
/**
* wlan_crypto_setkey - called by ucfg to setkey
* @vdev: vdev
* @req_key: req_key with cipher type, key macaddress
*
* This function gets called from ucfg to sey key
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_setkey(struct wlan_objmgr_vdev *vdev,
struct wlan_crypto_req_key *req_key){
QDF_STATUS status = QDF_STATUS_E_INVAL;
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_objmgr_psoc *psoc;
struct wlan_objmgr_peer *peer;
struct wlan_crypto_key *key = NULL;
const struct wlan_crypto_cipher *cipher;
uint8_t macaddr[QDF_MAC_ADDR_SIZE] =
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
bool isbcast;
enum QDF_OPMODE vdev_mode;
uint8_t igtk_idx = 0;
if (!vdev || !req_key || req_key->keylen > (sizeof(req_key->keydata))) {
crypto_err("Invalid params vdev%pK, req_key%pK", vdev, req_key);
return QDF_STATUS_E_INVAL;
}
isbcast = qdf_is_macaddr_group(
(struct qdf_mac_addr *)req_key->macaddr);
if ((req_key->keylen == 0) && !IS_FILS_CIPHER(req_key->type)) {
/* zero length keys, only set default key id if flags are set*/
if ((req_key->flags & WLAN_CRYPTO_KEY_DEFAULT)
&& (req_key->keyix != WLAN_CRYPTO_KEYIX_NONE)
&& (!IS_MGMT_CIPHER(req_key->type))) {
wlan_crypto_default_key(vdev,
req_key->macaddr,
req_key->keyix,
!isbcast);
return QDF_STATUS_SUCCESS;
}
crypto_err("req_key len zero");
return QDF_STATUS_E_INVAL;
}
cipher = wlan_crypto_cipher_ops[req_key->type];
if (!cipher && !IS_MGMT_CIPHER(req_key->type)) {
crypto_err("cipher invalid");
return QDF_STATUS_E_INVAL;
}
if (cipher && (!IS_FILS_CIPHER(req_key->type)) &&
(!IS_MGMT_CIPHER(req_key->type)) &&
((req_key->keylen != (cipher->keylen / CRYPTO_NBBY)) &&
(req_key->type != WLAN_CRYPTO_CIPHER_WEP))) {
crypto_err("cipher invalid");
return QDF_STATUS_E_INVAL;
} else if ((req_key->type == WLAN_CRYPTO_CIPHER_WEP) &&
!((req_key->keylen == WLAN_CRYPTO_KEY_WEP40_LEN)
|| (req_key->keylen == WLAN_CRYPTO_KEY_WEP104_LEN)
|| (req_key->keylen == WLAN_CRYPTO_KEY_WEP128_LEN))) {
crypto_err("wep key len invalid. keylen: %d", req_key->keylen);
return QDF_STATUS_E_INVAL;
}
if (req_key->keyix == WLAN_CRYPTO_KEYIX_NONE) {
if (req_key->flags != (WLAN_CRYPTO_KEY_XMIT
| WLAN_CRYPTO_KEY_RECV)) {
req_key->flags |= (WLAN_CRYPTO_KEY_XMIT
| WLAN_CRYPTO_KEY_RECV);
}
} else {
if ((req_key->keyix >= WLAN_CRYPTO_MAX_VLANKEYIX)
&& (!IS_MGMT_CIPHER(req_key->type))) {
return QDF_STATUS_E_INVAL;
}
req_key->flags |= (WLAN_CRYPTO_KEY_XMIT
| WLAN_CRYPTO_KEY_RECV);
if (isbcast)
req_key->flags |= WLAN_CRYPTO_KEY_GROUP;
}
vdev_mode = wlan_vdev_mlme_get_opmode(vdev);
wlan_vdev_obj_lock(vdev);
qdf_mem_copy(macaddr, wlan_vdev_mlme_get_macaddr(vdev),
QDF_MAC_ADDR_SIZE);
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
wlan_vdev_obj_unlock(vdev);
crypto_err("psoc NULL");
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_unlock(vdev);
if (req_key->type == WLAN_CRYPTO_CIPHER_WEP) {
if (wlan_crypto_vdev_has_auth_mode(vdev,
(1 << WLAN_CRYPTO_AUTH_8021X))) {
req_key->flags |= WLAN_CRYPTO_KEY_DEFAULT;
}
}
if (isbcast) {
crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
if (IS_MGMT_CIPHER(req_key->type)) {
igtk_idx = req_key->keyix - WLAN_CRYPTO_MAXKEYIDX;
if (igtk_idx >= WLAN_CRYPTO_MAXIGTKKEYIDX) {
crypto_err("igtk key invalid keyid %d",
igtk_idx);
return QDF_STATUS_E_INVAL;
}
key = qdf_mem_malloc(sizeof(struct wlan_crypto_key));
if (!key)
return QDF_STATUS_E_NOMEM;
if (crypto_priv->igtk_key[igtk_idx])
qdf_mem_free(crypto_priv->igtk_key[igtk_idx]);
crypto_priv->igtk_key[igtk_idx] = key;
crypto_priv->igtk_key_type = req_key->type;
crypto_priv->def_igtk_tx_keyid = igtk_idx;
} else {
if (IS_FILS_CIPHER(req_key->type)) {
crypto_err("FILS key is not for BroadCast pkt");
return QDF_STATUS_E_INVAL;
}
if (!HAS_MCAST_CIPHER(crypto_params, req_key->type)
&& (req_key->type != WLAN_CRYPTO_CIPHER_WEP)) {
return QDF_STATUS_E_INVAL;
}
if (!crypto_priv->key[req_key->keyix]) {
crypto_priv->key[req_key->keyix]
= qdf_mem_malloc(
sizeof(struct wlan_crypto_key));
if (!crypto_priv->key[req_key->keyix])
return QDF_STATUS_E_NOMEM;
}
key = crypto_priv->key[req_key->keyix];
}
if (vdev_mode == QDF_STA_MODE) {
peer = wlan_objmgr_vdev_try_get_bsspeer(vdev,
WLAN_CRYPTO_ID);
if (!peer) {
crypto_err("peer NULL");
if (IS_MGMT_CIPHER(req_key->type)) {
crypto_priv->igtk_key[igtk_idx] = NULL;
crypto_priv->igtk_key_type
= WLAN_CRYPTO_CIPHER_NONE;
} else
crypto_priv->key[req_key->keyix] = NULL;
if (key)
qdf_mem_free(key);
return QDF_STATUS_E_INVAL;
}
qdf_mem_copy(macaddr, wlan_peer_get_macaddr(peer),
QDF_MAC_ADDR_SIZE);
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
}
} else {
uint8_t pdev_id;
pdev_id = wlan_objmgr_pdev_get_pdev_id(
wlan_vdev_get_pdev(vdev));
peer = wlan_objmgr_get_peer_by_mac_n_vdev(
psoc,
pdev_id,
macaddr,
req_key->macaddr,
WLAN_CRYPTO_ID);
if (!peer) {
crypto_err("peer NULL");
return QDF_STATUS_E_INVAL;
}
qdf_mem_copy(macaddr, req_key->macaddr, QDF_MAC_ADDR_SIZE);
crypto_params = wlan_crypto_peer_get_comp_params(peer,
&crypto_priv);
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
if (IS_MGMT_CIPHER(req_key->type)) {
igtk_idx = req_key->keyix - WLAN_CRYPTO_MAXKEYIDX;
if (igtk_idx >= WLAN_CRYPTO_MAXIGTKKEYIDX) {
crypto_err("igtk key invalid keyid %d",
igtk_idx);
return QDF_STATUS_E_INVAL;
}
key = qdf_mem_malloc(sizeof(struct wlan_crypto_key));
if (!key)
return QDF_STATUS_E_NOMEM;
if (crypto_priv->igtk_key[igtk_idx])
qdf_mem_free(crypto_priv->igtk_key[igtk_idx]);
crypto_priv->igtk_key[igtk_idx] = key;
crypto_priv->igtk_key_type = req_key->type;
crypto_priv->def_igtk_tx_keyid = igtk_idx;
} else {
uint16_t kid = req_key->keyix;
if (kid == WLAN_CRYPTO_KEYIX_NONE)
kid = 0;
if (kid >= WLAN_CRYPTO_MAX_VLANKEYIX) {
crypto_err("invalid keyid %d", kid);
return QDF_STATUS_E_INVAL;
}
if (!crypto_priv->key[kid]) {
crypto_priv->key[kid]
= qdf_mem_malloc(
sizeof(struct wlan_crypto_key));
if (!crypto_priv->key[kid])
return QDF_STATUS_E_NOMEM;
}
key = crypto_priv->key[kid];
}
}
/* alloc key might not required as it is already there */
key->cipher_table = (void *)cipher;
key->keylen = req_key->keylen;
key->flags = req_key->flags;
if (req_key->keyix == WLAN_CRYPTO_KEYIX_NONE)
key->keyix = 0;
else
key->keyix = req_key->keyix;
if (req_key->flags & WLAN_CRYPTO_KEY_DEFAULT
&& (!IS_MGMT_CIPHER(req_key->type))) {
crypto_priv->def_tx_keyid = key->keyix;
key->flags |= WLAN_CRYPTO_KEY_DEFAULT;
}
if ((req_key->type == WLAN_CRYPTO_CIPHER_WAPI_SMS4)
|| (req_key->type == WLAN_CRYPTO_CIPHER_WAPI_GCM4)) {
uint8_t iv_AP[16] = { 0x5c, 0x36, 0x5c, 0x36,
0x5c, 0x36, 0x5c, 0x36,
0x5c, 0x36, 0x5c, 0x36,
0x5c, 0x36, 0x5c, 0x37};
uint8_t iv_STA[16] = { 0x5c, 0x36, 0x5c, 0x36,
0x5c, 0x36, 0x5c, 0x36,
0x5c, 0x36, 0x5c, 0x36,
0x5c, 0x36, 0x5c, 0x36};
/* During Tx PN should be increment and
* send but as per our implementation we increment only after
* Tx complete. So First packet PN check will be failed.
* To compensate increment the PN here by 2
*/
if (vdev_mode == QDF_SAP_MODE) {
iv_AP[15] += 2;
qdf_mem_copy(key->recviv, iv_STA,
WLAN_CRYPTO_WAPI_IV_SIZE);
qdf_mem_copy(key->txiv, iv_AP,
WLAN_CRYPTO_WAPI_IV_SIZE);
} else {
iv_STA[15] += 2;
qdf_mem_copy(key->recviv, iv_AP,
WLAN_CRYPTO_WAPI_IV_SIZE);
qdf_mem_copy(key->txiv, iv_STA,
WLAN_CRYPTO_WAPI_IV_SIZE);
}
} else {
uint8_t i = 0;
qdf_mem_copy((uint8_t *)(&key->keytsc),
(uint8_t *)(&req_key->keytsc), sizeof(key->keytsc));
for (i = 0; i < WLAN_CRYPTO_TID_SIZE; i++) {
qdf_mem_copy((uint8_t *)(&key->keyrsc[i]),
(uint8_t *)(&req_key->keyrsc),
sizeof(key->keyrsc[0]));
}
}
qdf_mem_copy(key->keyval, req_key->keydata, sizeof(key->keyval));
key->valid = 1;
if ((IS_MGMT_CIPHER(req_key->type))) {
if (HAS_CIPHER_CAP(crypto_params,
WLAN_CRYPTO_CAP_PMF_OFFLOAD)) {
if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) {
WLAN_CRYPTO_TX_OPS_SETKEY(psoc)(vdev,
key, macaddr, req_key->type);
}
}
wlan_crypto_set_mgmtcipher(crypto_params, req_key->type);
status = wlan_crypto_set_igtk_key(key);
return status;
} else if (IS_FILS_CIPHER(req_key->type)) {
/* Take request key object to FILS setkey */
key->private = req_key;
} else {
if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) {
WLAN_CRYPTO_TX_OPS_SETKEY(psoc)(vdev, key,
macaddr, req_key->type);
}
}
status = cipher->setkey(key);
if ((req_key->flags & WLAN_CRYPTO_KEY_DEFAULT) &&
(req_key->keyix != WLAN_CRYPTO_KEYIX_NONE) &&
(!IS_MGMT_CIPHER(req_key->type))) {
/* default xmit key */
wlan_crypto_default_key(vdev,
req_key->macaddr,
req_key->keyix,
!isbcast);
}
return status;
}
/**
* wlan_crypto_get_keytype - get keytype
* @key: key
*
* This function gets keytype from key
*
* Return: keytype
*/
wlan_crypto_cipher_type wlan_crypto_get_key_type(
struct wlan_crypto_key *key){
if (key && key->cipher_table) {
return ((struct wlan_crypto_cipher *)
(key->cipher_table))->cipher;
}
return WLAN_CRYPTO_CIPHER_NONE;
}
qdf_export_symbol(wlan_crypto_get_key_type);
/**
* wlan_crypto_vdev_getkey - get key from vdev
* @vdev: vdev
* @keyix: keyix
*
* This function gets key from vdev
*
* Return: key or NULL
*/
struct wlan_crypto_key *wlan_crypto_vdev_getkey(struct wlan_objmgr_vdev *vdev,
uint16_t keyix){
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_crypto_key *key = NULL;
crypto_params = wlan_crypto_vdev_get_comp_params(vdev, &crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return NULL;
}
/* for keyix 4,5 we return the igtk keys for keyix more than 5
* we return the default key, for all other keyix we return the
* key accordingly.
*/
if (keyix == WLAN_CRYPTO_KEYIX_NONE ||
keyix >= (WLAN_CRYPTO_MAXKEYIDX + WLAN_CRYPTO_MAXIGTKKEYIDX))
key = crypto_priv->key[crypto_priv->def_tx_keyid];
else if (keyix >= WLAN_CRYPTO_MAXKEYIDX)
key = crypto_priv->igtk_key[keyix - WLAN_CRYPTO_MAXKEYIDX];
else
key = crypto_priv->key[keyix];
if (key && key->valid)
return key;
return NULL;
}
qdf_export_symbol(wlan_crypto_vdev_getkey);
/**
* wlan_crypto_peer_getkey - get key from peer
* @peer: peer
* @keyix: keyix
*
* This function gets key from peer
*
* Return: key or NULL
*/
struct wlan_crypto_key *wlan_crypto_peer_getkey(struct wlan_objmgr_peer *peer,
uint16_t keyix){
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_crypto_key *key = NULL;
crypto_params = wlan_crypto_peer_get_comp_params(peer, &crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return NULL;
}
/* for keyix 4,5 we return the igtk keys for keyix more than 5
* we return the default key, for all other keyix we return the
* key accordingly.
*/
if (keyix == WLAN_CRYPTO_KEYIX_NONE ||
keyix >= (WLAN_CRYPTO_MAXKEYIDX + WLAN_CRYPTO_MAXIGTKKEYIDX))
key = crypto_priv->key[crypto_priv->def_tx_keyid];
else if (keyix >= WLAN_CRYPTO_MAXKEYIDX)
key = crypto_priv->igtk_key[keyix - WLAN_CRYPTO_MAXKEYIDX];
else
key = crypto_priv->key[keyix];
if (key && key->valid)
return key;
return NULL;
}
qdf_export_symbol(wlan_crypto_peer_getkey);
/**
* wlan_crypto_getkey - called by ucfg to get key
* @vdev: vdev
* @req_key: key value will be copied in this req_key
* @mac_address: mac address of the peer for unicast key
* or broadcast address if group key is requested.
*
* This function gets called from ucfg to get key
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_getkey(struct wlan_objmgr_vdev *vdev,
struct wlan_crypto_req_key *req_key,
uint8_t *mac_addr){
struct wlan_crypto_cipher *cipher_table;
struct wlan_crypto_key *key;
struct wlan_objmgr_psoc *psoc;
uint8_t macaddr[QDF_MAC_ADDR_SIZE] =
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
wlan_vdev_obj_lock(vdev);
qdf_mem_copy(macaddr, wlan_vdev_mlme_get_macaddr(vdev),
QDF_MAC_ADDR_SIZE);
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
wlan_vdev_obj_unlock(vdev);
crypto_err("psoc NULL");
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_unlock(vdev);
if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)mac_addr)) {
key = wlan_crypto_vdev_getkey(vdev, req_key->keyix);
if (!key)
return QDF_STATUS_E_INVAL;
} else {
struct wlan_objmgr_peer *peer;
uint8_t pdev_id;
pdev_id = wlan_objmgr_pdev_get_pdev_id(
wlan_vdev_get_pdev(vdev));
peer = wlan_objmgr_get_peer_by_mac_n_vdev(
psoc,
pdev_id,
macaddr,
mac_addr,
WLAN_CRYPTO_ID);
if (!peer) {
crypto_err("peer NULL");
return QDF_STATUS_E_NOENT;
}
key = wlan_crypto_peer_getkey(peer, req_key->keyix);
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
if (!key)
return QDF_STATUS_E_INVAL;
}
if (key->valid) {
qdf_mem_copy(req_key->keydata,
key->keyval, key->keylen);
qdf_mem_copy((uint8_t *)(&req_key->keytsc),
(uint8_t *)(&key->keytsc),
sizeof(req_key->keytsc));
qdf_mem_copy((uint8_t *)(&req_key->keyrsc),
(uint8_t *)(&key->keyrsc[0]),
sizeof(req_key->keyrsc));
req_key->keylen = key->keylen;
req_key->flags = key->flags;
cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
if (!cipher_table)
return QDF_STATUS_SUCCESS;
req_key->type = cipher_table->cipher;
if (req_key->type == WLAN_CRYPTO_CIPHER_WAPI_SMS4) {
qdf_mem_copy((uint8_t *)(&req_key->txiv),
(uint8_t *)(key->txiv),
sizeof(req_key->txiv));
qdf_mem_copy((uint8_t *)(&req_key->recviv),
(uint8_t *)(key->recviv),
sizeof(req_key->recviv));
}
}
return QDF_STATUS_SUCCESS;
}
/**
* wlan_crypto_delkey - called by ucfg to delete key
* @vdev: vdev
* @mac_address: mac address of the peer for unicast key
* or broadcast address if group key is deleted.
* @key_idx: key index to be deleted
*
* This function gets called from ucfg to delete key
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_delkey(struct wlan_objmgr_vdev *vdev,
uint8_t *macaddr,
uint8_t key_idx){
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_crypto_key *key;
struct wlan_crypto_cipher *cipher_table;
struct wlan_objmgr_psoc *psoc;
uint8_t bssid_mac[QDF_MAC_ADDR_SIZE];
if (!vdev || !macaddr ||
(key_idx >=
(WLAN_CRYPTO_MAXKEYIDX + WLAN_CRYPTO_MAXIGTKKEYIDX))) {
crypto_err("Invalid param vdev %pK macaddr %pK keyidx %d",
vdev, macaddr, key_idx);
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_lock(vdev);
qdf_mem_copy(bssid_mac, wlan_vdev_mlme_get_macaddr(vdev),
QDF_MAC_ADDR_SIZE);
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
wlan_vdev_obj_unlock(vdev);
crypto_err("psoc NULL");
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_unlock(vdev);
if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)macaddr)) {
crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
} else {
struct wlan_objmgr_peer *peer;
uint8_t pdev_id;
pdev_id = wlan_objmgr_pdev_get_pdev_id(
wlan_vdev_get_pdev(vdev));
peer = wlan_objmgr_get_peer_by_mac_n_vdev(
psoc, pdev_id,
bssid_mac,
macaddr,
WLAN_CRYPTO_ID);
if (!peer) {
return QDF_STATUS_E_INVAL;
}
crypto_params = wlan_crypto_peer_get_comp_params(peer,
&crypto_priv);
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
}
if (key_idx >= WLAN_CRYPTO_MAXKEYIDX) {
uint8_t igtk_idx = key_idx - WLAN_CRYPTO_MAXKEYIDX;
if (igtk_idx >= WLAN_CRYPTO_MAXIGTKKEYIDX) {
crypto_err("Igtk key invalid keyid %d", igtk_idx);
return QDF_STATUS_E_INVAL;
}
key = crypto_priv->igtk_key[igtk_idx];
crypto_priv->igtk_key[igtk_idx] = NULL;
if (key)
key->valid = 0;
} else {
key = crypto_priv->key[key_idx];
crypto_priv->key[key_idx] = NULL;
}
if (!key)
return QDF_STATUS_E_INVAL;
if (key->valid) {
cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
qdf_mem_zero(key->keyval, sizeof(key->keyval));
if (!IS_FILS_CIPHER(cipher_table->cipher) &&
WLAN_CRYPTO_TX_OPS_DELKEY(psoc)) {
WLAN_CRYPTO_TX_OPS_DELKEY(psoc)(vdev, key,
macaddr, cipher_table->cipher);
} else if (IS_FILS_CIPHER(cipher_table->cipher)) {
if (key->private)
qdf_mem_free(key->private);
}
}
qdf_mem_free(key);
return QDF_STATUS_SUCCESS;
}
#ifdef CRYPTO_SET_KEY_CONVERGED
static QDF_STATUS wlan_crypto_set_default_key(struct wlan_objmgr_vdev *vdev,
uint8_t key_idx, uint8_t *macaddr)
{
return QDF_STATUS_SUCCESS;
}
#else
static QDF_STATUS wlan_crypto_set_default_key(struct wlan_objmgr_vdev *vdev,
uint8_t key_idx, uint8_t *macaddr)
{
struct wlan_objmgr_psoc *psoc;
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
crypto_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
if (WLAN_CRYPTO_TX_OPS_DEFAULTKEY(psoc)) {
WLAN_CRYPTO_TX_OPS_DEFAULTKEY(psoc)(vdev, key_idx,
macaddr);
}
return QDF_STATUS_SUCCESS;
}
#endif
/**
* wlan_crypto_default_key - called by ucfg to set default tx key
* @vdev: vdev
* @mac_address: mac address of the peer for unicast key
* or broadcast address if group key need to made default.
* @key_idx: key index to be made as default key
* @unicast: is key was unicast or group key.
*
* This function gets called from ucfg to set default key
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_default_key(struct wlan_objmgr_vdev *vdev,
uint8_t *macaddr,
uint8_t key_idx,
bool unicast){
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_crypto_key *key;
struct wlan_objmgr_psoc *psoc;
uint8_t bssid_mac[QDF_MAC_ADDR_SIZE];
if (!vdev || !macaddr || (key_idx >= WLAN_CRYPTO_MAXKEYIDX)) {
crypto_err("Invalid param vdev %pK macaddr %pK keyidx %d",
vdev, macaddr, key_idx);
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_lock(vdev);
qdf_mem_copy(bssid_mac, wlan_vdev_mlme_get_macaddr(vdev),
QDF_MAC_ADDR_SIZE);
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
wlan_vdev_obj_unlock(vdev);
crypto_err("psoc NULL");
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_unlock(vdev);
if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)macaddr)) {
crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
key = crypto_priv->key[key_idx];
if (!key)
return QDF_STATUS_E_INVAL;
} else {
struct wlan_objmgr_peer *peer;
uint8_t pdev_id;
pdev_id = wlan_objmgr_pdev_get_pdev_id(
wlan_vdev_get_pdev(vdev));
peer = wlan_objmgr_get_peer_by_mac_n_vdev(
psoc, pdev_id,
bssid_mac,
macaddr,
WLAN_CRYPTO_ID);
if (!peer) {
crypto_err("peer NULL");
return QDF_STATUS_E_INVAL;
}
crypto_params = wlan_crypto_peer_get_comp_params(peer,
&crypto_priv);
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
key = crypto_priv->key[key_idx];
if (!key)
return QDF_STATUS_E_INVAL;
}
if (!key->valid)
return QDF_STATUS_E_INVAL;
if (wlan_crypto_set_default_key(vdev, key_idx, macaddr) !=
QDF_STATUS_SUCCESS)
return QDF_STATUS_E_INVAL;
crypto_priv->def_tx_keyid = key_idx;
return QDF_STATUS_SUCCESS;
}
/**
* wlan_crypto_encap - called by mgmt for encap the frame based on cipher
* @vdev: vdev
* @wbuf: wbuf
* @macaddr: macaddr
* @encapdone: is encapdone already or not.
*
* This function gets called from mgmt txrx to encap frame.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_encap(struct wlan_objmgr_vdev *vdev,
qdf_nbuf_t wbuf,
uint8_t *mac_addr,
uint8_t encapdone){
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_crypto_key *key;
QDF_STATUS status;
struct wlan_crypto_cipher *cipher_table;
struct wlan_objmgr_psoc *psoc;
struct wlan_objmgr_peer *peer;
uint8_t bssid_mac[QDF_MAC_ADDR_SIZE];
uint8_t pdev_id;
uint8_t hdrlen;
enum QDF_OPMODE opmode;
opmode = wlan_vdev_mlme_get_opmode(vdev);
wlan_vdev_obj_lock(vdev);
qdf_mem_copy(bssid_mac, wlan_vdev_mlme_get_macaddr(vdev),
QDF_MAC_ADDR_SIZE);
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
wlan_vdev_obj_unlock(vdev);
crypto_err("psoc NULL");
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_unlock(vdev);
pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev));
/* FILS Encap required only for (Re-)Assoc response */
peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, WLAN_CRYPTO_ID);
if (!wlan_crypto_is_data_protected((uint8_t *)qdf_nbuf_data(wbuf)) &&
peer && !wlan_crypto_get_peer_fils_aead(peer)) {
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
return QDF_STATUS_E_INVAL;
}
if (peer)
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
if (qdf_is_macaddr_group((struct qdf_mac_addr *)mac_addr)) {
crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
key = crypto_priv->key[crypto_priv->def_tx_keyid];
if (!key)
return QDF_STATUS_E_INVAL;
} else {
struct wlan_objmgr_peer *peer;
uint8_t pdev_id;
pdev_id = wlan_objmgr_pdev_get_pdev_id(
wlan_vdev_get_pdev(vdev));
peer = wlan_objmgr_get_peer_by_mac_n_vdev(psoc, pdev_id,
bssid_mac, mac_addr,
WLAN_CRYPTO_ID);
if (!peer) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
crypto_params = wlan_crypto_peer_get_comp_params(peer,
&crypto_priv);
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
key = crypto_priv->key[crypto_priv->def_tx_keyid];
if (!key)
return QDF_STATUS_E_INVAL;
}
if (opmode == QDF_MONITOR_MODE)
hdrlen = ieee80211_hdrsize((uint8_t *)qdf_nbuf_data(wbuf));
else
hdrlen = ieee80211_hdrspace(wlan_vdev_get_pdev(vdev),
(uint8_t *)qdf_nbuf_data(wbuf));
/* if tkip, is counter measures enabled, then drop the frame */
cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
status = cipher_table->encap(key, wbuf, encapdone,
hdrlen);
return status;
}
qdf_export_symbol(wlan_crypto_encap);
/**
* wlan_crypto_decap - called by mgmt for decap the frame based on cipher
* @vdev: vdev
* @wbuf: wbuf
* @macaddr: macaddr
* @tid: tid of the frame
*
* This function gets called from mgmt txrx to decap frame.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_decap(struct wlan_objmgr_vdev *vdev,
qdf_nbuf_t wbuf,
uint8_t *mac_addr,
uint8_t tid){
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_crypto_key *key;
QDF_STATUS status;
struct wlan_crypto_cipher *cipher_table;
struct wlan_objmgr_psoc *psoc;
struct wlan_objmgr_peer *peer;
uint8_t bssid_mac[QDF_MAC_ADDR_SIZE];
uint8_t keyid;
uint8_t pdev_id;
uint8_t hdrlen;
enum QDF_OPMODE opmode;
opmode = wlan_vdev_mlme_get_opmode(vdev);
wlan_vdev_obj_lock(vdev);
qdf_mem_copy(bssid_mac, wlan_vdev_mlme_get_macaddr(vdev),
QDF_MAC_ADDR_SIZE);
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
wlan_vdev_obj_unlock(vdev);
crypto_err("psoc NULL");
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_unlock(vdev);
if (opmode == QDF_MONITOR_MODE)
hdrlen = ieee80211_hdrsize((uint8_t *)qdf_nbuf_data(wbuf));
else
hdrlen = ieee80211_hdrspace(wlan_vdev_get_pdev(vdev),
(uint8_t *)qdf_nbuf_data(wbuf));
keyid = wlan_crypto_get_keyid((uint8_t *)qdf_nbuf_data(wbuf), hdrlen);
if (keyid >= WLAN_CRYPTO_MAXKEYIDX)
return QDF_STATUS_E_INVAL;
pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev));
/* FILS Decap required only for (Re-)Assoc request */
peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, WLAN_CRYPTO_ID);
if (!wlan_crypto_is_data_protected((uint8_t *)qdf_nbuf_data(wbuf)) &&
peer && !wlan_crypto_get_peer_fils_aead(peer)) {
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
return QDF_STATUS_E_INVAL;
}
if (peer)
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
if (qdf_is_macaddr_group((struct qdf_mac_addr *)mac_addr)) {
crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
key = crypto_priv->key[keyid];
if (!key)
return QDF_STATUS_E_INVAL;
} else {
struct wlan_objmgr_peer *peer;
uint8_t pdev_id;
pdev_id = wlan_objmgr_pdev_get_pdev_id(
wlan_vdev_get_pdev(vdev));
peer = wlan_objmgr_get_peer_by_mac_n_vdev(
psoc, pdev_id, bssid_mac,
mac_addr, WLAN_CRYPTO_ID);
if (!peer) {
crypto_err("peer NULL");
return QDF_STATUS_E_INVAL;
}
crypto_params = wlan_crypto_peer_get_comp_params(peer,
&crypto_priv);
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
key = crypto_priv->key[keyid];
if (!key)
return QDF_STATUS_E_INVAL;
}
/* if tkip, is counter measures enabled, then drop the frame */
cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
status = cipher_table->decap(key, wbuf, tid, hdrlen);
return status;
}
qdf_export_symbol(wlan_crypto_decap);
/**
* wlan_crypto_enmic - called by mgmt for adding mic in frame based on cipher
* @vdev: vdev
* @wbuf: wbuf
* @macaddr: macaddr
* @encapdone: is encapdone already or not.
*
* This function gets called from mgmt txrx to adding mic to the frame.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_enmic(struct wlan_objmgr_vdev *vdev,
qdf_nbuf_t wbuf,
uint8_t *mac_addr,
uint8_t encapdone){
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_crypto_key *key;
QDF_STATUS status;
struct wlan_crypto_cipher *cipher_table;
struct wlan_objmgr_psoc *psoc;
uint8_t bssid_mac[QDF_MAC_ADDR_SIZE];
uint8_t hdrlen;
enum QDF_OPMODE opmode;
opmode = wlan_vdev_mlme_get_opmode(vdev);
wlan_vdev_obj_lock(vdev);
qdf_mem_copy(bssid_mac, wlan_vdev_mlme_get_macaddr(vdev),
QDF_MAC_ADDR_SIZE);
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
wlan_vdev_obj_unlock(vdev);
crypto_err("psoc NULL");
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_unlock(vdev);
if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)mac_addr)) {
crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
key = crypto_priv->key[crypto_priv->def_tx_keyid];
if (!key)
return QDF_STATUS_E_INVAL;
} else {
struct wlan_objmgr_peer *peer;
uint8_t pdev_id;
pdev_id = wlan_objmgr_pdev_get_pdev_id(
wlan_vdev_get_pdev(vdev));
peer = wlan_objmgr_get_peer_by_mac_n_vdev(
psoc, pdev_id, bssid_mac,
mac_addr, WLAN_CRYPTO_ID);
if (!peer) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
crypto_params = wlan_crypto_peer_get_comp_params(peer,
&crypto_priv);
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
key = crypto_priv->key[crypto_priv->def_tx_keyid];
if (!key)
return QDF_STATUS_E_INVAL;
}
if (opmode == QDF_MONITOR_MODE)
hdrlen = ieee80211_hdrsize((uint8_t *)qdf_nbuf_data(wbuf));
else
hdrlen = ieee80211_hdrspace(wlan_vdev_get_pdev(vdev),
(uint8_t *)qdf_nbuf_data(wbuf));
/* if tkip, is counter measures enabled, then drop the frame */
cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
status = cipher_table->enmic(key, wbuf, encapdone, hdrlen);
return status;
}
/**
* wlan_crypto_demic - called by mgmt for remove and check mic for
* the frame based on cipher
* @vdev: vdev
* @wbuf: wbuf
* @macaddr: macaddr
* @tid: tid of the frame
* @keyid: keyid in the received frame
* This function gets called from mgmt txrx to decap frame.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_demic(struct wlan_objmgr_vdev *vdev,
qdf_nbuf_t wbuf,
uint8_t *mac_addr,
uint8_t tid,
uint8_t keyid){
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_crypto_key *key;
QDF_STATUS status;
struct wlan_crypto_cipher *cipher_table;
struct wlan_objmgr_psoc *psoc;
uint8_t bssid_mac[QDF_MAC_ADDR_SIZE];
uint8_t hdrlen;
enum QDF_OPMODE opmode;
opmode = wlan_vdev_mlme_get_opmode(vdev);
if (opmode == QDF_MONITOR_MODE)
hdrlen = ieee80211_hdrsize((uint8_t *)qdf_nbuf_data(wbuf));
else
hdrlen = ieee80211_hdrspace(wlan_vdev_get_pdev(vdev),
(uint8_t *)qdf_nbuf_data(wbuf));
wlan_vdev_obj_lock(vdev);
qdf_mem_copy(bssid_mac, wlan_vdev_mlme_get_macaddr(vdev),
QDF_MAC_ADDR_SIZE);
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
wlan_vdev_obj_unlock(vdev);
crypto_err("psoc NULL");
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_unlock(vdev);
if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)mac_addr)) {
crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
key = crypto_priv->key[keyid];
if (!key)
return QDF_STATUS_E_INVAL;
} else {
struct wlan_objmgr_peer *peer;
uint8_t pdev_id;
pdev_id = wlan_objmgr_pdev_get_pdev_id(
wlan_vdev_get_pdev(vdev));
peer = wlan_objmgr_get_peer_by_mac_n_vdev(
psoc, pdev_id, bssid_mac,
mac_addr, WLAN_CRYPTO_ID);
if (!peer) {
crypto_err("peer NULL");
return QDF_STATUS_E_INVAL;
}
crypto_params = wlan_crypto_peer_get_comp_params(peer,
&crypto_priv);
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
key = crypto_priv->key[keyid];
if (!key)
return QDF_STATUS_E_INVAL;
}
/* if tkip, is counter measures enabled, then drop the frame */
cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
status = cipher_table->demic(key, wbuf, tid, hdrlen);
return status;
}
/**
* wlan_crypto_vdev_is_pmf_enabled - called to check is pmf enabled in vdev
* @vdev: vdev
*
* This function gets called to check is pmf enabled or not in vdev.
*
* Return: true or false
*/
bool wlan_crypto_vdev_is_pmf_enabled(struct wlan_objmgr_vdev *vdev)
{
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *vdev_crypto_params;
if (!vdev)
return false;
vdev_crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
if ((vdev_crypto_params->rsn_caps &
WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)
|| (vdev_crypto_params->rsn_caps &
WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED)) {
return true;
}
return false;
}
/**
* wlan_crypto_vdev_is_pmf_required - called to check is pmf required in vdev
* @vdev: vdev
*
* This function gets called to check is pmf required or not in vdev.
*
* Return: true or false
*/
bool wlan_crypto_vdev_is_pmf_required(struct wlan_objmgr_vdev *vdev)
{
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *vdev_crypto_params;
if (!vdev)
return false;
vdev_crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
if (vdev_crypto_params->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED)
return true;
return false;
}
/**
* wlan_crypto_is_pmf_enabled - called by mgmt txrx to check is pmf enabled
* @vdev: vdev
* @peer: peer
*
* This function gets called by mgmt txrx to check is pmf enabled or not.
*
* Return: true or false
*/
bool wlan_crypto_is_pmf_enabled(struct wlan_objmgr_vdev *vdev,
struct wlan_objmgr_peer *peer){
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *vdev_crypto_params;
struct wlan_crypto_params *peer_crypto_params;
if (!vdev || !peer)
return false;
vdev_crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
peer_crypto_params = wlan_crypto_peer_get_comp_params(peer,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_INVAL;
}
if (((vdev_crypto_params->rsn_caps &
WLAN_CRYPTO_RSN_CAP_MFP_ENABLED) &&
(peer_crypto_params->rsn_caps &
WLAN_CRYPTO_RSN_CAP_MFP_ENABLED))
|| (vdev_crypto_params->rsn_caps &
WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED)) {
return true;
}
return false;
}
/**
* wlan_crypto_is_key_valid - called by mgmt txrx to check if key is valid
* @vdev: vdev
* @peer: peer
* @keyidx : key index
*
* This function gets called by mgmt txrx to check if key is valid
*
* Return: true or false
*/
bool wlan_crypto_is_key_valid(struct wlan_objmgr_vdev *vdev,
struct wlan_objmgr_peer *peer,
uint16_t keyidx)
{
struct wlan_crypto_key *key = NULL;
if (!vdev && !peer)
return false;
if (peer)
key = wlan_crypto_peer_getkey(peer, keyidx);
else if (vdev)
key = wlan_crypto_vdev_getkey(vdev, keyidx);
if ((key) && key->valid)
return true;
return false;
}
static void wlan_crypto_gmac_pn_swap(uint8_t *a, uint8_t *b)
{
a[0] = b[5];
a[1] = b[4];
a[2] = b[3];
a[3] = b[2];
a[4] = b[1];
a[5] = b[0];
}
/**
* wlan_crypto_add_mmie - called by mgmt txrx to add mmie in frame
* @vdev: vdev
* @bfrm: frame starting pointer
* @len: length of the frame
*
* This function gets called by mgmt txrx to add mmie in frame
*
* Return: end of frame or NULL in case failure
*/
uint8_t *wlan_crypto_add_mmie(struct wlan_objmgr_vdev *vdev,
uint8_t *bfrm,
uint32_t len) {
struct wlan_crypto_key *key;
struct wlan_crypto_mmie *mmie;
uint8_t *pn, *aad, *buf, *efrm, nounce[12];
struct wlan_frame_hdr *hdr;
uint32_t i, hdrlen, mic_len, aad_len;
uint8_t mic[16];
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
int32_t ret = -1;
if (!bfrm) {
crypto_err("frame is NULL");
return NULL;
}
crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return NULL;
}
if (crypto_priv->def_igtk_tx_keyid >= WLAN_CRYPTO_MAXIGTKKEYIDX) {
crypto_err("igtk key invalid keyid %d",
crypto_priv->def_igtk_tx_keyid);
return NULL;
}
key = crypto_priv->igtk_key[crypto_priv->def_igtk_tx_keyid];
if (!key) {
crypto_err("No igtk key present");
return NULL;
}
mic_len = (crypto_priv->igtk_key_type
== WLAN_CRYPTO_CIPHER_AES_CMAC) ? 8 : 16;
efrm = bfrm + len;
aad_len = 20;
hdrlen = sizeof(struct wlan_frame_hdr);
len += sizeof(struct wlan_crypto_mmie);
mmie = (struct wlan_crypto_mmie *) efrm;
qdf_mem_zero((unsigned char *)mmie, sizeof(*mmie));
mmie->element_id = WLAN_ELEMID_MMIE;
mmie->length = sizeof(*mmie) - 2;
mmie->key_id = qdf_cpu_to_le16(key->keyix);
mic_len = (crypto_priv->igtk_key_type
== WLAN_CRYPTO_CIPHER_AES_CMAC) ? 8 : 16;
if (mic_len == 8) {
mmie->length -= 8;
len -= 8;
}
/* PN = PN + 1 */
pn = (uint8_t *)&key->keytsc;
for (i = 0; i <= 5; i++) {
pn[i]++;
if (pn[i])
break;
}
/* Copy IPN */
qdf_mem_copy(mmie->sequence_number, pn, 6);
hdr = (struct wlan_frame_hdr *) bfrm;
buf = qdf_mem_malloc(len - hdrlen + 20);
if (!buf)
return NULL;
qdf_mem_zero(buf, len - hdrlen + 20);
aad = buf;
/* generate BIP AAD: FC(masked) || A1 || A2 || A3 */
/* FC type/subtype */
aad[0] = hdr->i_fc[0];
/* Mask FC Retry, PwrMgt, MoreData flags to zero */
aad[1] = (hdr->i_fc[1] & ~(WLAN_FC1_RETRY | WLAN_FC1_PWRMGT
| WLAN_FC1_MOREDATA));
/* A1 || A2 || A3 */
qdf_mem_copy(aad + 2, hdr->i_addr1, QDF_MAC_ADDR_SIZE);
qdf_mem_copy(aad + 8, hdr->i_addr2, QDF_MAC_ADDR_SIZE);
qdf_mem_copy(aad + 14, hdr->i_addr3, QDF_MAC_ADDR_SIZE);
qdf_mem_zero(mic, 16);
/*
* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64)
*/
qdf_mem_copy(buf + aad_len, bfrm + hdrlen, len - hdrlen);
if (crypto_priv->igtk_key_type == WLAN_CRYPTO_CIPHER_AES_CMAC) {
ret = omac1_aes_128(key->keyval, buf,
len + aad_len - hdrlen, mic);
qdf_mem_copy(mmie->mic, mic, 8);
} else if (crypto_priv->igtk_key_type
== WLAN_CRYPTO_CIPHER_AES_CMAC_256) {
ret = omac1_aes_256(key->keyval, buf,
len + aad_len - hdrlen, mmie->mic);
} else if ((crypto_priv->igtk_key_type == WLAN_CRYPTO_CIPHER_AES_GMAC)
|| (crypto_priv->igtk_key_type
== WLAN_CRYPTO_CIPHER_AES_GMAC_256)) {
qdf_mem_copy(nounce, hdr->i_addr2, QDF_MAC_ADDR_SIZE);
wlan_crypto_gmac_pn_swap(nounce + 6, pn);
ret = wlan_crypto_aes_gmac(key->keyval, key->keylen, nounce,
sizeof(nounce), buf,
len + aad_len - hdrlen, mmie->mic);
}
qdf_mem_free(buf);
if (ret < 0) {
crypto_err("add mmie failed");
return NULL;
}
return bfrm + len;
}
/**
* wlan_crypto_is_mmie_valid - called by mgmt txrx to check mmie of the frame
* @vdev: vdev
* @frm: frame starting pointer
* @efrm: end of frame pointer
*
* This function gets called by mgmt txrx to check mmie of the frame
*
* Return: true or false
*/
bool wlan_crypto_is_mmie_valid(struct wlan_objmgr_vdev *vdev,
uint8_t *frm,
uint8_t *efrm){
struct wlan_crypto_mmie *mmie = NULL;
uint8_t *ipn, *aad, *buf, mic[16], nounce[12];
struct wlan_crypto_key *key;
struct wlan_frame_hdr *hdr;
uint16_t mic_len, hdrlen, len;
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
uint8_t aad_len = 20;
int32_t ret = -1;
/* check if frame is illegal length */
if (!frm || !efrm || (efrm < frm)
|| ((efrm - frm) < sizeof(struct wlan_frame_hdr))) {
crypto_err("Invalid params");
return false;
}
len = efrm - frm;
crypto_priv = (struct wlan_crypto_comp_priv *)
wlan_get_vdev_crypto_obj(vdev);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return false;
}
crypto_params = &(crypto_priv->crypto_params);
mic_len = (crypto_priv->igtk_key_type
== WLAN_CRYPTO_CIPHER_AES_CMAC) ? 8 : 16;
hdrlen = sizeof(struct wlan_frame_hdr);
if (mic_len == 8)
mmie = (struct wlan_crypto_mmie *)(efrm - sizeof(*mmie) + 8);
else
mmie = (struct wlan_crypto_mmie *)(efrm - sizeof(*mmie));
/* check Elem ID*/
if ((!mmie) || (mmie->element_id != WLAN_ELEMID_MMIE)) {
crypto_err("IE is not MMIE");
return false;
}
if (mmie->key_id >= (WLAN_CRYPTO_MAXKEYIDX +
WLAN_CRYPTO_MAXIGTKKEYIDX) ||
(mmie->key_id < WLAN_CRYPTO_MAXKEYIDX)) {
crypto_err("keyid not valid");
return false;
}
key = crypto_priv->igtk_key[mmie->key_id - WLAN_CRYPTO_MAXKEYIDX];
if (!key) {
crypto_err("No igtk key present");
return false;
}
/* validate ipn */
ipn = mmie->sequence_number;
if (qdf_mem_cmp(ipn, key->keyrsc, 6) <= 0) {
uint8_t *su = (uint8_t *)key->keyrsc;
uint8_t *end = ipn + 6;
crypto_err("replay error :");
while (ipn < end) {
crypto_err("expected pn = %x received pn = %x",
*ipn++, *su++);
}
return false;
}
buf = qdf_mem_malloc(len - hdrlen + 20);
if (!buf)
return false;
aad = buf;
/* construct AAD */
hdr = (struct wlan_frame_hdr *)frm;
/* generate BIP AAD: FC(masked) || A1 || A2 || A3 */
/* FC type/subtype */
aad[0] = hdr->i_fc[0];
/* Mask FC Retry, PwrMgt, MoreData flags to zero */
aad[1] = (hdr->i_fc[1] & ~(WLAN_FC1_RETRY | WLAN_FC1_PWRMGT
| WLAN_FC1_MOREDATA));
/* A1 || A2 || A3 */
qdf_mem_copy(aad + 2, hdr->i_addr1, 3 * QDF_MAC_ADDR_SIZE);
/*
* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64)
*/
qdf_mem_copy(buf + 20, frm + hdrlen, len - hdrlen);
qdf_mem_zero(buf + (len - hdrlen + 20 - mic_len), mic_len);
qdf_mem_zero(mic, 16);
if (crypto_priv->igtk_key_type == WLAN_CRYPTO_CIPHER_AES_CMAC) {
ret = omac1_aes_128(key->keyval, buf,
len - hdrlen + aad_len, mic);
} else if (crypto_priv->igtk_key_type
== WLAN_CRYPTO_CIPHER_AES_CMAC_256) {
ret = omac1_aes_256(key->keyval, buf,
len + aad_len - hdrlen, mic);
} else if ((crypto_priv->igtk_key_type == WLAN_CRYPTO_CIPHER_AES_GMAC)
|| (crypto_priv->igtk_key_type
== WLAN_CRYPTO_CIPHER_AES_GMAC_256)) {
qdf_mem_copy(nounce, hdr->i_addr2, QDF_MAC_ADDR_SIZE);
wlan_crypto_gmac_pn_swap(nounce + 6, ipn);
ret = wlan_crypto_aes_gmac(key->keyval, key->keylen, nounce,
sizeof(nounce), buf,
len + aad_len - hdrlen, mic);
}
qdf_mem_free(buf);
if (ret < 0) {
crypto_err("genarate mmie failed");
return false;
}
if (qdf_mem_cmp(mic, mmie->mic, mic_len) != 0) {
crypto_err("mmie mismatch");
/* MMIE MIC mismatch */
return false;
}
/* Update the receive sequence number */
qdf_mem_copy(key->keyrsc, ipn, 6);
crypto_debug("mmie matched");
return true;
}
static int32_t wlan_crypto_wpa_cipher_to_suite(uint32_t cipher)
{
int32_t status = -1;
switch (cipher) {
case WLAN_CRYPTO_CIPHER_TKIP:
return WPA_CIPHER_SUITE_TKIP;
case WLAN_CRYPTO_CIPHER_AES_CCM:
return WPA_CIPHER_SUITE_CCMP;
case WLAN_CRYPTO_CIPHER_NONE:
return WPA_CIPHER_SUITE_NONE;
}
return status;
}
static int32_t wlan_crypto_rsn_cipher_to_suite(uint32_t cipher)
{
int32_t status = -1;
switch (cipher) {
case WLAN_CRYPTO_CIPHER_TKIP:
return RSN_CIPHER_SUITE_TKIP;
case WLAN_CRYPTO_CIPHER_AES_CCM:
return RSN_CIPHER_SUITE_CCMP;
case WLAN_CRYPTO_CIPHER_AES_CCM_256:
return RSN_CIPHER_SUITE_CCMP_256;
case WLAN_CRYPTO_CIPHER_AES_GCM:
return RSN_CIPHER_SUITE_GCMP;
case WLAN_CRYPTO_CIPHER_AES_GCM_256:
return RSN_CIPHER_SUITE_GCMP_256;
case WLAN_CRYPTO_CIPHER_AES_CMAC:
return RSN_CIPHER_SUITE_AES_CMAC;
case WLAN_CRYPTO_CIPHER_AES_CMAC_256:
return RSN_CIPHER_SUITE_BIP_CMAC_256;
case WLAN_CRYPTO_CIPHER_AES_GMAC:
return RSN_CIPHER_SUITE_BIP_GMAC_128;
case WLAN_CRYPTO_CIPHER_AES_GMAC_256:
return RSN_CIPHER_SUITE_BIP_GMAC_256;
case WLAN_CRYPTO_CIPHER_NONE:
return RSN_CIPHER_SUITE_NONE;
}
return status;
}
/*
* Convert an RSN key management/authentication algorithm
* to an internal code.
*/
static int32_t
wlan_crypto_rsn_keymgmt_to_suite(uint32_t keymgmt)
{
int32_t status = -1;
switch (keymgmt) {
case WLAN_CRYPTO_KEY_MGMT_NONE:
return RSN_AUTH_KEY_MGMT_NONE;
case WLAN_CRYPTO_KEY_MGMT_IEEE8021X:
return RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
case WLAN_CRYPTO_KEY_MGMT_PSK:
return RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
case WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X:
return RSN_AUTH_KEY_MGMT_FT_802_1X;
case WLAN_CRYPTO_KEY_MGMT_FT_PSK:
return RSN_AUTH_KEY_MGMT_FT_PSK;
case WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256:
return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
case WLAN_CRYPTO_KEY_MGMT_PSK_SHA256:
return RSN_AUTH_KEY_MGMT_PSK_SHA256;
case WLAN_CRYPTO_KEY_MGMT_SAE:
return RSN_AUTH_KEY_MGMT_SAE;
case WLAN_CRYPTO_KEY_MGMT_FT_SAE:
return RSN_AUTH_KEY_MGMT_FT_SAE;
case WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B:
return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
case WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192:
return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
case WLAN_CRYPTO_KEY_MGMT_CCKM:
return RSN_AUTH_KEY_MGMT_CCKM;
case WLAN_CRYPTO_KEY_MGMT_OSEN:
return RSN_AUTH_KEY_MGMT_OSEN;
case WLAN_CRYPTO_KEY_MGMT_FILS_SHA256:
return RSN_AUTH_KEY_MGMT_FILS_SHA256;
case WLAN_CRYPTO_KEY_MGMT_FILS_SHA384:
return RSN_AUTH_KEY_MGMT_FILS_SHA384;
case WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256:
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
case WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384:
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
case WLAN_CRYPTO_KEY_MGMT_OWE:
return RSN_AUTH_KEY_MGMT_OWE;
case WLAN_CRYPTO_KEY_MGMT_DPP:
return RSN_AUTH_KEY_MGMT_DPP;
}
return status;
}
/*
* Convert an RSN key management/authentication algorithm
* to an internal code.
*/
static int32_t
wlan_crypto_wpa_keymgmt_to_suite(uint32_t keymgmt)
{
int32_t status = -1;
switch (keymgmt) {
case WLAN_CRYPTO_KEY_MGMT_NONE:
return WPA_AUTH_KEY_MGMT_NONE;
case WLAN_CRYPTO_KEY_MGMT_IEEE8021X:
return WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
case WLAN_CRYPTO_KEY_MGMT_PSK:
return WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
case WLAN_CRYPTO_KEY_MGMT_CCKM:
return WPA_AUTH_KEY_MGMT_CCKM;
}
return status;
}
/**
* Convert a WPA cipher selector OUI to an internal
* cipher algorithm. Where appropriate we also
* record any key length.
*/
static int32_t wlan_crypto_wpa_suite_to_cipher(uint8_t *sel)
{
uint32_t w = LE_READ_4(sel);
int32_t status = -1;
switch (w) {
case WPA_CIPHER_SUITE_TKIP:
return WLAN_CRYPTO_CIPHER_TKIP;
case WPA_CIPHER_SUITE_CCMP:
return WLAN_CRYPTO_CIPHER_AES_CCM;
case WPA_CIPHER_SUITE_NONE:
return WLAN_CRYPTO_CIPHER_NONE;
}
return status;
}
/*
* Convert a WPA key management/authentication algorithm
* to an internal code.
*/
static int32_t wlan_crypto_wpa_suite_to_keymgmt(uint8_t *sel)
{
uint32_t w = LE_READ_4(sel);
int32_t status = -1;
switch (w) {
case WPA_AUTH_KEY_MGMT_UNSPEC_802_1X:
return WLAN_CRYPTO_KEY_MGMT_IEEE8021X;
case WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X:
return WLAN_CRYPTO_KEY_MGMT_PSK;
case WPA_AUTH_KEY_MGMT_CCKM:
return WLAN_CRYPTO_KEY_MGMT_CCKM;
case WPA_AUTH_KEY_MGMT_NONE:
return WLAN_CRYPTO_KEY_MGMT_NONE;
}
return status;
}
/*
* Convert a RSN cipher selector OUI to an internal
* cipher algorithm. Where appropriate we also
* record any key length.
*/
static int32_t wlan_crypto_rsn_suite_to_cipher(uint8_t *sel)
{
uint32_t w = LE_READ_4(sel);
int32_t status = -1;
switch (w) {
case RSN_CIPHER_SUITE_TKIP:
return WLAN_CRYPTO_CIPHER_TKIP;
case RSN_CIPHER_SUITE_CCMP:
return WLAN_CRYPTO_CIPHER_AES_CCM;
case RSN_CIPHER_SUITE_CCMP_256:
return WLAN_CRYPTO_CIPHER_AES_CCM_256;
case RSN_CIPHER_SUITE_GCMP:
return WLAN_CRYPTO_CIPHER_AES_GCM;
case RSN_CIPHER_SUITE_GCMP_256:
return WLAN_CRYPTO_CIPHER_AES_GCM_256;
case RSN_CIPHER_SUITE_AES_CMAC:
return WLAN_CRYPTO_CIPHER_AES_CMAC;
case RSN_CIPHER_SUITE_BIP_CMAC_256:
return WLAN_CRYPTO_CIPHER_AES_CMAC_256;
case RSN_CIPHER_SUITE_BIP_GMAC_128:
return WLAN_CRYPTO_CIPHER_AES_GMAC;
case RSN_CIPHER_SUITE_BIP_GMAC_256:
return WLAN_CRYPTO_CIPHER_AES_GMAC_256;
case RSN_CIPHER_SUITE_NONE:
return WLAN_CRYPTO_CIPHER_NONE;
}
return status;
}
/*
* Convert an RSN key management/authentication algorithm
* to an internal code.
*/
static int32_t wlan_crypto_rsn_suite_to_keymgmt(uint8_t *sel)
{
uint32_t w = LE_READ_4(sel);
int32_t status = -1;
switch (w) {
case RSN_AUTH_KEY_MGMT_UNSPEC_802_1X:
return WLAN_CRYPTO_KEY_MGMT_IEEE8021X;
case RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X:
return WLAN_CRYPTO_KEY_MGMT_PSK;
case RSN_AUTH_KEY_MGMT_FT_802_1X:
return WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X;
case RSN_AUTH_KEY_MGMT_FT_PSK:
return WLAN_CRYPTO_KEY_MGMT_FT_PSK;
case RSN_AUTH_KEY_MGMT_802_1X_SHA256:
return WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256;
case RSN_AUTH_KEY_MGMT_PSK_SHA256:
return WLAN_CRYPTO_KEY_MGMT_PSK_SHA256;
case RSN_AUTH_KEY_MGMT_SAE:
return WLAN_CRYPTO_KEY_MGMT_SAE;
case RSN_AUTH_KEY_MGMT_FT_SAE:
return WLAN_CRYPTO_KEY_MGMT_FT_SAE;
case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B:
return WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B;
case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192:
return WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192;
case RSN_AUTH_KEY_MGMT_CCKM:
return WLAN_CRYPTO_KEY_MGMT_CCKM;
case RSN_AUTH_KEY_MGMT_OSEN:
return WLAN_CRYPTO_KEY_MGMT_OSEN;
case RSN_AUTH_KEY_MGMT_FILS_SHA256:
return WLAN_CRYPTO_KEY_MGMT_FILS_SHA256;
case RSN_AUTH_KEY_MGMT_FILS_SHA384:
return WLAN_CRYPTO_KEY_MGMT_FILS_SHA384;
case RSN_AUTH_KEY_MGMT_FT_FILS_SHA256:
return WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256;
case RSN_AUTH_KEY_MGMT_FT_FILS_SHA384:
return WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384;
case RSN_AUTH_KEY_MGMT_OWE:
return WLAN_CRYPTO_KEY_MGMT_OWE;
case RSN_AUTH_KEY_MGMT_DPP:
return WLAN_CRYPTO_KEY_MGMT_DPP;
case RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_384:
return WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384;
}
return status;
}
/**
* wlan_crypto_wpaie_check - called by mlme to check the wpaie
* @crypto params: crypto params
* @iebuf: ie buffer
*
* This function gets called by mlme to check the contents of wpa is
* matching with given crypto params
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_wpaie_check(struct wlan_crypto_params *crypto_params,
uint8_t *frm){
uint8_t len = frm[1];
int32_t w;
int n;
/*
* Check the length once for fixed parts: OUI, type,
* version, mcast cipher, and 2 selector counts.
* Other, variable-length data, must be checked separately.
*/
RESET_AUTHMODE(crypto_params);
SET_AUTHMODE(crypto_params, WLAN_CRYPTO_AUTH_WPA);
if (len < 14)
return QDF_STATUS_E_INVAL;
frm += 6, len -= 4;
w = LE_READ_2(frm);
if (w != WPA_VERSION)
return QDF_STATUS_E_INVAL;
frm += 2, len -= 2;
/* multicast/group cipher */
RESET_MCAST_CIPHERS(crypto_params);
w = wlan_crypto_wpa_suite_to_cipher(frm);
if (w < 0)
return QDF_STATUS_E_INVAL;
SET_MCAST_CIPHER(crypto_params, w);
frm += 4, len -= 4;
/* unicast ciphers */
n = LE_READ_2(frm);
frm += 2, len -= 2;
if (len < n*4+2)
return QDF_STATUS_E_INVAL;
RESET_UCAST_CIPHERS(crypto_params);
for (; n > 0; n--) {
w = wlan_crypto_wpa_suite_to_cipher(frm);
if (w < 0)
return QDF_STATUS_E_INVAL;
SET_UCAST_CIPHER(crypto_params, w);
frm += 4, len -= 4;
}
if (!crypto_params->ucastcipherset)
return QDF_STATUS_E_INVAL;
/* key management algorithms */
n = LE_READ_2(frm);
frm += 2, len -= 2;
if (len < n*4)
return QDF_STATUS_E_INVAL;
w = 0;
RESET_KEY_MGMT(crypto_params);
for (; n > 0; n--) {
w = wlan_crypto_wpa_suite_to_keymgmt(frm);
if (w < 0)
return QDF_STATUS_E_INVAL;
SET_KEY_MGMT(crypto_params, w);
frm += 4, len -= 4;
}
/* optional capabilities */
if (len >= 2) {
crypto_params->rsn_caps = LE_READ_2(frm);
frm += 2, len -= 2;
}
return 0;
}
/**
* wlan_crypto_rsnie_check - called by mlme to check the rsnie
* @crypto params: crypto params
* @iebuf: ie buffer
*
* This function gets called by mlme to check the contents of wpa is
* matching with given crypto params
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_rsnie_check(struct wlan_crypto_params *crypto_params,
uint8_t *frm){
uint8_t len = frm[1];
int32_t w;
int n;
/* Check the length once for fixed parts: OUI, type & version */
if (len < 2)
return QDF_STATUS_E_INVAL;
/* initialize crypto params */
qdf_mem_zero(crypto_params, sizeof(struct wlan_crypto_params));
SET_AUTHMODE(crypto_params, WLAN_CRYPTO_AUTH_RSNA);
frm += 2;
/* NB: iswapoui already validated the OUI and type */
w = LE_READ_2(frm);
if (w != RSN_VERSION)
return QDF_STATUS_E_INVAL;
frm += 2, len -= 2;
if (!len) {
/* set defaults */
/* default group cipher CCMP-128 */
SET_MCAST_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CCM);
/* default ucast cipher CCMP-128 */
SET_UCAST_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CCM);
/* default key mgmt 8021x */
SET_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_IEEE8021X);
return QDF_STATUS_SUCCESS;
} else if (len < 4) {
return QDF_STATUS_E_INVAL;
}
/* multicast/group cipher */
w = wlan_crypto_rsn_suite_to_cipher(frm);
if (w < 0)
return QDF_STATUS_E_INVAL;
else {
SET_MCAST_CIPHER(crypto_params, w);
frm += 4, len -= 4;
}
if (crypto_params->mcastcipherset == 0)
return QDF_STATUS_E_INVAL;
if (!len) {
/* default ucast cipher CCMP-128 */
SET_UCAST_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CCM);
/* default key mgmt 8021x */
SET_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_IEEE8021X);
return QDF_STATUS_SUCCESS;
} else if (len < 2) {
return QDF_STATUS_E_INVAL;
}
/* unicast ciphers */
n = LE_READ_2(frm);
frm += 2, len -= 2;
if (n) {
if (len < n * 4)
return QDF_STATUS_E_INVAL;
for (; n > 0; n--) {
w = wlan_crypto_rsn_suite_to_cipher(frm);
if (w < 0)
return QDF_STATUS_E_INVAL;
SET_UCAST_CIPHER(crypto_params, w);
frm += 4, len -= 4;
}
} else {
/* default ucast cipher CCMP-128 */
SET_UCAST_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CCM);
}
if (crypto_params->ucastcipherset == 0)
return QDF_STATUS_E_INVAL;
if (!len) {
/* default key mgmt 8021x */
SET_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_IEEE8021X);
return QDF_STATUS_SUCCESS;
} else if (len < 2) {
return QDF_STATUS_E_INVAL;
}
/* key management algorithms */
n = LE_READ_2(frm);
frm += 2, len -= 2;
if (n) {
if (len < n * 4)
return QDF_STATUS_E_INVAL;
for (; n > 0; n--) {
w = wlan_crypto_rsn_suite_to_keymgmt(frm);
if (w < 0)
return QDF_STATUS_E_INVAL;
SET_KEY_MGMT(crypto_params, w);
frm += 4, len -= 4;
}
} else {
/* default key mgmt 8021x */
SET_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_IEEE8021X);
}
if (crypto_params->key_mgmt == 0)
return QDF_STATUS_E_INVAL;
/* optional capabilities */
if (len >= 2) {
crypto_params->rsn_caps = LE_READ_2(frm);
frm += 2, len -= 2;
} else if (len && len < 2) {
return QDF_STATUS_E_INVAL;
}
/* PMKID */
if (len >= 2) {
n = LE_READ_2(frm);
frm += 2, len -= 2;
if (n && len) {
if (len >= n * PMKID_LEN)
frm += (n * PMKID_LEN), len -= (n * PMKID_LEN);
else
return QDF_STATUS_E_INVAL;
} else if (n && !len) {
return QDF_STATUS_E_INVAL;
}
/*TODO: Save pmkid in params for further reference */
}
/* BIP */
if (!len &&
(crypto_params->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) {
/* when no BIP mentioned and MFP capable use CMAC as default*/
SET_MGMT_CIPHER(crypto_params, WLAN_CRYPTO_CIPHER_AES_CMAC);
return QDF_STATUS_SUCCESS;
} else if (len >= 4) {
w = wlan_crypto_rsn_suite_to_cipher(frm);
frm += 4, len -= 4;
SET_MGMT_CIPHER(crypto_params, w);
}
return QDF_STATUS_SUCCESS;
}
/**
* wlan_crypto_build_wpaie - called by mlme to build wpaie
* @vdev: vdev
* @iebuf: ie buffer
*
* This function gets called by mlme to build wpaie from given vdev
*
* Return: end of buffer
*/
uint8_t *wlan_crypto_build_wpaie(struct wlan_objmgr_vdev *vdev,
uint8_t *iebuf){
uint8_t *frm = iebuf;
uint8_t *selcnt;
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
if (!frm)
return NULL;
crypto_params = wlan_crypto_vdev_get_comp_params(vdev, &crypto_priv);
if (!crypto_params)
return NULL;
*frm++ = WLAN_ELEMID_VENDOR;
*frm++ = 0;
WLAN_CRYPTO_ADDSELECTOR(frm, WPA_TYPE_OUI);
WLAN_CRYPTO_ADDSHORT(frm, WPA_VERSION);
/* multicast cipher */
if (MCIPHER_IS_TKIP(crypto_params))
WPA_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_TKIP);
else if (MCIPHER_IS_CCMP128(crypto_params))
WPA_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_AES_CCM);
/* unicast cipher list */
selcnt = frm;
WLAN_CRYPTO_ADDSHORT(frm, 0);
/* do not use CCMP unicast cipher in WPA mode */
if (UCIPHER_IS_CCMP128(crypto_params)) {
selcnt[0]++;
WPA_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_AES_CCM);
}
if (UCIPHER_IS_TKIP(crypto_params)) {
selcnt[0]++;
WPA_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_TKIP);
}
/* authenticator selector list */
selcnt = frm;
WLAN_CRYPTO_ADDSHORT(frm, 0);
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) {
selcnt[0]++;
WPA_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X);
} else if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_PSK)) {
selcnt[0]++;
WPA_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_PSK);
} else if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_CCKM)) {
selcnt[0]++;
WPA_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_CCKM);
} else {
selcnt[0]++;
WPA_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_NONE);
}
/* optional capabilities */
if (crypto_params->rsn_caps != 0 &&
crypto_params->rsn_caps != WLAN_CRYPTO_RSN_CAP_PREAUTH) {
WLAN_CRYPTO_ADDSHORT(frm, crypto_params->rsn_caps);
}
/* calculate element length */
iebuf[1] = frm - iebuf - 2;
return frm;
}
/**
* 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,
struct qdf_mac_addr *bssid)
{
uint8_t *frm = iebuf;
uint8_t *selcnt;
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
if (!frm) {
return NULL;
}
crypto_params = wlan_crypto_vdev_get_comp_params(vdev, &crypto_priv);
if (!crypto_params) {
return NULL;
}
*frm++ = WLAN_ELEMID_RSN;
*frm++ = 0;
WLAN_CRYPTO_ADDSHORT(frm, RSN_VERSION);
/* multicast cipher */
if (MCIPHER_IS_TKIP(crypto_params))
RSN_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_TKIP);
else if (MCIPHER_IS_CCMP128(crypto_params))
RSN_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_AES_CCM);
else if (MCIPHER_IS_CCMP256(crypto_params))
RSN_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_AES_CCM_256);
else if (MCIPHER_IS_GCMP128(crypto_params))
RSN_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_AES_GCM);
else if (MCIPHER_IS_GCMP256(crypto_params))
RSN_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_AES_GCM_256);
/* unicast cipher list */
selcnt = frm;
WLAN_CRYPTO_ADDSHORT(frm, 0);
if (UCIPHER_IS_CCMP256(crypto_params)) {
selcnt[0]++;
RSN_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_AES_CCM_256);
}
if (UCIPHER_IS_GCMP256(crypto_params)) {
selcnt[0]++;
RSN_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_AES_GCM_256);
}
if (UCIPHER_IS_CCMP128(crypto_params)) {
selcnt[0]++;
RSN_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_AES_CCM);
}
if (UCIPHER_IS_GCMP128(crypto_params)) {
selcnt[0]++;
RSN_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_AES_GCM);
}
if (UCIPHER_IS_TKIP(crypto_params)) {
selcnt[0]++;
RSN_ADD_CIPHER_TO_SUITE(frm, WLAN_CRYPTO_CIPHER_TKIP);
}
/* authenticator selector list */
selcnt = frm;
WLAN_CRYPTO_ADDSHORT(frm, 0);
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_CCKM)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_CCKM);
/* Other key mgmt should not be added after CCKM */
goto add_rsn_caps;
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_PSK)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_PSK);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm,
WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_FT_PSK)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_FT_PSK);
}
if (HAS_KEY_MGMT(crypto_params,
WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm,
WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_SAE)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_SAE);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_FT_SAE)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_FT_SAE);
}
if (HAS_KEY_MGMT(crypto_params,
WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B)) {
uint32_t kmgmt = WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B;
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, kmgmt);
}
if (HAS_KEY_MGMT(crypto_params,
WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192)) {
uint32_t kmgmt = WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192;
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, kmgmt);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm,
WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm,
WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_OWE)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_OWE);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_DPP)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_DPP);
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_OSEN)) {
selcnt[0]++;
RSN_ADD_KEYMGMT_TO_SUITE(frm, WLAN_CRYPTO_KEY_MGMT_OSEN);
}
add_rsn_caps:
WLAN_CRYPTO_ADDSHORT(frm, crypto_params->rsn_caps);
/* optional capabilities */
if (crypto_params->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED) {
/* 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);
}
} else
WLAN_CRYPTO_ADDSHORT(frm, 0);
if (HAS_MGMT_CIPHER(crypto_params,
WLAN_CRYPTO_CIPHER_AES_CMAC)) {
RSN_ADD_CIPHER_TO_SUITE(frm,
WLAN_CRYPTO_CIPHER_AES_CMAC);
}
if (HAS_MGMT_CIPHER(crypto_params,
WLAN_CRYPTO_CIPHER_AES_GMAC)) {
RSN_ADD_CIPHER_TO_SUITE(frm,
WLAN_CRYPTO_CIPHER_AES_GMAC);
}
if (HAS_MGMT_CIPHER(crypto_params,
WLAN_CRYPTO_CIPHER_AES_CMAC_256)) {
RSN_ADD_CIPHER_TO_SUITE(frm,
WLAN_CRYPTO_CIPHER_AES_CMAC_256
);
}
if (HAS_MGMT_CIPHER(crypto_params,
WLAN_CRYPTO_CIPHER_AES_GMAC_256)) {
RSN_ADD_CIPHER_TO_SUITE(frm,
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 */
iebuf[1] = frm - iebuf - 2;
return frm;
}
bool wlan_crypto_rsn_info(struct wlan_objmgr_vdev *vdev,
struct wlan_crypto_params *crypto_params){
struct wlan_crypto_params *my_crypto_params;
my_crypto_params = wlan_crypto_vdev_get_crypto_params(vdev);
if (!my_crypto_params) {
crypto_debug("vdev crypto params is NULL");
return false;
}
/*
* Check peer's pairwise ciphers.
* At least one must match with our unicast cipher
*/
if (!UCAST_CIPHER_MATCH(crypto_params, my_crypto_params)) {
crypto_debug("Unicast cipher match failed");
return false;
}
/*
* Check peer's group cipher is our enabled multicast cipher.
*/
if (!MCAST_CIPHER_MATCH(crypto_params, my_crypto_params)) {
crypto_debug("Multicast cipher match failed");
return false;
}
/*
* Check peer's key management class set (PSK or UNSPEC)
*/
if (!KEY_MGMTSET_MATCH(crypto_params, my_crypto_params)) {
crypto_debug("Key mgmt match failed");
return false;
}
if (wlan_crypto_vdev_is_pmf_required(vdev) &&
!(crypto_params->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) {
crypto_debug("Peer is not PMF capable");
return false;
}
if (!wlan_crypto_vdev_is_pmf_enabled(vdev) &&
(crypto_params->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED)) {
crypto_debug("Peer needs PMF, but vdev is not capable");
return false;
}
return true;
}
/*
* Convert an WAPI CIPHER suite to to an internal code.
*/
static int32_t wlan_crypto_wapi_suite_to_cipher(uint8_t *sel)
{
uint32_t w = LE_READ_4(sel);
int32_t status = -1;
switch (w) {
case (WLAN_WAPI_SEL(WLAN_CRYPTO_WAPI_SMS4_CIPHER)):
return WLAN_CRYPTO_CIPHER_WAPI_SMS4;
}
return status;
}
/*
* Convert an WAPI key management/authentication algorithm
* to an internal code.
*/
static int32_t wlan_crypto_wapi_keymgmt(u_int8_t *sel)
{
uint32_t w = LE_READ_4(sel);
int32_t status = -1;
switch (w) {
case (WLAN_WAPI_SEL(WLAN_WAI_PSK)):
return WLAN_CRYPTO_KEY_MGMT_WAPI_PSK;
case (WLAN_WAPI_SEL(WLAN_WAI_CERT_OR_SMS4)):
return WLAN_CRYPTO_KEY_MGMT_WAPI_CERT;
}
return status;
}
/**
* wlan_crypto_wapiie_check - called by mlme to check the wapiie
* @crypto params: crypto params
* @iebuf: ie buffer
*
* This function gets called by mlme to check the contents of wapi is
* matching with given crypto params
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
QDF_STATUS wlan_crypto_wapiie_check(struct wlan_crypto_params *crypto_params,
uint8_t *frm)
{
uint8_t len = frm[1];
int32_t w;
int n;
/*
* Check the length once for fixed parts: OUI, type,
* version, mcast cipher, and 2 selector counts.
* Other, variable-length data, must be checked separately.
*/
RESET_AUTHMODE(crypto_params);
SET_AUTHMODE(crypto_params, WLAN_CRYPTO_AUTH_WAPI);
if (len < WLAN_CRYPTO_WAPI_IE_LEN)
return QDF_STATUS_E_INVAL;
frm += 2;
w = LE_READ_2(frm);
frm += 2, len -= 2;
if (w != WAPI_VERSION)
return QDF_STATUS_E_INVAL;
n = LE_READ_2(frm);
frm += 2, len -= 2;
if (len < n*4+2)
return QDF_STATUS_E_INVAL;
RESET_KEY_MGMT(crypto_params);
for (; n > 0; n--) {
w = wlan_crypto_wapi_keymgmt(frm);
if (w < 0)
return QDF_STATUS_E_INVAL;
SET_KEY_MGMT(crypto_params, w);
frm += 4, len -= 4;
}
/* unicast ciphers */
n = LE_READ_2(frm);
frm += 2, len -= 2;
if (len < n*4+2)
return QDF_STATUS_E_INVAL;
RESET_UCAST_CIPHERS(crypto_params);
for (; n > 0; n--) {
w = wlan_crypto_wapi_suite_to_cipher(frm);
if (w < 0)
return QDF_STATUS_E_INVAL;
SET_UCAST_CIPHER(crypto_params, w);
frm += 4, len -= 4;
}
if (!crypto_params->ucastcipherset)
return QDF_STATUS_E_INVAL;
/* multicast/group cipher */
RESET_MCAST_CIPHERS(crypto_params);
w = wlan_crypto_wapi_suite_to_cipher(frm);
if (w < 0)
return QDF_STATUS_E_INVAL;
SET_MCAST_CIPHER(crypto_params, w);
frm += 4, len -= 4;
return QDF_STATUS_SUCCESS;
}
/**
* wlan_crypto_build_wapiie - called by mlme to build wapi ie
* @vdev: vdev
* @iebuf: ie buffer
*
* This function gets called by mlme to build wapi ie from given vdev
*
* Return: end of buffer
*/
uint8_t *wlan_crypto_build_wapiie(struct wlan_objmgr_vdev *vdev,
uint8_t *iebuf)
{
uint8_t *frm;
uint8_t *selcnt;
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
frm = iebuf;
if (!frm) {
crypto_err("ie buffer NULL");
return NULL;
}
crypto_params = wlan_crypto_vdev_get_comp_params(vdev, &crypto_priv);
if (!crypto_params) {
crypto_err("crypto_params NULL");
return NULL;
}
*frm++ = WLAN_ELEMID_WAPI;
*frm++ = 0;
WLAN_CRYPTO_ADDSHORT(frm, WAPI_VERSION);
/* authenticator selector list */
selcnt = frm;
WLAN_CRYPTO_ADDSHORT(frm, 0);
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_WAPI_PSK)) {
selcnt[0]++;
WLAN_CRYPTO_ADDSELECTOR(frm,
WLAN_WAPI_SEL(WLAN_WAI_PSK));
}
if (HAS_KEY_MGMT(crypto_params, WLAN_CRYPTO_KEY_MGMT_WAPI_CERT)) {
selcnt[0]++;
WLAN_CRYPTO_ADDSELECTOR(frm,
WLAN_WAPI_SEL(WLAN_WAI_CERT_OR_SMS4));
}
/* unicast cipher list */
selcnt = frm;
WLAN_CRYPTO_ADDSHORT(frm, 0);
if (UCIPHER_IS_SMS4(crypto_params)) {
selcnt[0]++;
WLAN_CRYPTO_ADDSELECTOR(frm,
WLAN_WAPI_SEL(WLAN_CRYPTO_WAPI_SMS4_CIPHER));
}
WLAN_CRYPTO_ADDSELECTOR(frm,
WLAN_WAPI_SEL(WLAN_CRYPTO_WAPI_SMS4_CIPHER));
/* optional capabilities */
WLAN_CRYPTO_ADDSHORT(frm, crypto_params->rsn_caps);
/* bkid count */
if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE ||
vdev->vdev_mlme.vdev_opmode == QDF_P2P_CLIENT_MODE)
WLAN_CRYPTO_ADDSHORT(frm, 0);
/* calculate element length */
iebuf[1] = frm - iebuf - 2;
return frm;
}
/**
* wlan_crypto_pn_check - called by data patch for PN check
* @vdev: vdev
* @wbuf: wbuf
*
* This function gets called by data patch for PN check
*
* Return: QDF_STATUS
*/
QDF_STATUS wlan_crypto_pn_check(struct wlan_objmgr_vdev *vdev,
qdf_nbuf_t wbuf){
/* Need to check is there real requirement for this function
* as PN check is already handled in decap function.
*/
return QDF_STATUS_SUCCESS;
}
/**
* wlan_crypto_vdev_get_crypto_params - called by mlme to get crypto params
* @vdev:vdev
*
* This function gets called by mlme to get crypto params
*
* Return: wlan_crypto_params or NULL in case of failure
*/
struct wlan_crypto_params *wlan_crypto_vdev_get_crypto_params(
struct wlan_objmgr_vdev *vdev){
struct wlan_crypto_comp_priv *crypto_priv;
return wlan_crypto_vdev_get_comp_params(vdev, &crypto_priv);
}
/**
* wlan_crypto_peer_get_crypto_params - called by mlme to get crypto params
* @peer:peer
*
* This function gets called by mlme to get crypto params
*
* Return: wlan_crypto_params or NULL in case of failure
*/
struct wlan_crypto_params *wlan_crypto_peer_get_crypto_params(
struct wlan_objmgr_peer *peer){
struct wlan_crypto_comp_priv *crypto_priv;
return wlan_crypto_peer_get_comp_params(peer, &crypto_priv);
}
QDF_STATUS wlan_crypto_set_peer_wep_keys(struct wlan_objmgr_vdev *vdev,
struct wlan_objmgr_peer *peer)
{
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_comp_priv *sta_crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_crypto_key *key;
struct wlan_crypto_key *sta_key;
struct wlan_crypto_cipher *cipher_table;
struct wlan_objmgr_psoc *psoc;
uint8_t *mac_addr;
int i;
enum QDF_OPMODE opmode;
QDF_STATUS status = QDF_STATUS_SUCCESS;
if (!vdev)
return QDF_STATUS_E_NULL_VALUE;
if (!peer) {
crypto_debug("peer NULL");
return QDF_STATUS_E_INVAL;
}
opmode = wlan_vdev_mlme_get_opmode(vdev);
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
crypto_err("psoc NULL");
return QDF_STATUS_E_NULL_VALUE;
}
wlan_peer_obj_lock(peer);
mac_addr = wlan_peer_get_macaddr(peer);
wlan_peer_obj_unlock(peer);
crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_NULL_VALUE;
}
/* push only valid static WEP keys from vap */
if (AUTH_IS_8021X(crypto_params))
return QDF_STATUS_E_INVAL;
if (opmode == QDF_STA_MODE) {
peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_CRYPTO_ID);
if (!peer) {
crypto_err("peer NULL");
return QDF_STATUS_E_INVAL;
}
}
wlan_crypto_peer_get_comp_params(peer, &sta_crypto_priv);
if (!sta_crypto_priv) {
crypto_err("sta priv is null");
status = QDF_STATUS_E_INVAL;
goto exit;
}
for (i = 0; i < WLAN_CRYPTO_MAXKEYIDX; i++) {
if (crypto_priv->key[i]) {
key = crypto_priv->key[i];
if (!key || !key->valid)
continue;
cipher_table = (struct wlan_crypto_cipher *)
key->cipher_table;
if (cipher_table->cipher == WLAN_CRYPTO_CIPHER_WEP) {
sta_key = qdf_mem_malloc(
sizeof(struct wlan_crypto_key));
if (!sta_key) {
status = QDF_STATUS_E_NOMEM;
goto exit;
}
sta_crypto_priv->key[i] = sta_key;
qdf_mem_copy(sta_key, key,
sizeof(struct wlan_crypto_key));
sta_key->flags &= ~WLAN_CRYPTO_KEY_DEFAULT;
if (crypto_priv->def_tx_keyid == i) {
sta_key->flags
|= WLAN_CRYPTO_KEY_DEFAULT;
sta_crypto_priv->def_tx_keyid =
crypto_priv->def_tx_keyid;
}
/* setting the broadcast/multicast key for sta*/
if (opmode == QDF_STA_MODE ||
opmode == QDF_IBSS_MODE){
if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) {
WLAN_CRYPTO_TX_OPS_SETKEY(psoc)(
vdev, sta_key, mac_addr,
cipher_table->cipher);
}
}
/* setting unicast key */
sta_key->flags &= ~WLAN_CRYPTO_KEY_GROUP;
if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) {
WLAN_CRYPTO_TX_OPS_SETKEY(psoc)(vdev,
sta_key, mac_addr,
cipher_table->cipher);
}
}
}
}
exit:
if (opmode == QDF_STA_MODE)
wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
return status;
}
/**
* wlan_crypto_register_crypto_rx_ops - set crypto_rx_ops
* @crypto_rx_ops: crypto_rx_ops
*
* This function gets called by object manger to register crypto rx ops.
*
* Return: QDF_STATUS
*/
QDF_STATUS wlan_crypto_register_crypto_rx_ops(
struct wlan_lmac_if_crypto_rx_ops *crypto_rx_ops){
crypto_rx_ops->crypto_encap = wlan_crypto_encap;
crypto_rx_ops->crypto_decap = wlan_crypto_decap;
crypto_rx_ops->crypto_enmic = wlan_crypto_enmic;
crypto_rx_ops->crypto_demic = wlan_crypto_demic;
crypto_rx_ops->set_peer_wep_keys = wlan_crypto_set_peer_wep_keys;
return QDF_STATUS_SUCCESS;
}
/**
* wlan_crypto_get_crypto_rx_ops - get crypto_rx_ops from psoc
* @psoc: psoc
*
* This function gets called by umac to get the crypto_rx_ops
*
* Return: crypto_rx_ops
*/
struct wlan_lmac_if_crypto_rx_ops *wlan_crypto_get_crypto_rx_ops(
struct wlan_objmgr_psoc *psoc)
{
return &(psoc->soc_cb.rx_ops.crypto_rx_ops);
}
qdf_export_symbol(wlan_crypto_get_crypto_rx_ops);
/**
* wlan_crypto_vdev_has_auth_mode - check authmode for vdev
* @vdev: vdev
* @authvalue: authvalue to be checked
*
* This function check is authvalue passed is set in vdev or not
*
* Return: true or false
*/
bool wlan_crypto_vdev_has_auth_mode(struct wlan_objmgr_vdev *vdev,
wlan_crypto_auth_mode authvalue)
{
return wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_AUTH_MODE)
& authvalue;
}
qdf_export_symbol(wlan_crypto_vdev_has_auth_mode);
/**
* wlan_crypto_peer_has_auth_mode - check authmode for peer
* @peer: peer
* @authvalue: authvalue to be checked
*
* This function check is authvalue passed is set in peer or not
*
* Return: true or false
*/
bool wlan_crypto_peer_has_auth_mode(struct wlan_objmgr_peer *peer,
wlan_crypto_auth_mode authvalue)
{
return wlan_crypto_get_peer_param(peer, WLAN_CRYPTO_PARAM_AUTH_MODE)
& authvalue;
}
qdf_export_symbol(wlan_crypto_peer_has_auth_mode);
/**
* wlan_crypto_vdev_has_ucastcipher - check ucastcipher for vdev
* @vdev: vdev
* @ucastcipher: ucastcipher to be checked
*
* This function check is ucastcipher passed is set in vdev or not
*
* Return: true or false
*/
bool wlan_crypto_vdev_has_ucastcipher(struct wlan_objmgr_vdev *vdev,
wlan_crypto_cipher_type ucastcipher)
{
return wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_UCAST_CIPHER)
& ucastcipher;
}
qdf_export_symbol(wlan_crypto_vdev_has_ucastcipher);
/**
* wlan_crypto_peer_has_ucastcipher - check ucastcipher for peer
* @peer: peer
* @ucastcipher: ucastcipher to be checked
*
* This function check is ucastcipher passed is set in peer or not
*
* Return: true or false
*/
bool wlan_crypto_peer_has_ucastcipher(struct wlan_objmgr_peer *peer,
wlan_crypto_cipher_type ucastcipher)
{
return wlan_crypto_get_peer_param(peer, WLAN_CRYPTO_PARAM_UCAST_CIPHER)
& ucastcipher;
}
qdf_export_symbol(wlan_crypto_peer_has_ucastcipher);
/**
* wlan_crypto_vdev_has_mcastcipher - check mcastcipher for vdev
* @vdev: vdev
* @mcastcipher: mcastcipher to be checked
*
* This function check is mcastcipher passed is set in vdev or not
*
* Return: true or false
*/
bool wlan_crypto_vdev_has_mcastcipher(struct wlan_objmgr_vdev *vdev,
wlan_crypto_cipher_type mcastcipher)
{
return wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_MCAST_CIPHER)
& mcastcipher;
}
qdf_export_symbol(wlan_crypto_vdev_has_mcastcipher);
/**
* wlan_crypto_peer_has_mcastcipher - check mcastcipher for peer
* @peer: peer
* @mcastcipher: mcastcipher to be checked
*
* This function check is mcastcipher passed is set in peer or not
*
* Return: true or false
*/
bool wlan_crypto_peer_has_mcastcipher(struct wlan_objmgr_peer *peer,
wlan_crypto_cipher_type mcastcipher)
{
return wlan_crypto_get_peer_param(peer, WLAN_CRYPTO_PARAM_MCAST_CIPHER)
& mcastcipher;
}
qdf_export_symbol(wlan_crypto_peer_has_mcastcipher);
/**
* wlan_crypto_vdev_has_mgmtcipher - check mgmtcipher for vdev
* @vdev: vdev
* @mgmtcipher: mgmtcipher to be checked
*
* This function checks any one of mgmtciphers are supported by vdev or not.
*
* Return: true or false
*/
bool wlan_crypto_vdev_has_mgmtcipher(struct wlan_objmgr_vdev *vdev,
uint32_t mgmtcipher)
{
return (wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_MGMT_CIPHER)
& mgmtcipher) != 0;
}
qdf_export_symbol(wlan_crypto_vdev_has_mgmtcipher);
/**
* wlan_crypto_peer_has_mgmtcipher - check mgmtcipher for peer
* @peer: peer
* @mgmtcipher: mgmtcipher to be checked
*
* This function checks any one of mgmtciphers are supported by peer or not
*
* Return: true or false
*/
bool wlan_crypto_peer_has_mgmtcipher(struct wlan_objmgr_peer *peer,
uint32_t mgmtcipher)
{
return (wlan_crypto_get_peer_param(peer, WLAN_CRYPTO_PARAM_MGMT_CIPHER)
& mgmtcipher) != 0;
}
qdf_export_symbol(wlan_crypto_peer_has_mgmtcipher);
uint8_t wlan_crypto_get_peer_fils_aead(struct wlan_objmgr_peer *peer)
{
struct wlan_crypto_comp_priv *crypto_priv = NULL;
if (!peer) {
crypto_err("Invalid Input");
return 0;
}
crypto_priv = wlan_get_peer_crypto_obj(peer);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return 0;
}
return crypto_priv->fils_aead_set;
}
void
wlan_crypto_set_peer_fils_aead(struct wlan_objmgr_peer *peer, uint8_t value)
{
struct wlan_crypto_comp_priv *crypto_priv = NULL;
if (!peer) {
crypto_err("Invalid Input");
return;
}
crypto_priv = wlan_get_peer_crypto_obj(peer);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return;
}
crypto_priv->fils_aead_set = value;
}
/**
* wlan_crypto_get_key_header - get header length
* @key: key
*
* This function gets header length based on keytype
*
* Return: header length
*/
uint8_t wlan_crypto_get_key_header(struct wlan_crypto_key *key)
{
struct wlan_crypto_cipher *cipher_table;
cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
if (cipher_table)
return cipher_table->header;
else
return 0;
}
qdf_export_symbol(wlan_crypto_get_key_header);
/**
* wlan_crypto_get_key_trailer - get cipher trailer length
* @key: key
*
* This function gets cipher trailer length based on keytype
*
* Return: cipher trailer length
*/
uint8_t wlan_crypto_get_key_trailer(struct wlan_crypto_key *key)
{
struct wlan_crypto_cipher *cipher_table;
cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
if (cipher_table)
return cipher_table->trailer;
else
return 0;
}
qdf_export_symbol(wlan_crypto_get_key_trailer);
/**
* wlan_crypto_get_key_miclen - get cipher miclen length
* @key: key
*
* This function gets cipher miclen length based on keytype
*
* Return: cipher miclen length
*/
uint8_t wlan_crypto_get_key_miclen(struct wlan_crypto_key *key)
{
struct wlan_crypto_cipher *cipher_table;
cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
if (cipher_table)
return cipher_table->miclen;
else
return 0;
}
qdf_export_symbol(wlan_crypto_get_key_miclen);
/**
* wlan_crypto_get_keyid - get keyid from frame
* @data: frame
*
* This function parse frame and returns keyid
*
* Return: keyid
*/
uint16_t wlan_crypto_get_keyid(uint8_t *data, int hdrlen)
{
struct wlan_frame_hdr *hdr = (struct wlan_frame_hdr *)data;
uint8_t *iv;
uint8_t stype = WLAN_FC0_GET_STYPE(hdr->i_fc[0]);
/*
* In FILS SK (Re)Association request/response frame has
* to be decrypted
*/
if ((stype == WLAN_FC0_STYPE_ASSOC_REQ) ||
(stype == WLAN_FC0_STYPE_REASSOC_REQ) ||
(stype == WLAN_FC0_STYPE_ASSOC_RESP) ||
(stype == WLAN_FC0_STYPE_REASSOC_RESP)) {
return 0;
}
if (hdr->i_fc[1] & WLAN_FC1_ISWEP) {
iv = data + hdrlen;
/*
* iv[3] is the Key ID octet in the CCMP/TKIP/WEP headers
* Bits 6–7 of the Key ID octet are for the Key ID subfield
*/
return ((iv[3] >> 6) & 0x3);
} else {
return WLAN_CRYPTO_KEYIX_NONE;
}
}
qdf_export_symbol(wlan_crypto_get_keyid);
/**
* crypto_plumb_peer_keys - called during radio reset
* @vdev: vdev
* @object: peer
* @arg: psoc
*
* Restore unicast and persta hardware keys
*
* Return: void
*/
static void crypto_plumb_peer_keys(struct wlan_objmgr_vdev *vdev,
void *object, void *arg) {
struct wlan_objmgr_peer *peer = (struct wlan_objmgr_peer *)object;
struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)arg;
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_crypto_key *key = NULL;
int i;
if ((!peer) || (!vdev) || (!psoc)) {
crypto_err("Peer or vdev or psoc objects are null!");
return;
}
crypto_params = wlan_crypto_peer_get_comp_params(peer,
&crypto_priv);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return;
}
for (i = 0; i < WLAN_CRYPTO_MAXKEYIDX; i++) {
key = crypto_priv->key[i];
if (key && key->valid) {
if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) {
WLAN_CRYPTO_TX_OPS_SETKEY(psoc)
(
vdev,
key,
wlan_peer_get_macaddr(peer),
wlan_crypto_get_key_type(key)
);
}
}
}
}
/**
* wlan_crypto_restore_keys - called during radio reset
* @vdev: vdev
*
* Clear and restore keycache, needed for some DA chipsets which put
* random values in keycache when phy reset is triggered
*
* Return: void
*/
void wlan_crypto_restore_keys(struct wlan_objmgr_vdev *vdev)
{
int i;
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_crypto_key *key;
uint8_t macaddr[QDF_MAC_ADDR_SIZE] =
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
struct wlan_objmgr_pdev *pdev = NULL;
struct wlan_objmgr_psoc *psoc = NULL;
pdev = wlan_vdev_get_pdev(vdev);
psoc = wlan_vdev_get_psoc(vdev);
if (!pdev) {
crypto_err("pdev is NULL");
return;
}
if (!psoc) {
crypto_err("psoc is NULL");
return;
}
/* TBD: QWRAP key restore*/
/* crypto is on */
if (wlan_vdev_mlme_feat_cap_get(vdev, WLAN_VDEV_F_PRIVACY)) {
/* restore static shared keys */
for (i = 0; i < WLAN_CRYPTO_MAXKEYIDX; i++) {
crypto_params = wlan_crypto_vdev_get_comp_params
(
vdev,
&crypto_priv
);
if (!crypto_priv) {
crypto_err("crypto_priv is NULL");
return;
}
key = crypto_priv->key[i];
if (key && key->valid) {
if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) {
WLAN_CRYPTO_TX_OPS_SETKEY(psoc)
(
vdev,
key,
macaddr,
wlan_crypto_get_key_type(key)
);
}
}
}
wlan_objmgr_iterate_peerobj_list(vdev,
crypto_plumb_peer_keys,
psoc,
WLAN_CRYPTO_ID);
}
}
/**
* wlan_crypto_check_open_none - called by ucfg to check for open security
* @psoc: psoc pointer
* @vdev_id: vdev id
*
* This function gets called from ucfg to check open security.
*
* Return: true or false
*/
bool wlan_crypto_check_open_none(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
{
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_objmgr_vdev *vdev;
bool match = true;
if (!psoc) {
crypto_err("PSOC is NULL");
return false;
}
vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
WLAN_CRYPTO_ID);
if (!vdev) {
crypto_err("vdev is NULL");
return false;
}
crypto_priv = (struct wlan_crypto_comp_priv *)
wlan_get_vdev_crypto_obj(vdev);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
match = false;
goto send_res;
}
crypto_params = &crypto_priv->crypto_params;
if (crypto_params->mcastcipherset != WLAN_CRYPTO_CIPHER_NONE) {
match = false;
goto send_res;
}
if ((crypto_params->authmodeset != WLAN_CRYPTO_AUTH_AUTO) &&
(crypto_params->authmodeset != WLAN_CRYPTO_AUTH_NONE))
match = false;
send_res:
wlan_objmgr_vdev_release_ref(vdev, WLAN_CRYPTO_ID);
return match;
}
/**
* wlan_crypto_check_wep - called by ucfg to check for WEP security
* @psoc: psoc pointer
* @vdev_id: vdev id
*
* This function gets called from ucfg to check WEP security.
*
* Return: true or false
*/
bool wlan_crypto_check_wep(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
{
struct wlan_crypto_comp_priv *crypto_priv;
struct wlan_crypto_params *crypto_params;
struct wlan_objmgr_vdev *vdev;
bool match = true;
if (!psoc) {
crypto_err("PSOC is NULL");
return false;
}
vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
WLAN_CRYPTO_ID);
if (!vdev) {
crypto_err("vdev is NULL");
return false;
}
crypto_priv = (struct wlan_crypto_comp_priv *)
wlan_get_vdev_crypto_obj(vdev);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
match = false;
goto send_res;
}
crypto_params = &crypto_priv->crypto_params;
if ((crypto_params->ucastcipherset != WLAN_CRYPTO_CIPHER_WEP) &&
(crypto_params->ucastcipherset != WLAN_CRYPTO_CIPHER_WEP_40) &&
(crypto_params->ucastcipherset != WLAN_CRYPTO_CIPHER_WEP_104)) {
match = false;
goto send_res;
}
if ((crypto_params->mcastcipherset != WLAN_CRYPTO_CIPHER_WEP) &&
(crypto_params->mcastcipherset != WLAN_CRYPTO_CIPHER_WEP_40) &&
(crypto_params->mcastcipherset != WLAN_CRYPTO_CIPHER_WEP_104)) {
match = false;
goto send_res;
}
if (crypto_params->ucastcipherset != crypto_params->mcastcipherset) {
match = false;
goto send_res;
}
if ((crypto_params->authmodeset != WLAN_CRYPTO_AUTH_AUTO) &&
(crypto_params->authmodeset != WLAN_CRYPTO_AUTH_OPEN) &&
(crypto_params->authmodeset != WLAN_CRYPTO_AUTH_SHARED)) {
match = false;
}
send_res:
wlan_objmgr_vdev_release_ref(vdev, WLAN_CRYPTO_ID);
return match;
}
static QDF_STATUS
wlan_get_crypto_params_from_rsn_ie(struct wlan_crypto_params *crypto_params,
uint8_t *ie_ptr, uint16_t ie_len)
{
const uint8_t *rsn_ie = NULL;
QDF_STATUS status;
qdf_mem_zero(crypto_params, sizeof(struct wlan_crypto_params));
rsn_ie = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSN, ie_ptr, ie_len);
if (!rsn_ie) {
crypto_err("RSN IE NULL");
return QDF_STATUS_E_INVAL;
}
status = wlan_crypto_rsnie_check(crypto_params, (uint8_t *)rsn_ie);
if (QDF_STATUS_SUCCESS != status) {
crypto_err("RSN IE check failed");
return status;
}
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS
wlan_get_crypto_params_from_wpa_ie(struct wlan_crypto_params *crypto_params,
uint8_t *ie_ptr, uint16_t ie_len)
{
const uint8_t *wpa_ie = NULL;
uint32_t wpa_oui;
QDF_STATUS status;
qdf_mem_zero(crypto_params, sizeof(struct wlan_crypto_params));
wpa_oui = WLAN_WPA_SEL(WLAN_WPA_OUI_TYPE);
wpa_ie = wlan_get_vendor_ie_ptr_from_oui((uint8_t *)&wpa_oui,
WLAN_OUI_SIZE, ie_ptr, ie_len);
if (!wpa_ie) {
crypto_err("WPA IE NULL");
return QDF_STATUS_E_INVAL;
}
status = wlan_crypto_wpaie_check(crypto_params, (uint8_t *)wpa_ie);
if (QDF_STATUS_SUCCESS != status) {
crypto_err("WPA IE check failed");
return status;
}
return QDF_STATUS_SUCCESS;
}
/**
* wlan_crypto_check_rsn_match - called by ucfg to check for RSN match
* @psoc: psoc pointer
* @vdev_id: vdev id
* @ie_ptr: pointer to IEs
* @ie_len: IE length
*
* This function gets called from ucfg to check RSN match.
*
* Return: true or false
*/
bool wlan_crypto_check_rsn_match(struct wlan_objmgr_psoc *psoc,
uint8_t vdev_id, uint8_t *ie_ptr,
uint16_t ie_len)
{
struct wlan_crypto_params peer_crypto_params;
struct wlan_objmgr_vdev *vdev;
bool match = true;
QDF_STATUS status;
if (!psoc) {
crypto_err("PSOC is NULL");
return false;
}
status = wlan_get_crypto_params_from_rsn_ie(&peer_crypto_params,
ie_ptr, ie_len);
if (QDF_STATUS_SUCCESS != status) {
crypto_err("get crypto prarams from RSN IE failed");
return false;
}
vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
WLAN_CRYPTO_ID);
if (!vdev) {
crypto_err("vdev is NULL");
return false;
}
match = wlan_crypto_rsn_info(vdev, &peer_crypto_params);
wlan_objmgr_vdev_release_ref(vdev, WLAN_CRYPTO_ID);
return match;
}
/**
* wlan_crypto_check_wpa_match - called by ucfg to check for WPA match
* @psoc: psoc pointer
* @vdev_id: vdev id
* @ie_ptr: pointer to IEs
* @ie_len: IE length
*
* This function gets called from ucfg to check WPA match.
*
* Return: true or false
*/
bool wlan_crypto_check_wpa_match(struct wlan_objmgr_psoc *psoc,
uint8_t vdev_id, uint8_t *ie_ptr,
uint16_t ie_len)
{
struct wlan_crypto_params peer_crypto_params;
struct wlan_objmgr_vdev *vdev;
bool match = true;
QDF_STATUS status;
if (!psoc) {
crypto_err("PSOC is NULL");
return false;
}
vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
WLAN_CRYPTO_ID);
if (!vdev) {
crypto_err("vdev is NULL");
return false;
}
status = wlan_get_crypto_params_from_wpa_ie(&peer_crypto_params,
ie_ptr, ie_len);
if (QDF_STATUS_SUCCESS != status) {
crypto_err("get crypto prarams from WPA IE failed");
match = false;
goto send_res;
}
match = wlan_crypto_rsn_info(vdev, &peer_crypto_params);
send_res:
wlan_objmgr_vdev_release_ref(vdev, WLAN_CRYPTO_ID);
return match;
}
static void
wlan_crypto_merge_prarams(struct wlan_crypto_params *dst_params,
struct wlan_crypto_params *src_params)
{
dst_params->authmodeset |= src_params->authmodeset;
dst_params->ucastcipherset |= src_params->ucastcipherset;
dst_params->mcastcipherset |= src_params->mcastcipherset;
dst_params->mgmtcipherset |= src_params->mgmtcipherset;
dst_params->cipher_caps |= src_params->cipher_caps;
dst_params->key_mgmt |= src_params->key_mgmt;
dst_params->rsn_caps |= src_params->rsn_caps;
}
static void
wlan_crypto_reset_prarams(struct wlan_crypto_params *params)
{
params->authmodeset = 0;
params->ucastcipherset = 0;
params->mcastcipherset = 0;
params->mgmtcipherset = 0;
params->cipher_caps = 0;
params->key_mgmt = 0;
params->rsn_caps = 0;
}
QDF_STATUS wlan_set_vdev_crypto_prarams_from_ie(struct wlan_objmgr_vdev *vdev,
uint8_t *ie_ptr,
uint16_t ie_len)
{
struct wlan_crypto_params crypto_params;
QDF_STATUS status;
struct wlan_crypto_params *vdev_crypto_params;
struct wlan_crypto_comp_priv *crypto_priv;
bool send_fail = false;
if (!vdev) {
crypto_err("VDEV is NULL");
return QDF_STATUS_E_FAILURE;
}
if (!ie_ptr) {
crypto_err("IE ptr is NULL");
return QDF_STATUS_E_FAILURE;
}
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_FAILURE;
}
vdev_crypto_params = &crypto_priv->crypto_params;
wlan_crypto_reset_prarams(vdev_crypto_params);
status = wlan_get_crypto_params_from_rsn_ie(&crypto_params,
ie_ptr, ie_len);
if (QDF_STATUS_SUCCESS == status) {
wlan_crypto_merge_prarams(vdev_crypto_params, &crypto_params);
} else {
crypto_err("get crypto prarams from RSN IE failed");
send_fail = true;
}
status = wlan_get_crypto_params_from_wpa_ie(&crypto_params,
ie_ptr, ie_len);
if (QDF_STATUS_SUCCESS == status) {
wlan_crypto_merge_prarams(vdev_crypto_params, &crypto_params);
send_fail = false;
} else {
crypto_debug("get crypto prarams from WPA IE failed");
}
return send_fail ? QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS;
}
int8_t wlan_crypto_get_default_key_idx(struct wlan_objmgr_vdev *vdev, bool igtk)
{
struct wlan_crypto_comp_priv *crypto_priv;
crypto_priv = wlan_get_vdev_crypto_obj(vdev);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_FAILURE;
}
if (igtk)
return crypto_priv->def_igtk_tx_keyid;
else
return crypto_priv->def_tx_keyid;
}
enum wlan_crypto_cipher_type
wlan_crypto_get_cipher(struct wlan_objmgr_vdev *vdev,
bool pairwise, uint8_t key_index)
{
struct wlan_crypto_key *crypto_key;
crypto_key = wlan_crypto_get_key(vdev, key_index);
if (crypto_key)
return crypto_key->cipher_type;
else
return WLAN_CRYPTO_CIPHER_INVALID;
}
#ifdef CRYPTO_SET_KEY_CONVERGED
QDF_STATUS wlan_crypto_validate_key_params(enum wlan_crypto_cipher_type cipher,
uint8_t key_index, uint8_t key_len,
uint8_t seq_len)
{
if (key_index >= (WLAN_CRYPTO_MAXKEYIDX + WLAN_CRYPTO_MAXIGTKKEYIDX)) {
crypto_err("Invalid Key index %d", key_index);
return QDF_STATUS_E_INVAL;
}
if (cipher == WLAN_CRYPTO_CIPHER_INVALID) {
crypto_err("Invalid Cipher %d", cipher);
return QDF_STATUS_E_INVAL;
}
if ((!(cipher == WLAN_CRYPTO_CIPHER_AES_CMAC ||
cipher == WLAN_CRYPTO_CIPHER_AES_CMAC_256 ||
cipher == WLAN_CRYPTO_CIPHER_AES_GMAC ||
cipher == WLAN_CRYPTO_CIPHER_AES_GMAC_256)) &&
(key_index >= WLAN_CRYPTO_MAXKEYIDX)) {
crypto_err("Invalid key index %d for cipher %d",
key_index, cipher);
return QDF_STATUS_E_INVAL;
}
if (key_len > (WLAN_CRYPTO_KEYBUF_SIZE + WLAN_CRYPTO_MICBUF_SIZE)) {
crypto_err("Invalid key length %d", key_len);
return QDF_STATUS_E_INVAL;
}
if (seq_len > WLAN_CRYPTO_RSC_SIZE) {
crypto_err("Invalid seq length %d", seq_len);
return QDF_STATUS_E_INVAL;
}
crypto_debug("key: idx:%d, len:%d, seq len:%d",
key_index, key_len, seq_len);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_crypto_save_key(struct wlan_objmgr_vdev *vdev,
uint8_t key_index,
struct wlan_crypto_key *crypto_key)
{
struct wlan_crypto_comp_priv *crypto_priv;
crypto_priv = wlan_get_vdev_crypto_obj(vdev);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return QDF_STATUS_E_FAILURE;
}
if (key_index >= (WLAN_CRYPTO_MAXKEYIDX + WLAN_CRYPTO_MAXIGTKKEYIDX)) {
crypto_err("Invalid Key index %d", key_index);
return QDF_STATUS_E_FAILURE;
}
if (key_index < WLAN_CRYPTO_MAXKEYIDX)
crypto_priv->key[key_index] = crypto_key;
else
crypto_priv->igtk_key[key_index - WLAN_CRYPTO_MAXKEYIDX] =
crypto_key;
return QDF_STATUS_SUCCESS;
}
struct wlan_crypto_key *wlan_crypto_get_key(struct wlan_objmgr_vdev *vdev,
uint8_t key_index)
{
struct wlan_crypto_comp_priv *crypto_priv;
crypto_priv = wlan_get_vdev_crypto_obj(vdev);
if (!crypto_priv) {
crypto_err("crypto_priv NULL");
return NULL;
}
if (key_index >= (WLAN_CRYPTO_MAXKEYIDX + WLAN_CRYPTO_MAXIGTKKEYIDX)) {
crypto_err("Invalid Key index %d", key_index);
return NULL;
}
if (key_index < WLAN_CRYPTO_MAXKEYIDX)
return crypto_priv->key[key_index];
return crypto_priv->igtk_key[key_index - WLAN_CRYPTO_MAXKEYIDX];
}
QDF_STATUS wlan_crypto_set_key_req(struct wlan_objmgr_vdev *vdev,
struct wlan_crypto_key *req,
enum wlan_crypto_key_type key_type)
{
struct wlan_objmgr_psoc *psoc;
psoc = wlan_vdev_get_psoc(vdev);
if (psoc && WLAN_CRYPTO_TX_OPS_SET_KEY(psoc))
WLAN_CRYPTO_TX_OPS_SET_KEY(psoc)(vdev, req, key_type);
else
return QDF_STATUS_E_FAILURE;
return QDF_STATUS_SUCCESS;
}
void wlan_crypto_update_set_key_peer(struct wlan_objmgr_vdev *vdev,
bool pairwise, uint8_t key_index,
struct qdf_mac_addr *peer_mac)
{
struct wlan_crypto_key *crypto_key;
crypto_key = wlan_crypto_get_key(vdev, key_index);
if (!crypto_key) {
crypto_err("crypto_key not present for key_idx %d", key_index);
return;
}
qdf_mem_copy(crypto_key->macaddr, peer_mac, QDF_MAC_ADDR_SIZE);
}
#endif