/** @file hostsa_init.c * * @brief This file defines the initialize /free APIs for authenticator and supplicant. * * Copyright (C) 2014-2017, 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; 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); if (sta_ptr) *ppconPtr = sta_ptr->cm_connectioninfo; else *ppconPtr = MNULL; 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); } t_u8 Hostsa_get_intf_hr_len(t_void *pmlan_private) { mlan_private *pmpriv = (mlan_private *)pmlan_private; return pmpriv->intf_hr_len; } /** * @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_get_intf_hr_len = Hostsa_get_intf_hr_len; pmlan_fns->Hostsa_sendEventRsnConnect = Hostsa_sendEventRsnConnect; }; /** * @brief Init hostsa data * * @param pmpriv A pointer to mlan_private 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 pmpriv A pointer to mlan_private 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; }