/******************************************************************************
*
* Copyright(c) 2019 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*****************************************************************************/
#define _PHL_SEC_C_
#include "phl_headers.h"
#define RTW_PHL_EXT_KEY_LEN 32
#define RTW_SEC_KEY_TYPE_NUM 3
static enum rtw_phl_status
_phl_set_key(struct phl_info_t *phl_info,
struct rtw_phl_stainfo_t *sta,
struct phl_sec_param_h *crypt,
u8 *keybuf)
{
enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
if(keybuf)
PHL_INFO("Add_key:: enc_type(%d) key_id(%d) key_type(%d)\n",
crypt->enc_type, crypt->keyid, crypt->key_type);
hal_status = rtw_hal_set_key(phl_info->hal,
sta,
crypt->enc_type,
(crypt->key_len==RTW_PHL_EXT_KEY_LEN)?1:0,
crypt->spp,
crypt->keyid,
crypt->key_type,
keybuf);
if (hal_status == RTW_HAL_STATUS_SUCCESS)
phl_status = RTW_PHL_STATUS_SUCCESS;
return phl_status;
}
#ifdef CONFIG_CMD_DISP
struct cmd_sec_param {
struct rtw_phl_stainfo_t *sta;
struct phl_sec_param_h *crypt;
u8 *keybuf;
};
static void
_phl_cmd_set_key_done(void *drv_priv,
u8 *cmd,
u32 cmd_len,
enum rtw_phl_status status)
{
struct cmd_sec_param *param = (struct cmd_sec_param *)cmd;
if (param) {
if (param->keybuf)
_os_kmem_free(drv_priv,
param->keybuf,
param->crypt->key_len);
if (param->crypt)
_os_kmem_free(drv_priv,
param->crypt,
sizeof(struct phl_sec_param_h));
_os_kmem_free(drv_priv, param, cmd_len);
}
}
enum rtw_phl_status
_phl_cmd_set_key(void *phl,
struct rtw_phl_stainfo_t *sta,
struct phl_sec_param_h *crypt,
u8 *keybuf,
enum phl_cmd_type cmd_type,
u32 cmd_timeout)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
void *drv = phl_to_drvpriv(phl_info);
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
struct cmd_sec_param *param = NULL;
u32 param_len = 0, crypt_len = 0;
if (cmd_type == PHL_CMD_DIRECTLY) {
psts = _phl_set_key(phl_info, sta, crypt, keybuf);
goto _exit;
}
param_len = sizeof(struct cmd_sec_param);
param = _os_kmem_alloc(drv, param_len);
if (param == NULL) {
PHL_ERR("%s: alloc param failed!\n", __func__);
psts = RTW_PHL_STATUS_RESOURCE;
goto error_param;
}
_os_mem_set(drv, param, 0, param_len);
param->sta = sta;
crypt_len = sizeof(struct phl_sec_param_h);
param->crypt = _os_kmem_alloc(drv, crypt_len);
if (param->crypt == NULL) {
PHL_ERR("%s: alloc param->crypt failed!\n", __func__);
psts = RTW_PHL_STATUS_RESOURCE;
goto error_crypt;
}
_os_mem_set(drv, param->crypt, 0, crypt_len);
_os_mem_cpy(drv, param->crypt, crypt, crypt_len);
if (keybuf) { /* set key */
param->keybuf = _os_kmem_alloc(drv, param->crypt->key_len);
if (param->keybuf == NULL) {
PHL_ERR("%s: alloc param->keybuf failed!\n", __func__);
psts = RTW_PHL_STATUS_RESOURCE;
goto error_key_buf;
}
_os_mem_cpy(drv, param->keybuf, keybuf, param->crypt->key_len);
}
psts = phl_cmd_enqueue(phl_info,
sta->wrole->hw_band,
MSG_EVT_SEC_KEY,
(u8 *)param,
param_len,
_phl_cmd_set_key_done,
cmd_type,
cmd_timeout);
if (is_cmd_failure(psts)) {
/* Send cmd success, but wait cmd fail*/
psts = RTW_PHL_STATUS_FAILURE;
} else if (psts != RTW_PHL_STATUS_SUCCESS) {
/* Send cmd fail */
psts = RTW_PHL_STATUS_FAILURE;
goto error_cmd;
}
return psts;
error_cmd:
if (param->keybuf)
_os_kmem_free(drv, param->keybuf, param->crypt->key_len);
error_key_buf:
if (param->crypt)
_os_kmem_free(drv, param->crypt, crypt_len);
error_crypt:
if (param)
_os_kmem_free(drv, param, param_len);
error_param:
_exit:
return psts;
}
enum rtw_phl_status
phl_cmd_set_key_hdl(struct phl_info_t *phl_info, u8 *param)
{
struct cmd_sec_param *cmd_sec_param = (struct cmd_sec_param *)param;
return _phl_set_key(phl_info,
cmd_sec_param->sta,
cmd_sec_param->crypt,
cmd_sec_param->keybuf);
}
#endif /* CONFIG_CMD_DISP */
enum rtw_phl_status
rtw_phl_cmd_add_key(void *phl,
struct rtw_phl_stainfo_t *sta,
struct phl_sec_param_h *crypt,
u8 *keybuf,
enum phl_cmd_type cmd_type,
u32 cmd_timeout)
{
#ifdef CONFIG_CMD_DISP
return _phl_cmd_set_key(phl, sta, crypt, keybuf, cmd_type, cmd_timeout);
#else
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s: not support add key cmd\n",
__func__);
return _phl_set_key((struct phl_info_t *)phl, sta, crypt, keybuf);
#endif /* CONFIG_CMD_DISP */
}
enum rtw_phl_status
rtw_phl_cmd_del_key(void *phl,
struct rtw_phl_stainfo_t *sta,
struct phl_sec_param_h *crypt,
enum phl_cmd_type cmd_type,
u32 cmd_timeout)
{
#ifdef CONFIG_CMD_DISP
return _phl_cmd_set_key(phl, sta, crypt, NULL, cmd_type, cmd_timeout);
#else
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s: not support del key cmd\n",
__func__);
return _phl_set_key((struct phl_info_t *)phl, sta, crypt, NULL);
#endif /* CONFIG_CMD_DISP */
}
u8 rtw_phl_trans_sec_mode(u8 unicast, u8 multicast)
{
u8 ret = RTW_SEC_ENT_MODE_0;
if (RTW_ENC_NONE == unicast && RTW_ENC_NONE == multicast) {
ret = RTW_SEC_ENT_MODE_0;
} else if ((RTW_ENC_WEP40 == unicast && RTW_ENC_WEP40 == multicast) ||
(RTW_ENC_WEP104 == unicast && RTW_ENC_WEP104 == multicast)) {
ret = RTW_SEC_ENT_MODE_1;
} else if (RTW_ENC_WEP40 == multicast || RTW_ENC_WEP104 == multicast) {
ret = RTW_SEC_ENT_MODE_3;
} else {
ret = RTW_SEC_ENT_MODE_2;
}
return ret;
}
u8 rtw_phl_get_sec_cam_idx(void *phl,
struct rtw_phl_stainfo_t *sta,
u8 keyid,
u8 key_type)
{
u8 ret = 0;
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
ret = (u8) rtw_hal_search_key_idx(phl_info->hal, sta, keyid, key_type);
return ret;
}