blob: 62a2a325d64dcea84418dfae9cc9f02cd30af80f [file] [log] [blame]
/** @file hostsa_init.c
*
* @brief This file defines the initialize /free APIs for authenticator and supplicant.
*
* Copyright (C) 2014, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
/******************************************************
Change log:
03/07/2014: Initial version
******************************************************/
#include "mlan.h"
#ifdef STA_SUPPORT
#include "mlan_join.h"
#endif
#include "mlan_ioctl.h"
#include "mlan_util.h"
#include "mlan_fw.h"
#include "mlan_main.h"
#include "mlan_init.h"
#include "mlan_wmm.h"
#include "hostsa_def.h"
#include "authenticator_api.h"
/*********************
Local Variables
*********************/
/*********************
Global Variables
*********************/
/*********************
Local Functions
*********************/
/*********************
Global Functions
*********************/
/*********************
Utility Handler
*********************/
/**
* @brief alloc mlan buffer
*
* @param pmlan_adapter A void pointer
* @param data_len request buffer len
* @param head_room head room len
* @param malloc_flag flag for mlan buffer
* @return pointer to mlan buffer
*/
pmlan_buffer
hostsa_alloc_mlan_buffer(t_void *pmlan_adapter,
t_u32 data_len, t_u32 head_room, t_u32 malloc_flag)
{
mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
pmlan_buffer newbuf = MNULL;
newbuf = wlan_alloc_mlan_buffer(pmadapter, data_len, head_room,
malloc_flag);
return newbuf;
}
/**
* @brief free mlan buffer
*
* @param pmlan_adapter A void pointer
* @param pmbuf a pointer to mlan buffer
*
* @return
*/
void
hostsa_free_mlan_buffer(t_void *pmlan_adapter, mlan_buffer *pmbuf)
{
mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
ENTER();
wlan_free_mlan_buffer(pmadapter, pmbuf);
LEAVE();
}
/**
* @brief send packet
*
* @param pmlan_private A void pointer
* @param pmbuf a pointer to mlan buffer
* @param frameLen paket len
*
* @return
*/
void
hostsa_tx_packet(t_void *pmlan_private, pmlan_buffer pmbuf, t_u16 frameLen)
{
mlan_private *pmpriv = (mlan_private *)pmlan_private;
mlan_adapter *pmadapter = pmpriv->adapter;
t_u8 bss_role = GET_BSS_ROLE(pmpriv);
ENTER();
pmbuf->bss_index = pmpriv->bss_index;
pmbuf->data_len = frameLen;
wlan_add_buf_bypass_txqueue(pmadapter, pmbuf);
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL);
LEAVE();
}
/**
* @brief set key to fw
*
* @param pmlan_private A void pointer
* @param encrypt_key key structure
*
* @return
*/
void
wlan_set_encrypt_key(t_void *pmlan_private, mlan_ds_encrypt_key *encrypt_key)
{
mlan_private *priv = (mlan_private *)pmlan_private;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
if (!encrypt_key->key_len) {
PRINTM(MCMND, "Skip set key with key_len = 0\n");
LEAVE();
return;
}
ret = wlan_prepare_cmd(priv,
HostCmd_CMD_802_11_KEY_MATERIAL,
HostCmd_ACT_GEN_SET,
KEY_INFO_ENABLED, MNULL, encrypt_key);
if (ret == MLAN_STATUS_SUCCESS)
wlan_recv_event(priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL);
LEAVE();
}
/**
* @brief clear key to fw
*
* @param pmlan_private A void pointer
*
* @return
*/
void
wlan_clr_encrypt_key(t_void *pmlan_private)
{
mlan_private *priv = (mlan_private *)pmlan_private;
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_ds_encrypt_key encrypt_key;
ENTER();
memset(priv->adapter, &encrypt_key, 0, sizeof(mlan_ds_encrypt_key));
encrypt_key.key_disable = MTRUE;
encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
ret = wlan_prepare_cmd(priv,
HostCmd_CMD_802_11_KEY_MATERIAL,
HostCmd_ACT_GEN_SET,
KEY_INFO_ENABLED, MNULL, &encrypt_key);
if (ret == MLAN_STATUS_SUCCESS)
wlan_recv_event(priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL);
LEAVE();
}
/**
* @brief send deauth frame
*
* @param pmlan_private A void pointer
* @param addr destination mac address
* @param reason deauth reason
*
* @return
*/
void
hostsa_SendDeauth(t_void *pmlan_private, t_u8 *addr, t_u16 reason)
{
mlan_private *pmpriv = (mlan_private *)pmlan_private;
mlan_adapter *pmadapter = pmpriv->adapter;
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_deauth_param deauth;
ENTER();
memcpy(pmadapter, deauth.mac_addr, addr, MLAN_MAC_ADDR_LENGTH);
deauth.reason_code = reason;
ret = wlan_prepare_cmd(pmpriv,
HOST_CMD_APCMD_STA_DEAUTH,
HostCmd_ACT_GEN_SET,
0, MNULL, (t_void *)&deauth);
if (ret == MLAN_STATUS_SUCCESS)
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
MNULL);
LEAVE();
}
/**
* @brief deauth all connected stations
*
* @param pmlan_private A void pointer
* @param reason deauth reason
*
* @return
*/
void
ApDisAssocAllSta(void *pmlan_private, t_u16 reason)
{
mlan_private *pmpriv = (mlan_private *)pmlan_private;
mlan_adapter *pmadapter = pmpriv->adapter;
sta_node *sta_ptr;
ENTER();
sta_ptr = (sta_node *)util_peek_list(pmadapter->pmoal_handle,
&pmpriv->sta_list,
pmadapter->callbacks.
moal_spin_lock,
pmadapter->callbacks.
moal_spin_unlock);
if (!sta_ptr) {
LEAVE();
return;
}
while (sta_ptr != (sta_node *)&pmpriv->sta_list) {
hostsa_SendDeauth((t_void *)pmpriv, sta_ptr->mac_addr, reason);
sta_ptr = sta_ptr->pnext;
}
LEAVE();
}
/**
* @brief get station entry
*
* @param pmlan_private A void pointer
* @param mac pointer to station mac address
* @param ppconPtr pointer to pointer to connection
*
* @return
*/
void
Hostsa_get_station_entry(t_void *pmlan_private, t_u8 *mac, t_void **ppconPtr)
{
mlan_private *priv = (mlan_private *)pmlan_private;
sta_node *sta_ptr = MNULL;
ENTER();
sta_ptr = wlan_get_station_entry(priv, mac);
*ppconPtr = sta_ptr->cm_connectioninfo;
LEAVE();
}
/**
* @brief find a connection
*
* @param pmlan_private A void pointer
* @param ppconPtr a pointer to pointer to connection
* @param ppsta_node a pointer to pointer to sta node
*
* @return
*/
void
Hostsa_find_connection(t_void *pmlan_private, t_void **ppconPtr,
t_void **ppsta_node)
{
mlan_private *priv = (mlan_private *)pmlan_private;
sta_node *sta_ptr = MNULL;
ENTER();
sta_ptr = (sta_node *)util_peek_list(priv->adapter->pmoal_handle,
&priv->sta_list,
priv->adapter->callbacks.
moal_spin_lock,
priv->adapter->callbacks.
moal_spin_unlock);
if (!sta_ptr) {
LEAVE();
return;
}
*ppsta_node = (t_void *)sta_ptr;
*ppconPtr = sta_ptr->cm_connectioninfo;
LEAVE();
}
/**
* @brief find next connection
*
* @param pmlan_private A void pointer
* @param ppconPtr a pointer to pointer to connection
* @param ppsta_node a pointer to pointer to sta node
*
* @return
*/
void
Hostsa_find_next_connection(t_void *pmlan_private, t_void **ppconPtr,
t_void **ppsta_node)
{
mlan_private *priv = (mlan_private *)pmlan_private;
sta_node *sta_ptr = (sta_node *)*ppsta_node;
ENTER();
if (sta_ptr != (sta_node *)&priv->sta_list)
sta_ptr = sta_ptr->pnext;
*ppsta_node = MNULL;
*ppconPtr = MNULL;
if ((sta_ptr != MNULL) && (sta_ptr != (sta_node *)&priv->sta_list)) {
*ppsta_node = (t_void *)sta_ptr;
*ppconPtr = sta_ptr->cm_connectioninfo;
}
LEAVE();
}
/**
* @brief set management ie for beacon or probe response
*
* @param pmlan_private A void pointer
* @param pbuf ie buf
* @param len ie len
* @param clearIE clear ie
*
* @return
*/
void
Hostsa_set_mgmt_ie(t_void *pmlan_private, t_u8 *pbuf, t_u16 len, t_u8 clearIE)
{
mlan_private *priv = (mlan_private *)pmlan_private;
mlan_adapter *pmadapter = priv->adapter;
mlan_ioctl_req *pioctl_req = MNULL;
mlan_ds_misc_cfg *pds_misc_cfg = MNULL;
custom_ie *pmgmt_ie = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
if (pmadapter == MNULL) {
LEAVE();
return;
}
/* allocate buffer for mlan_ioctl_req and mlan_ds_misc_cfg */
/* FYI - will be freed as part of cmd_response handler */
ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
sizeof(mlan_ioctl_req) +
sizeof(mlan_ds_misc_cfg),
MLAN_MEM_DEF,
(t_u8 **)&pioctl_req);
if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
PRINTM(MERROR, "%s(): Could not allocate ioctl req\n",
__func__);
LEAVE();
return;
}
pds_misc_cfg = (mlan_ds_misc_cfg *)((t_u8 *)pioctl_req +
sizeof(mlan_ioctl_req));
/* prepare mlan_ioctl_req */
memset(pmadapter, pioctl_req, 0x00, sizeof(mlan_ioctl_req));
pioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
pioctl_req->action = MLAN_ACT_SET;
pioctl_req->bss_index = priv->bss_index;
pioctl_req->pbuf = (t_u8 *)pds_misc_cfg;
pioctl_req->buf_len = sizeof(mlan_ds_misc_cfg);
/* prepare mlan_ds_misc_cfg */
memset(pmadapter, pds_misc_cfg, 0x00, sizeof(mlan_ds_misc_cfg));
pds_misc_cfg->sub_command = MLAN_OID_MISC_CUSTOM_IE;
pds_misc_cfg->param.cust_ie.type = TLV_TYPE_MGMT_IE;
pds_misc_cfg->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);
/* configure custom_ie api settings */
pmgmt_ie = (custom_ie *)&pds_misc_cfg->param.cust_ie.ie_data_list[0];
pmgmt_ie->ie_index = 0xffff; /* Auto index */
pmgmt_ie->ie_length = len;
pmgmt_ie->mgmt_subtype_mask = MBIT(8) | MBIT(5); /* add IE for
BEACON |
PROBE_RSP */
if (clearIE)
pmgmt_ie->mgmt_subtype_mask = 0;
memcpy(pmadapter, pmgmt_ie->ie_buffer, pbuf, len);
pds_misc_cfg->param.cust_ie.len += pmgmt_ie->ie_length;
DBG_HEXDUMP(MCMD_D, "authenticator: RSN or WPA IE",
(t_u8 *)pmgmt_ie, pds_misc_cfg->param.cust_ie.len);
ret = wlan_misc_ioctl_custom_ie_list(pmadapter, pioctl_req, MFALSE);
if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) {
PRINTM(MERROR,
"%s(): Could not set IE for priv=%p [priv_bss_idx=%d]!\n",
__func__, priv, priv->bss_index);
/* TODO: how to handle this error case?? ignore & continue? */
}
/* free ioctl buffer memory before we leave */
pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
(t_u8 *)pioctl_req);
}
t_void
StaControlledPortOpen(t_void *pmlan_private)
{
mlan_private *priv = (mlan_private *)pmlan_private;
PRINTM(MERROR, "StaControlledPortOpen\n");
if (priv->port_ctrl_mode == MTRUE) {
PRINTM(MINFO, "PORT_REL: port_status = OPEN\n");
priv->port_open = MTRUE;
}
priv->adapter->scan_block = MFALSE;
wlan_recv_event(priv, MLAN_EVENT_ID_FW_PORT_RELEASE, MNULL);
}
void
hostsa_StaSendDeauth(t_void *pmlan_private, t_u8 *addr, t_u16 reason)
{
mlan_private *pmpriv = (mlan_private *)pmlan_private;
mlan_adapter *pmadapter = pmpriv->adapter;
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_deauth_param deauth;
ENTER();
memcpy(pmadapter, deauth.mac_addr, addr, MLAN_MAC_ADDR_LENGTH);
deauth.reason_code = reason;
ret = wlan_prepare_cmd(pmpriv,
HostCmd_CMD_802_11_DEAUTHENTICATE,
HostCmd_ACT_GEN_SET,
0, MNULL, (t_void *)&deauth);
if (ret == MLAN_STATUS_SUCCESS)
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
MNULL);
LEAVE();
}
t_u8
Hostsa_get_bss_role(t_void *pmlan_private)
{
mlan_private *pmpriv = (mlan_private *)pmlan_private;
return GET_BSS_ROLE(pmpriv);
}
/**
* @brief send event to moal to notice that 4 way handshake complete
*
* @param pmlan_private A void pointer
* @param addr pointer to station mac address
*
* @return
*/
t_void
Hostsa_sendEventRsnConnect(t_void *pmlan_private, t_u8 *addr)
{
mlan_private *pmpriv = (mlan_private *)pmlan_private;
mlan_adapter *pmadapter = pmpriv->adapter;
t_u8 *event_buf = MNULL, *pos = MNULL;
t_u32 event_cause = 0;
mlan_event *pevent = MNULL;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
MAX_EVENT_SIZE, MLAN_MEM_DEF,
&event_buf);
if ((ret != MLAN_STATUS_SUCCESS) || !event_buf) {
PRINTM(MERROR, "Could not allocate buffer for event buf\n");
goto done;
}
pevent = (pmlan_event)event_buf;
memset(pmadapter, event_buf, 0, MAX_EVENT_SIZE);
pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
pevent->bss_index = pmpriv->bss_index;
event_cause = wlan_cpu_to_le32(0x51); /* MICRO_AP_EV_ID_RSN_CONNECT */
memcpy(pmadapter, (t_u8 *)pevent->event_buf,
(t_u8 *)&event_cause, sizeof(event_cause));
pos = pevent->event_buf + sizeof(event_cause) + 2; /* reserved 2
byte */
memcpy(pmadapter, (t_u8 *)pos, addr, MLAN_MAC_ADDR_LENGTH);
pevent->event_len = MLAN_MAC_ADDR_LENGTH + sizeof(event_cause) + 2;
wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_PASSTHRU, event_buf);
done:
if (event_buf)
pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
event_buf);
LEAVE();
}
/**
* @brief This function initializes callbacks that hostsa interface uses.
*
* @param pmpriv A pointer to mlan_private structure
* @param putil_fns A pointer to hostsa_util_fns structure
* @param pmlan_fns A pointer to hostsa_mlan_fns structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static t_void
hostsa_mlan_callbacks(IN pmlan_private pmpriv,
IN hostsa_util_fns *putil_fns,
IN hostsa_mlan_fns *pmlan_fns)
{
pmlan_adapter pmadapter = pmpriv->adapter;
pmlan_callbacks pcb = &pmadapter->callbacks;
putil_fns->pmoal_handle = pmadapter->pmoal_handle;
putil_fns->moal_malloc = pcb->moal_malloc;
putil_fns->moal_mfree = pcb->moal_mfree;
putil_fns->moal_memset = pcb->moal_memset;
putil_fns->moal_memcpy = pcb->moal_memcpy;
putil_fns->moal_memmove = pcb->moal_memmove;
putil_fns->moal_memcmp = pcb->moal_memcmp;
putil_fns->moal_udelay = pcb->moal_udelay;
putil_fns->moal_get_system_time = pcb->moal_get_system_time;
putil_fns->moal_init_timer = pcb->moal_init_timer;
putil_fns->moal_free_timer = pcb->moal_free_timer;
putil_fns->moal_start_timer = pcb->moal_start_timer;
putil_fns->moal_stop_timer = pcb->moal_stop_timer;
putil_fns->moal_init_lock = pcb->moal_init_lock;
putil_fns->moal_free_lock = pcb->moal_free_lock;
putil_fns->moal_spin_lock = pcb->moal_spin_lock;
putil_fns->moal_spin_unlock = pcb->moal_spin_unlock;
putil_fns->moal_print = pcb->moal_print;
putil_fns->moal_print_netintf = pcb->moal_print_netintf;
pmlan_fns->pmlan_private = pmpriv;
pmlan_fns->pmlan_adapter = pmpriv->adapter;
pmlan_fns->bss_index = pmpriv->bss_index;
pmlan_fns->bss_type = pmpriv->bss_type;
#if 0
pmlan_fns->mlan_add_buf_txqueue = mlan_add_buf_txqueue;
pmlan_fns->mlan_select_wmm_queue = mlan_select_wmm_queue;
pmlan_fns->mlan_write_data_complete = mlan_write_data_complete;
#endif
pmlan_fns->hostsa_alloc_mlan_buffer = hostsa_alloc_mlan_buffer;
pmlan_fns->hostsa_tx_packet = hostsa_tx_packet;
pmlan_fns->hostsa_set_encrypt_key = wlan_set_encrypt_key;
pmlan_fns->hostsa_clr_encrypt_key = wlan_clr_encrypt_key;
pmlan_fns->hostsa_SendDeauth = hostsa_SendDeauth;
pmlan_fns->Hostsa_DisAssocAllSta = ApDisAssocAllSta;
pmlan_fns->hostsa_free_mlan_buffer = hostsa_free_mlan_buffer;
pmlan_fns->Hostsa_get_station_entry = Hostsa_get_station_entry;
pmlan_fns->Hostsa_set_mgmt_ie = Hostsa_set_mgmt_ie;
pmlan_fns->Hostsa_find_connection = Hostsa_find_connection;
pmlan_fns->Hostsa_find_next_connection = Hostsa_find_next_connection;
pmlan_fns->Hostsa_StaControlledPortOpen = StaControlledPortOpen;
pmlan_fns->hostsa_StaSendDeauth = hostsa_StaSendDeauth;
pmlan_fns->Hostsa_get_bss_role = Hostsa_get_bss_role;
pmlan_fns->Hostsa_sendEventRsnConnect = Hostsa_sendEventRsnConnect;
};
/**
* @brief Init hostsa data
*
* @param pmlan_private A pointer to mlan private data structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
hostsa_init(pmlan_private pmpriv)
{
hostsa_util_fns util_fns;
hostsa_mlan_fns mlan_fns;
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
hostsa_mlan_callbacks(pmpriv, &util_fns, &mlan_fns);
ret = supplicant_authenticator_init(&pmpriv->psapriv, &util_fns,
&mlan_fns, pmpriv->curr_addr);
LEAVE();
return ret;
}
/**
* @brief Cleanup hostsa data
*
* @param pmlan_private A pointer to a mlan private data structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
hostsa_cleanup(pmlan_private pmpriv)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
supplicant_authenticator_free(pmpriv->psapriv);
LEAVE();
return ret;
}